aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-09-23 21:29:10 +0200
committerEelco Dolstra <edolstra@gmail.com>2020-09-23 21:29:10 +0200
commit4ce8a3ed452f06b18a40cffefc37d47c916927a8 (patch)
treeeda73078baffc345821aa0a4c113de94f9dd3ff2 /src/libstore/build.cc
parent9a24ece122eb19f3b69f072f6ce3c39c5ae4d0ce (diff)
Hopefully fix EPERM on macOS
Diffstat (limited to 'src/libstore/build.cc')
-rw-r--r--src/libstore/build.cc72
1 files changed, 40 insertions, 32 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index f0820e711..db7dbc17e 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1675,6 +1675,33 @@ void DerivationGoal::tryLocalBuild() {
}
+static void chmod_(const Path & path, mode_t mode)
+{
+ if (chmod(path.c_str(), mode) == -1)
+ throw SysError("setting permissions on '%s'", path);
+}
+
+
+/* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if
+ it's a directory and we're not root (to be able to update the
+ directory's parent link ".."). */
+static void movePath(const Path & src, const Path & dst)
+{
+ auto st = lstat(src);
+
+ bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR));
+
+ if (changePerm)
+ chmod_(src, st.st_mode | S_IWUSR);
+
+ if (rename(src.c_str(), dst.c_str()))
+ throw SysError("renaming '%1%' to '%2%'", src, dst);
+
+ if (changePerm)
+ chmod_(dst, st.st_mode);
+}
+
+
void replaceValidPath(const Path & storePath, const Path & tmpPath)
{
/* We can't atomically replace storePath (the original) with
@@ -1683,12 +1710,20 @@ void replaceValidPath(const Path & storePath, const Path & tmpPath)
we're repairing (say) Glibc, we end up with a broken system. */
Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % random()).str();
if (pathExists(storePath))
- rename(storePath.c_str(), oldPath.c_str());
- if (rename(tmpPath.c_str(), storePath.c_str()) == -1) {
- auto ex = SysError("moving '%s' to '%s'", tmpPath, storePath);
- rename(oldPath.c_str(), storePath.c_str()); // attempt to recover
- throw ex;
+ movePath(storePath, oldPath);
+
+ try {
+ movePath(tmpPath, storePath);
+ } catch (...) {
+ try {
+ // attempt to recover
+ movePath(oldPath, storePath);
+ } catch (...) {
+ ignoreException();
+ }
+ throw;
}
+
deletePath(oldPath);
}
@@ -2006,13 +2041,6 @@ HookReply DerivationGoal::tryBuildHook()
}
-static void chmod_(const Path & path, mode_t mode)
-{
- if (chmod(path.c_str(), mode) == -1)
- throw SysError("setting permissions on '%s'", path);
-}
-
-
int childEntry(void * arg)
{
((DerivationGoal *) arg)->runChild();
@@ -3731,26 +3759,6 @@ void DerivationGoal::runChild()
}
-/* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if
- it's a directory and we're not root (to be able to update the
- directory's parent link ".."). */
-static void movePath(const Path & src, const Path & dst)
-{
- auto st = lstat(src);
-
- bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR));
-
- if (changePerm)
- chmod_(src, st.st_mode | S_IWUSR);
-
- if (rename(src.c_str(), dst.c_str()))
- throw SysError("renaming '%1%' to '%2%'", src, dst);
-
- if (changePerm)
- chmod_(dst, st.st_mode);
-}
-
-
void DerivationGoal::registerOutputs()
{
/* When using a build hook, the build hook can register the output