Set replacement file permissions before moving into place

When doing :write -method replace, make sure we've set the correct mode,
uid and gid on the replacement file before attempting to rename it on
top of the original. This means that the original file is left in place
with correct permissions if anything fails, rather than ending up with
0700 permissions from mkstemp().
This commit is contained in:
Chris Webb 2023-11-28 08:51:32 +00:00
parent d3af9b57d4
commit 3ba3399f94

View File

@ -369,6 +369,13 @@ void write_buffer_to_file(Buffer& buffer, StringView filename,
::fsync(fd); ::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 (replace and rename(temp_filename, zfilename) != 0)
{ {
if (force) if (force)
@ -376,11 +383,6 @@ void write_buffer_to_file(Buffer& buffer, StringView filename,
throw runtime_error("replacing file failed"); throw runtime_error("replacing file failed");
} }
if (replace and geteuid() == 0 and ::chown(zfilename, st.st_uid, st.st_gid) < 0)
throw runtime_error(format("unable to restore file ownership: {}", strerror(errno)));
if ((force or replace) and ::chmod(zfilename, st.st_mode) < 0)
throw runtime_error(format("unable to restore file permissions: {}", strerror(errno)));
if ((buffer.flags() & Buffer::Flags::File) and if ((buffer.flags() & Buffer::Flags::File) and
real_path(filename) == real_path(buffer.name())) real_path(filename) == real_path(buffer.name()))
buffer.notify_saved(get_fs_status(real_path(filename))); buffer.notify_saved(get_fs_status(real_path(filename)));