summaryrefslogtreecommitdiff
path: root/buffer.c
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-03-03 13:28:50 -0500
committerpommicket <pommicket@gmail.com>2023-03-03 13:28:50 -0500
commit24d888156ae0f3085de3e5f7a5583ea1e0ba8ebc (patch)
tree354515166ad1a1e965d4babe56251af9a92b61e1 /buffer.c
parentc67ac3cecf5452467ea0fc757400de94bd8bdb74 (diff)
preserve permissions on save
Diffstat (limited to 'buffer.c')
-rw-r--r--buffer.c153
1 files changed, 84 insertions, 69 deletions
diff --git a/buffer.c b/buffer.c
index 50bdbe7..aa9e165 100644
--- a/buffer.c
+++ b/buffer.c
@@ -4,6 +4,8 @@
#include "ted.h"
+#include <sys/stat.h>
+
#define BUFFER_UNTITLED "Untitled" // what to call untitled buffers
// this is a macro so we get -Wformat warnings
@@ -2455,84 +2457,97 @@ void buffer_new_file(TextBuffer *buffer, const char *path) {
bool buffer_save(TextBuffer *buffer) {
const Settings *settings = buffer_settings(buffer);
- if (buffer_is_named_file(buffer)) {
- if (buffer->view_only) {
- buffer_error(buffer, "Can't save view-only file.");
+ 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");
+ if (!out) {
+ buffer_error(buffer, "Couldn't open file %s for writing: %s.", buffer->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;
}
- 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;
+ fchmod(fileno(out), mode);
+ }
+ #endif
+ if (settings->auto_add_newline) {
+ Line *last_line = &buffer->lines[buffer->nlines - 1];
+ if (last_line->len) {
+ // if the last line isn't empty, add a newline to the end of the file
+ char32_t c = '\n';
+ String32 s = {&c, 1};
+ buffer_insert_text_at_pos(buffer, buffer_pos_end_of_file(buffer), s);
}
-
- FILE *out = fopen(tmp_path, "wb");
- if (out) {
- if (settings->auto_add_newline) {
- Line *last_line = &buffer->lines[buffer->nlines - 1];
- if (last_line->len) {
- // if the last line isn't empty, add a newline to the end of the file
- char32_t c = '\n';
- String32 s = {&c, 1};
- 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) {
- char utf8[4] = {0};
- 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);
- success = false;
- }
- }
- }
-
- if (i != buffer->nlines-1) {
- putc('\n', out);
- }
- }
-
- if (ferror(out)) {
- if (!buffer_has_error(buffer))
+ }
+
+ 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) {
+ char utf8[4] = {0};
+ 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);
- success = false;
- }
- if (fclose(out) != 0) {
- if (!buffer_has_error(buffer))
- buffer_error(buffer, "Couldn't close file %s.", tmp_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;
}
}
- buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->path));
- if (success) {
- buffer->undo_history_write_pos = arr_len(buffer->undo_history);
- if (buffer->path && streq(path_filename(buffer->path), "ted.cfg")
- && buffer_settings(buffer)->auto_reload_config) {
- ted_load_configs(buffer->ted, true);
- }
- }
- return success;
- } else {
- buffer_error(buffer, "Couldn't open file %s for writing: %s.", buffer->path, strerror(errno));
- return false;
}
- } else {
- // user tried to save line buffer. whatever
- return true;
+
+ if (i != buffer->nlines-1) {
+ putc('\n', out);
+ }
}
+
+ if (ferror(out)) {
+ if (!buffer_has_error(buffer))
+ 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.", tmp_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;
+ }
+ }
+ buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->path));
+ if (success) {
+ buffer->undo_history_write_pos = arr_len(buffer->undo_history);
+ if (buffer->path && streq(path_filename(buffer->path), TED_CFG)
+ && buffer_settings(buffer)->auto_reload_config) {
+ ted_load_configs(buffer->ted, true);
+ }
+ }
+ return success;
}
bool buffer_save_as(TextBuffer *buffer, const char *new_path) {