чување 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:
| M | TODO | | | 16 | ---------------- |
| M | TODO.done | | | 16 | ++++++++++++++++ |
| M | draw.c | | | 2 | +- |
| M | sled.c | | | 79 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- |
| M | util.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