Fix crash when ':write -method replace' fails to create tempfile
If a user attempts to save a file without write permission for the containing directory, with writemethod set as 'replace' or an explicit ':write -method replace' command, kak crashes with "terminating due to uncaught exception of type Kakoune:runtime_error". (Note this doesn't happen with a forced write, which fails earlier when it tries to enable u+w permission.) Don't raise another exception when already bailing out with a runtime error for failing to create a temporary file or open the existing file. Instead, make a best-efforts attempt to restore the file permissions before raising the first exception, and only report the runtime chmod exception if that step fails on the non-error path.
This commit is contained in:
parent
990e92a5f3
commit
05bbdb27c9
19
src/file.cc
19
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); });
|
||||
|
@ -370,7 +370,14 @@ void write_buffer_to_file(Buffer& buffer, StringView filename,
|
|||
}
|
||||
|
||||
if (replace and rename(temp_filename, zfilename) != 0)
|
||||
{
|
||||
if (force)
|
||||
::chmod(zfilename, st.st_mode);
|
||||
throw runtime_error("replacing file failed");
|
||||
}
|
||||
|
||||
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
|
||||
real_path(filename) == real_path(buffer.name()))
|
||||
|
|
Loading…
Reference in New Issue
Block a user