From 8ae9e18c008dba7e47c5750f7feb91df8bf723df Mon Sep 17 00:00:00 2001 From: pommicket Date: Thu, 11 May 2023 11:47:22 -0400 Subject: fix backups wrt hard links, add crlf-windows setting --- buffer.c | 85 ++++++++++++++++++++++++++++++++-------------------------------- config.c | 2 ++ main.c | 3 --- ted.cfg | 8 ++++++ ted.h | 2 ++ 5 files changed, 55 insertions(+), 45 deletions(-) diff --git a/buffer.c b/buffer.c index 5090306..f607f10 100644 --- a/buffer.c +++ b/buffer.c @@ -2666,44 +2666,13 @@ void buffer_new_file(TextBuffer *buffer, const char *path) { buffer->nlines = 1; } -bool buffer_save(TextBuffer *buffer) { +static bool buffer_write_to_file(TextBuffer *buffer, const char *path) { const Settings *settings = buffer_settings(buffer); - - if (!buffer_is_named_file(buffer)) { - // user tried to save line buffer. whatever - return true; - } - if (buffer->view_only) { - 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(tmp_path, "wb"); + FILE *out = fopen(path, "wb"); if (!out) { - buffer_error(buffer, "Couldn't open file %s for writing: %s.", buffer->path, strerror(errno)); + buffer_error(buffer, "Couldn't open file %s for writing: %s.", path, strerror(errno)); return false; } - #if __unix__ - // preserve permissions - struct stat statbuf = {0}; - if (stat(buffer->path, &statbuf) == 0) { - mode_t mode = statbuf.st_mode; - if (!(mode & 0222)) { - // we won't be able to write to buffer->path - buffer_error(buffer, "Can't write to %s (file has permissions %04o)", buffer->path, mode); - fclose(out); - return false; - } - fchmod(fileno(out), mode); - } - #endif if (settings->auto_add_newline) { Line *last_line = &buffer->lines[buffer->nlines - 1]; if (last_line->len) { @@ -2723,34 +2692,66 @@ 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.", tmp_path); + buffer_error(buffer, "Couldn't write to %s.", path); success = false; } } } if (i != buffer->nlines-1) { + #if _WIN32 + if (settings->crlf_windows) + putc('\r', out); + #endif putc('\n', out); } } if (ferror(out)) { if (!buffer_has_error(buffer)) - buffer_error(buffer, "Couldn't write to %s.", tmp_path); + buffer_error(buffer, "Couldn't write to %s.", path); success = false; } if (fclose(out) != 0) { if (!buffer_has_error(buffer)) - buffer_error(buffer, "Couldn't close file %s.", tmp_path); + buffer_error(buffer, "Couldn't close file %s.", path); success = false; } - if (success) { - if (os_rename_overwrite(tmp_path, buffer->path) < 0) { - if (!buffer_has_error(buffer)) - buffer_error(buffer, "Couldn't rename %s => %s.", tmp_path, buffer->path); - success = false; + + return success; +} + +bool buffer_save(TextBuffer *buffer) { + const Settings *settings = buffer_settings(buffer); + + if (!buffer_is_named_file(buffer)) { + // user tried to save line buffer. whatever + return true; + } + if (buffer->view_only) { + buffer_error(buffer, "Can't save view-only file."); + return false; + } + + char backup_path[TED_PATH_MAX+10]; + *backup_path = '\0'; + + if (settings->save_backup) { + strbuf_printf(backup_path, "%s.ted-bk", buffer->path); + if (strlen(backup_path) != strlen(buffer->path) + 7) { + buffer_error(buffer, "File name too long."); + return false; } + } + + bool success = true; + if (*backup_path) + success &= buffer_write_to_file(buffer, backup_path); + if (success) + success &= buffer_write_to_file(buffer, buffer->path); + if (success && *backup_path) + remove(backup_path); buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->path)); if (success) { buffer->undo_history_write_pos = arr_len(buffer->undo_history); diff --git a/config.c b/config.c index 81fac91..5baa772 100644 --- a/config.c +++ b/config.c @@ -97,6 +97,8 @@ static const SettingBool settings_bool[] = { {"vsync", &settings_zero.vsync, false}, {"highlight-enabled", &settings_zero.highlight_enabled, true}, {"highlight-auto", &settings_zero.highlight_auto, true}, + {"save-backup", &settings_zero.save_backup, true}, + {"crlf-windows", &settings_zero.crlf_windows, true}, }; static const SettingU8 settings_u8[] = { {"tab-width", &settings_zero.tab_width, 1, 100, true}, diff --git a/main.c b/main.c index f09efcf..23d0d07 100644 --- a/main.c +++ b/main.c @@ -1,8 +1,5 @@ /* TODO: -- fix backup file creation wrt hard links (right now saving a hard-linked file creates a new link) - idea: just copy to the backup file, then overwrite the original. - also, add a setting for whether or not to back up. - option for whether to jump to build error when the build command finishes, and maybe :build-jump, :build-nojump commands - highlight TODO, FIXME, XXX, others(?) in comments - :go-to-matching-bracket diff --git a/ted.cfg b/ted.cfg index 592cfb4..408c9b3 100644 --- a/ted.cfg +++ b/ted.cfg @@ -99,6 +99,14 @@ regenerate-tags-if-not-found = yes # if no identifying files are found, the directory containing the current file is used. root-identifiers = .ted-root, .ted-root.out, Cargo.toml, make.bat, CMakeLists.txt, Makefile, go.mod, .git +# whether or not to save a backup copy of files before +# writing to the file (prevents loss of data if power goes out mid-write or something). +# the backups are deleted immediately after writing. +save-backup = yes +# whether to default to \r\n line endings. +# this setting is ignored on non-Windows operating system. +crlf-windows = no + # you can make your own custom background for ted using a shader. # an example is provided here. you will have access to the following variables: # t_pos - screen position of fragment (0,0) to (1,1) diff --git a/ted.h b/ted.h index 0852669..e1a571b 100644 --- a/ted.h +++ b/ted.h @@ -271,6 +271,8 @@ typedef struct { bool highlight_enabled; bool highlight_auto; bool vsync; + bool save_backup; + bool crlf_windows; KeyCombo hover_key; KeyCombo highlight_key; u8 tab_width; -- cgit v1.2.3