чување 3ca053034cccbd059e4b81c5b99f3b17c3b6d217
родитељ 5f862722d79c391d84f8cba0507ee2bd36eb12cc
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Wed, 2 Mar 2022 16:08:29 +0100
sled.c(save_file): More sophisticated handling of file mode and symlinks
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | sled.c | | | 64 | +++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
измењених датотека: 1, додавања: 49(+), брисања: 15(-)
diff --git a/sled.c b/sled.c
@@ -36,7 +36,11 @@ 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_MOVE_FILE = 3,
+ SAVE_ERR_CANT_STAT_FILE = 4,
+ SAVE_ERR_CANT_READLINK = 5,
+ SAVE_ERR_CANT_SYMLINK = 6,
+ SAVE_ERR_CANT_UNLINK = 7
};
extern const char* backup_suffix;
@@ -681,39 +685,59 @@ save_file(struct DrawState* state)
char* backup_filename = NULL;
#endif
struct stat st;
+ char* real_filename = NULL;
+ size_t rfn_len = 0;
- if (!(buf = calloc(MAXBUFLINE, 1)))
- {
- state->running = 0;
+ if (!(buf = calloc(MAXBUFLINE, 1))
+ || !(real_filename = calloc(MAXPATH, 1)))
return SAVE_ERR_CANT_ALLOC;
- }
#ifdef CREATE_BACKUPS
if (!(backup_filename = calloc(MAXPATH, 1)))
- {
- state->running = 0;
return SAVE_ERR_CANT_ALLOC;
- }
#endif
strcpy(state->action, actions[ACT_WRITING]);
redraw_status(state);
#ifdef CREATE_BACKUPS
- if (stat(state->filename, &st) != -1)
+ if (lstat(state->filename, &st) != -1)
{
+ if (S_ISLNK(st.st_mode))
+ {
+ rfn_len = readlink(state->filename, real_filename,
+ MAXPATH);
+ if (rfn_len == -1)
+ return SAVE_ERR_CANT_READLINK;
+ real_filename[rfn_len] = 0;
+ if (stat(real_filename, &st) == -1)
+ return SAVE_ERR_CANT_STAT_FILE;
+ }
strcpy(backup_filename, state->filename);
strcat(backup_filename, backup_suffix);
- if (rename(state->filename, backup_filename) == -1)
- {
- strcpy(state->error, errors[SAVE_ERR_CANT_MOVE_FILE]);
+ if (rename(rfn_len > 0 ? real_filename : state->filename,
+ backup_filename)
+ == -1)
return SAVE_ERR_CANT_MOVE_FILE;
- }
}
+ else
+ return SAVE_ERR_CANT_STAT_FILE;
#endif
- if (!(output = fopen(state->filename, "wt")))
+ if (!(output = fopen(rfn_len > 0 ? real_filename : state->filename,
+ "wt")))
return SAVE_ERR_CANT_OPEN_FILE;
+#ifdef CREATE_BACKUPS
+ if (rfn_len > 0)
+ {
+ if (unlink(state->filename) == -1)
+ return SAVE_ERR_CANT_UNLINK;
+ if (symlink(real_filename, state->filename) == -1)
+ return SAVE_ERR_CANT_SYMLINK;
+ }
+ chmod(rfn_len > 0 ? real_filename : state->filename, st.st_mode);
+#endif
+
if (state->rows_count == 1 && state->buffer[0].length == 0)
goto save_file_cleanup;
@@ -729,6 +753,7 @@ save_file_cleanup:
free(backup_filename);
#endif
free(buf);
+ free(real_filename);
*state->action = 0;
return SAVE_ERR_NONE;
}
@@ -1659,12 +1684,21 @@ write_file(struct DrawState* state)
state->running = 0;
break;
case SAVE_ERR_CANT_MOVE_FILE:
+ strcpy(state->error, errors[ERR_CANT_MOVE]);
+ state->running = 0;
+ break;
+ case SAVE_ERR_CANT_READLINK:
+ case SAVE_ERR_CANT_STAT_FILE:
+ case SAVE_ERR_CANT_SYMLINK:
+ case SAVE_ERR_CANT_UNLINK:
strcpy(state->error, strerror(errno));
state->running = 0;
break;
- default:
+ case SAVE_ERR_NONE:
*state->error = 0;
state->dirty = 0;
+ break;
+ default:;
}
return 0;