sled

Једноставни уређивач текста
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 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:
Msled.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;