summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2023-12-02 10:56:11 +1100
committerMaxime Coste <mawww@kakoune.org>2023-12-02 10:56:11 +1100
commit42fefb16afe4ddeab4a5d3d14085954432da6922 (patch)
tree72526d830a048f779b6a6c29c233eb6479e22728 /src
parent8e2eacae83f2e471fe20b718126ec250f3140435 (diff)
parent3ba3399f943dff5d5fbe0c4b89752b0ec549ff74 (diff)
Merge remote-tracking branch 'arachsys/write-replace'
Diffstat (limited to 'src')
-rw-r--r--src/file.cc23
1 files changed, 17 insertions, 6 deletions
diff --git a/src/file.cc b/src/file.cc
index 58eb9284..87112e24 100644
--- a/src/file.cc
+++ b/src/file.cc
@@ -351,16 +351,16 @@ void write_buffer_to_file(Buffer& buffer, StringView filename,
if (force and ::chmod(zfilename, st.st_mode | S_IWUSR) < 0)
throw runtime_error(format("unable to change file permissions: {}", strerror(errno)));
- auto restore_mode = on_scope_end([&]{
- if ((force or replace) and ::chmod(zfilename, st.st_mode) < 0)
- throw runtime_error(format("unable to restore file permissions: {}", strerror(errno)));
- });
-
char temp_filename[PATH_MAX];
const int fd = replace ? open_temp_file(filename, temp_filename)
: open(zfilename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1)
- throw file_access_error(filename, strerror(errno));
+ {
+ auto saved_errno = errno;
+ if (force)
+ ::chmod(zfilename, st.st_mode);
+ throw file_access_error(filename, strerror(saved_errno));
+ }
{
auto close_fd = on_scope_end([fd]{ close(fd); });
@@ -369,8 +369,19 @@ void write_buffer_to_file(Buffer& buffer, StringView filename,
::fsync(fd);
}
+ if (replace and geteuid() == 0 and ::chown(temp_filename, st.st_uid, st.st_gid) < 0)
+ throw runtime_error(format("unable to set replacement file ownership: {}", strerror(errno)));
+ if (replace and ::chmod(temp_filename, st.st_mode) < 0)
+ throw runtime_error(format("unable to set replacement file permissions: {}", strerror(errno)));
+ if (force and not replace and ::chmod(zfilename, st.st_mode) < 0)
+ throw runtime_error(format("unable to restore file permissions: {}", strerror(errno)));
+
if (replace and rename(temp_filename, zfilename) != 0)
+ {
+ if (force)
+ ::chmod(zfilename, st.st_mode);
throw runtime_error("replacing file failed");
+ }
if ((buffer.flags() & Buffer::Flags::File) and
real_path(filename) == real_path(buffer.name()))