aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
authorK900 <me@0upti.me>2024-04-12 12:29:10 +0300
committerK900 <me@0upti.me>2024-04-13 12:43:19 +0300
commitb469c6509ba616da6df8a27e4ccb205a877c66c9 (patch)
treede7ed716d1346043e2085693f88ebffbce106581 /src/libutil
parentd363bc2f123876b2524ca76997f27f9f4e0a2391 (diff)
libstore/build: just copy the magic /etc files into the sandbox
Saves us a bunch of thinking about how to handle symlinks, and prevents the DNS config from changing on the fly under the build, which may or may not be a good thing? Change-Id: I071e6ae7e220884690b788d94f480866f428db71
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/filesystem.cc22
-rw-r--r--src/libutil/util.hh15
2 files changed, 28 insertions, 9 deletions
diff --git a/src/libutil/filesystem.cc b/src/libutil/filesystem.cc
index ea934ffaf..b637281d0 100644
--- a/src/libutil/filesystem.cc
+++ b/src/libutil/filesystem.cc
@@ -103,31 +103,37 @@ void setWriteTime(const fs::path & p, const struct stat & st)
throw SysError("changing modification time of '%s'", p);
}
-void copy(const fs::directory_entry & from, const fs::path & to, bool andDelete)
+void copy(const fs::directory_entry & from, const fs::path & to, CopyFileFlags flags)
{
// TODO: Rewrite the `is_*` to use `symlink_status()`
auto statOfFrom = lstat(from.path().c_str());
auto fromStatus = from.symlink_status();
// Mark the directory as writable so that we can delete its children
- if (andDelete && fs::is_directory(fromStatus)) {
+ if (flags.deleteAfter && fs::is_directory(fromStatus)) {
fs::permissions(from.path(), fs::perms::owner_write, fs::perm_options::add | fs::perm_options::nofollow);
}
if (fs::is_symlink(fromStatus) || fs::is_regular_file(fromStatus)) {
- fs::copy(from.path(), to, fs::copy_options::copy_symlinks | fs::copy_options::overwrite_existing);
+ auto opts = fs::copy_options::overwrite_existing;
+
+ if (!flags.followSymlinks) {
+ opts |= fs::copy_options::copy_symlinks;
+ }
+
+ fs::copy(from.path(), to, opts);
} else if (fs::is_directory(fromStatus)) {
fs::create_directory(to);
for (auto & entry : fs::directory_iterator(from.path())) {
- copy(entry, to / entry.path().filename(), andDelete);
+ copy(entry, to / entry.path().filename(), flags);
}
} else {
throw Error("file '%s' has an unsupported type", from.path());
}
setWriteTime(to, statOfFrom);
- if (andDelete) {
+ if (flags.deleteAfter) {
if (!fs::is_symlink(fromStatus))
fs::permissions(from.path(), fs::perms::owner_write, fs::perm_options::add | fs::perm_options::nofollow);
fs::remove(from.path());
@@ -135,9 +141,9 @@ void copy(const fs::directory_entry & from, const fs::path & to, bool andDelete)
}
-void copyFile(const Path & oldPath, const Path & newPath, bool andDelete)
+void copyFile(const Path & oldPath, const Path & newPath, CopyFileFlags flags)
{
- return copy(fs::directory_entry(fs::path(oldPath)), fs::path(newPath), andDelete);
+ return copy(fs::directory_entry(fs::path(oldPath)), fs::path(newPath), flags);
}
void renameFile(const Path & oldName, const Path & newName)
@@ -160,7 +166,7 @@ void moveFile(const Path & oldName, const Path & newName)
if (e.code().value() == EXDEV) {
fs::remove(newPath);
warn("Can’t rename %s as %s, copying instead", oldName, newName);
- copy(fs::directory_entry(oldPath), tempCopyTarget, true);
+ copy(fs::directory_entry(oldPath), tempCopyTarget, { .deleteAfter = true });
renameFile(tempCopyTarget, newPath);
}
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 61df6c4f8..9c2385e84 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -279,13 +279,26 @@ void renameFile(const Path & src, const Path & dst);
*/
void moveFile(const Path & src, const Path & dst);
+struct CopyFileFlags
+{
+ /**
+ * Delete the file after copying.
+ */
+ bool deleteAfter = false;
+
+ /**
+ * Follow symlinks and copy the eventual target.
+ */
+ bool followSymlinks = false;
+};
+
/**
* Recursively copy the content of `oldPath` to `newPath`. If `andDelete` is
* `true`, then also remove `oldPath` (making this equivalent to `moveFile`, but
* with the guaranty that the destination will be “fresh”, with no stale inode
* or file descriptor pointing to it).
*/
-void copyFile(const Path & oldPath, const Path & newPath, bool andDelete);
+void copyFile(const Path & oldPath, const Path & newPath, CopyFileFlags flags);
/**
* Wrappers arount read()/write() that read/write exactly the