diff options
| author | Maxime Coste <mawww@kakoune.org> | 2019-02-12 20:54:37 +1100 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2019-02-12 21:01:19 +1100 |
| commit | 4dae2c875bf70d87ace53d7b03c4a9289b2bb241 (patch) | |
| tree | 5b4c66cbbcf2ca461d7e0e5e456c51d1e208cc4f /src/file.cc | |
| parent | e8f26cbae751180ace2655b000b1b86ad3a2940c (diff) | |
Introduce a writemethod option to either overwrite or replace files
This permit to choose if files should be written by overwriting their
content (the default), or by writing to a separate temporary file
and rename it to the current file.
As discussed in #2036
Diffstat (limited to 'src/file.cc')
| -rw-r--r-- | src/file.cc | 58 |
1 files changed, 39 insertions, 19 deletions
diff --git a/src/file.cc b/src/file.cc index d5e73bed..eb26ddc4 100644 --- a/src/file.cc +++ b/src/file.cc @@ -280,25 +280,51 @@ void write_buffer_to_fd(Buffer& buffer, int fd) } } -void write_buffer_to_file(Buffer& buffer, StringView filename, WriteFlags flags) +int open_temp_file(StringView filename, char (&buffer)[PATH_MAX]) +{ + String path = real_path(filename); + auto [dir,file] = split_path(path); + + if (dir.empty()) + format_to(buffer, ".{}.kak.XXXXXX", file); + else + format_to(buffer, "{}/.{}.kak.XXXXXX", dir, file); + + return mkstemp(buffer); +} + +int open_temp_file(StringView filename) +{ + char buffer[PATH_MAX]; + return open_temp_file(filename, buffer); +} + +void write_buffer_to_file(Buffer& buffer, StringView filename, + WriteMethod method, WriteFlags flags) { - struct stat st; auto zfilename = filename.zstr(); + struct stat st; + + bool replace = method == WriteMethod::Replace; + bool force = flags & WriteFlags::Force; - if (flags & WriteFlags::Force and ::stat(zfilename, &st) == 0) + if ((replace or force) and ::stat(zfilename, &st) != 0) { - if (::chmod(zfilename, st.st_mode | S_IWUSR) < 0) - throw runtime_error("unable to change file permissions"); + force = false; + replace = false; } - else - flags |= ~WriteFlags::Force; + + if (force and ::chmod(zfilename, st.st_mode | S_IWUSR) < 0) + throw runtime_error("unable to change file permissions"); auto restore_mode = on_scope_end([&]{ - if (flags & WriteFlags::Force and ::chmod(zfilename, st.st_mode) < 0) + if ((force or replace) and ::chmod(zfilename, st.st_mode) < 0) throw runtime_error("unable to restore file permissions"); }); - const int fd = open(zfilename, O_CREAT | O_WRONLY | O_TRUNC, 0644); + 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)); @@ -309,6 +335,9 @@ void write_buffer_to_file(Buffer& buffer, StringView filename, WriteFlags flags) ::fsync(fd); } + if (replace) + rename(temp_filename, zfilename); + if ((buffer.flags() & Buffer::Flags::File) and real_path(filename) == real_path(buffer.name())) buffer.notify_saved(); @@ -316,16 +345,7 @@ void write_buffer_to_file(Buffer& buffer, StringView filename, WriteFlags flags) void write_buffer_to_backup_file(Buffer& buffer) { - String path = real_path(buffer.name()); - auto [dir,file] = split_path(path); - - char pattern[PATH_MAX]; - if (dir.empty()) - format_to(pattern, ".{}.kak.XXXXXX", file); - else - format_to(pattern, "{}/.{}.kak.XXXXXX", dir, file); - - int fd = mkstemp(pattern); + const int fd = open_temp_file(buffer.name()); if (fd >= 0) { write_buffer_to_fd(buffer, fd); |
