diff options
author | pommicket <pommicket@gmail.com> | 2023-01-08 09:55:18 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2023-01-08 09:55:18 -0500 |
commit | 21c2b2244e4abddd70b9e1ee298dfe4b7a6d6d2d (patch) | |
tree | 03fc644ee82f31a83d63821ca4b5238533802020 /buffer.c | |
parent | 2d2922637d08bb156cfdcbaaba00a974e6e7a8cf (diff) |
write first to <path>.ted-tmp then rename to <path>.
this prevents freak occurences, e.g. power outage during file write,
from losing (all) data.
Diffstat (limited to 'buffer.c')
-rw-r--r-- | buffer.c | 30 |
1 files changed, 24 insertions, 6 deletions
@@ -2409,8 +2409,14 @@ bool buffer_save(TextBuffer *buffer) { buffer_error(buffer, "Can't save view-only file."); return false; } + char tmp_path[TED_PATH_MAX+10]; + strbuf_printf(tmp_path, "%s.ted-tmp", buffer->path); + if (strlen(tmp_path) != strlen(buffer->path) + 8) { + buffer_error(buffer, "File name too long."); + return false; + } - FILE *out = fopen(buffer->path, "wb"); + FILE *out = fopen(tmp_path, "wb"); if (out) { if (settings->auto_add_newline) { Line *last_line = &buffer->lines[buffer->nlines - 1]; @@ -2421,7 +2427,9 @@ bool buffer_save(TextBuffer *buffer) { buffer_insert_text_at_pos(buffer, buffer_pos_end_of_file(buffer), s); } } - + + bool success = true; + for (u32 i = 0; i < buffer->nlines; ++i) { Line *line = &buffer->lines[i]; for (char32_t *p = line->str, *p_end = p + line->len; p != p_end; ++p) { @@ -2429,7 +2437,8 @@ bool buffer_save(TextBuffer *buffer) { size_t bytes = unicode_utf32_to_utf8(utf8, *p); if (bytes != (size_t)-1) { if (fwrite(utf8, 1, bytes, out) != bytes) { - buffer_error(buffer, "Couldn't write to %s.", buffer->path); + buffer_error(buffer, "Couldn't write to %s.", tmp_path); + success = false; } } } @@ -2438,16 +2447,25 @@ bool buffer_save(TextBuffer *buffer) { putc('\n', out); } } + if (ferror(out)) { if (!buffer_has_error(buffer)) - buffer_error(buffer, "Couldn't write to %s.", buffer->path); + buffer_error(buffer, "Couldn't write to %s.", tmp_path); + success = false; } if (fclose(out) != 0) { if (!buffer_has_error(buffer)) - buffer_error(buffer, "Couldn't close file %s.", buffer->path); + buffer_error(buffer, "Couldn't close file %s.", tmp_path); + success = false; + } + if (success) { + if (rename(tmp_path, buffer->path) != 0) { + if (!buffer_has_error(buffer)) + buffer_error(buffer, "Couldn't rename %s => %s.", tmp_path, buffer->path); + success = false; + } } buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->path)); - bool success = !buffer_has_error(buffer); if (success) { buffer->undo_history_write_pos = arr_len(buffer->undo_history); if (buffer->path && streq(path_filename(buffer->path), "ted.cfg") |