sled

Једноставни уређивач текста
git clone https://git.sr.ht/~strahinja/sled
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување cec2b429688d1cf8995d8675aee116801fe55513
родитељ eae3b7176476cfa5fdcc49475d81fa31daa02ce9
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sat,  2 Mar 2024 20:19:04 +0100

Copy file to backup instead of rename(2)-ing it (crontab -e fix)

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
MTODO | 16----------------
MTODO.done | 16++++++++++++++++
Mdraw.c | 2+-
Msled.c | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mutil.h | 3++-
измењених датотека: 5, додавања: 89(+), брисања: 27(-)

diff --git a/TODO b/TODO @@ -5,22 +5,6 @@ TODO [ ] Switch to strlcpy, strlcat; check u8_*/u32_* -[ ] Change the backup method, as `crontab -e` doesn't like inode changes - (crontab -e with CREATE_BACKUPS gives: - - crontab: crontab temp file moved, editor may create backup files\ -improperly - crontab: no changes made to crontab - - - Currently: - mv file file~ - write to file - - - Planned: - cp file file~ \ very inelegant, but the - <change file~ mtime?> / only way to appease crontab -e - write to file - Legend ------ diff --git a/TODO.done b/TODO.done @@ -1,6 +1,22 @@ Done or canceled todos ====================== +[x] Change the backup method, as `crontab -e` doesn't like inode changes + (crontab -e with CREATE_BACKUPS gives: + + crontab: crontab temp file moved, editor may create backup files\ +improperly + crontab: no changes made to crontab + + - Currently: + mv file file~ + write to file + + - Planned: + cp file file~ \ very inelegant, but the + <change file~ mtime?> / only way to appease crontab -e + write to file + [/] Investigate segfault: sled README C-\ diff --git a/draw.c b/draw.c @@ -51,7 +51,7 @@ const char* errors[] = { [ERR_CANT_ALLOC] = "Memory allocation failed", [ERR_CANT_SAVE] = "File is not writeable", [ERR_CANT_OPEN] = "Cannot read file", - [ERR_CANT_MOVE] = "Cannot move temporary file", + [ERR_CANT_COPY] = "Cannot create the backup file", [ERR_INPUT_NONNUM] = "Input must be numerical", [ERR_INVALID_NUM] = "Invalid input"}; const char* actions[] = { diff --git a/sled.c b/sled.c @@ -10,6 +10,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> #include <unistd.h> #define TB_OPT_V1_COMPAT @@ -39,7 +40,7 @@ enum { SAVE_ERR_NONE = 0, SAVE_ERR_CANT_ALLOC = 1, SAVE_ERR_CANT_OPEN_FILE = 2, - SAVE_ERR_CANT_MOVE_FILE = 3, + SAVE_ERR_CANT_COPY_FILE = 3, SAVE_ERR_CANT_STAT_FILE = 4, SAVE_ERR_CANT_READLINK = 5, SAVE_ERR_CANT_SYMLINK = 6, @@ -59,6 +60,7 @@ extern const char* prompt_reread_dirty; extern const char* program_name; int clear_selection(struct DrawState* state); +int cp(const char* from, const char* to); int create_file(struct DrawState* dstate); char* dirname(char* path); int do_search_replace(struct DrawState* state); @@ -95,6 +97,66 @@ clear_selection(struct DrawState* state) } int +cp(const char* from, const char* to) +{ + int fromfd, tofd; + int nread = 0; + int nwritten = 0; + char buf[MAXCOPYBUF]; + int result; + struct stat st; + struct timespec times[2]; + + fromfd = open(from, O_RDONLY); + if (fromfd < 0) + return -1; + tofd = open(to, O_WRONLY | O_CREAT | O_TRUNC); + if (tofd < 0) + return -1; + + if (fstat(fromfd, &st) < 0) + { + result = -1; + goto cp_cleanup; + } + if (fchmod(tofd, st.st_mode) < 0) + { + result = -1; + goto cp_cleanup; + } + times[0] = st.st_atim; + times[1] = st.st_mtim; + + result = 0; + while ((nread = read(fromfd, buf, MAXCOPYBUF)) > 0) + { + nwritten = write(tofd, buf, nread); + if (nwritten < nread) + { + result = -1; + goto cp_cleanup; + } + result += nwritten; + } + + if (nread < 0) + { + result = -1; + goto cp_cleanup; + } + + errno = 0; + if (futimens(tofd, times) < 0) + result = -1; + +cp_cleanup: + close(tofd); + close(fromfd); + + return result; +} + +int create_file(struct DrawState* state) { struct BufferLine* newchunk = NULL; @@ -890,21 +952,20 @@ save_file(struct DrawState* state) if (state->backup_possible) { if (unlink(state->backup_filename) < 0 && errno != ENOENT) - return SAVE_ERR_CANT_MOVE_FILE; + return SAVE_ERR_CANT_COPY_FILE; errno = 0; - rename(state->rfn_len > 0 ? state->real_filename - : state->filename, + cp(state->rfn_len > 0 ? state->real_filename : state->filename, state->backup_filename); errno = 0; /* ignore errors */ } #else /* !BACKUP_FAIL_OK */ if (unlink(state->backup_filename) < 0 && errno != ENOENT) - return SAVE_ERR_CANT_MOVE_FILE; + return SAVE_ERR_CANT_COPY_FILE; - if (rename(state->rfn_len > 0 ? state->real_filename : state->filename, + if (cp(state->rfn_len > 0 ? state->real_filename : state->filename, state->backup_filename) == -1) - return SAVE_ERR_CANT_MOVE_FILE; + return SAVE_ERR_CANT_COPY_FILE; #endif /* BACKUP_FAIL_OK */ #endif /* CREATE_BACKUPS */ @@ -2146,8 +2207,8 @@ write_file(struct DrawState* state) strcpy(state->error, errors[ERR_CANT_SAVE]); state->running = 0; break; - case SAVE_ERR_CANT_MOVE_FILE: - strcpy(state->error, errors[ERR_CANT_MOVE]); + case SAVE_ERR_CANT_COPY_FILE: + strcpy(state->error, errors[ERR_CANT_COPY]); state->running = 0; break; case SAVE_ERR_CANT_READLINK: diff --git a/util.h b/util.h @@ -28,7 +28,7 @@ enum { ERR_CANT_ALLOC, ERR_CANT_SAVE, ERR_CANT_OPEN, - ERR_CANT_MOVE, + ERR_CANT_COPY, ERR_INPUT_NONNUM, ERR_INVALID_NUM }; @@ -37,6 +37,7 @@ enum { ACT_WRITING, ACT_READING }; #define ALLOC_DELTA 50 #define MAXBUFLINE 4096 +#define MAXCOPYBUF 8192 #define MAXDATEBUF 80 #define MAXFLAGSBUF (4 + 1) #define MAXMSGLINE 1024