чување 7ee1d7823b76f9314d428855f7f423399a99901a
родитељ dc52ccf5e0c9b70d9c86b17b2b43de7692b52014
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Wed, 2 Mar 2022 18:15:59 +0100
More sophisticated handling of file mode and symlinks
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | po.c | | | 39 | ++++++++++++++++++++++++++++++++++++--- |
| M | po.h | | | 6 | +++++- |
измењених датотека: 2, додавања: 41(+), брисања: 4(-)
diff --git a/po.c b/po.c
@@ -1,5 +1,9 @@
/* See the file LICENSE for copyright and license details. */
+#define _POSIX_C_SOURCE 200809L
+#define _DEFAULT_SOURCE
+#define _XOPEN_SOURCE
+
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
@@ -508,24 +512,52 @@ save_file(const struct PoEntry* entries, const size_t real_msgid_count,
char* backup_filename = NULL;
#endif
struct stat st;
+ char* real_filename = NULL;
+ size_t rfn_len = 0;
+ if (!(real_filename = calloc(MAXPATH, 1)))
+ return SAVE_ERR_CANT_ALLOC;
#ifdef CREATE_BACKUPS
if (!(backup_filename = calloc(MAXPATH, 1)))
return SAVE_ERR_CANT_ALLOC;
#endif
#ifdef CREATE_BACKUPS
- if (stat(filename, &st) != -1)
+ if (lstat(filename, &st) != -1)
{
+ if (S_ISLNK(st.st_mode))
+ {
+ rfn_len = readlink(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, filename);
strcat(backup_filename, backup_suffix);
- if (rename(filename, backup_filename) == -1)
+ if (rename(rfn_len > 0 ? real_filename : filename,
+ backup_filename)
+ == -1)
return SAVE_ERR_CANT_MOVE_FILE;
}
+ else
+ return SAVE_ERR_CANT_STAT_FILE;
#endif
- if (!(output = fopen(filename, "wt")))
+ if (!(output = fopen(rfn_len > 0 ? real_filename : filename, "wt")))
return SAVE_ERR_CANT_OPEN_FILE;
+#ifdef CREATE_BACKUPS
+ if (rfn_len > 0)
+ {
+ if (unlink(filename) == -1)
+ return SAVE_ERR_CANT_UNLINK;
+ if (symlink(real_filename, filename) == -1)
+ return SAVE_ERR_CANT_SYMLINK;
+ }
+ chmod(rfn_len > 0 ? real_filename : filename, st.st_mode);
+#endif
+
save_loop_entries_start:
if (current >= entries + real_msgid_count)
goto save_loop_entries_done;
@@ -856,6 +888,7 @@ save_loop_entries_done:
#ifdef CREATE_BACKUPS
free(backup_filename);
#endif
+ free(real_filename);
return SAVE_ERR_NONE;
}
diff --git a/po.h b/po.h
@@ -35,7 +35,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
};
typedef enum {