diff options
author | pommicket <pommicket@gmail.com> | 2024-02-13 09:24:43 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2024-02-13 09:24:43 -0500 |
commit | 6d85a7e605011d16018fdf202e40e59e2f916b63 (patch) | |
tree | 8ce9a180f24b0b2d5465475b199713589f96b68b /buffer.c | |
parent | 12622d7fd3f19936f2d235d8965491eb2adbae80 (diff) |
better backups!
- they are now created with 600 permissions on unix
to prevent leaking file contents to other users
- they use the ~ suffix used by emacs etc
for better compatibility with gitignores, etc.
- we now call fdatasync / _commit to ensure that even
if power goes out halfway through saving, no data can be lost
Diffstat (limited to 'buffer.c')
-rw-r--r-- | buffer.c | 29 |
1 files changed, 26 insertions, 3 deletions
@@ -6,6 +6,11 @@ #include <sys/stat.h> +#if __unix__ +#include <fcntl.h> +#include <unistd.h> +#endif + /// A single line in a buffer typedef struct Line Line; @@ -3196,6 +3201,13 @@ static bool buffer_write_to_file(TextBuffer *buffer, const char *path) { buffer_error(buffer, "Couldn't write to %s.", path); success = false; } + fflush(out); + // make sure data is on disk before returning from this function + #if __unix__ + fdatasync(fileno(out)); + #elif _WIN32 + _commit(_fileno(out)); + #endif if (fclose(out) != 0) { if (!buffer_has_error(buffer)) buffer_error(buffer, "Couldn't close file %s.", path); @@ -3221,19 +3233,30 @@ bool buffer_save(TextBuffer *buffer) { *backup_path = '\0'; if (settings->save_backup) { - strbuf_printf(backup_path, "%s.ted-bk", buffer->path); - if (strlen(backup_path) != strlen(buffer->path) + 7) { + strbuf_printf(backup_path, "%s~", buffer->path); + if (strlen(backup_path) < strlen(buffer->path) + 1) { buffer_error(buffer, "File name too long."); return false; } - + #if __unix__ + // create backup file with 600 permissions so we don't leak file data to other users. + int fd = open(backup_path, O_CREAT|O_TRUNC|O_WRONLY, 0600); + if (fd == -1) { + buffer_error(buffer, "Error creating %s: %s", + backup_path, strerror(errno)); + return false; + } + close(fd); + #endif } bool success = true; + // first save backup so if writing main file fails halfway through user's data won't be lost if (*backup_path) success &= buffer_write_to_file(buffer, backup_path); if (success) success &= buffer_write_to_file(buffer, buffer->path); + // now if writing the main file succeeded we can safely delete the backup if (success && *backup_path) remove(backup_path); buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->path)); |