1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
From: Colin Clark <colin.clark@cclark.uk>
Date: Sun, 15 Jun 2025 15:59:19 +0100
Subject: Fix #1771: Deleting (not write protected) symlinks to write
protected images gives warning
https://github.com/BestImageViewer/geeqie/issues/1771
Function access() was used, but this function follows symlinks.
Instead use lstat for delete/move/rename operations.
---
src/filedata/filedata.cc | 59 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 57 insertions(+), 2 deletions(-)
diff --git a/src/filedata/filedata.cc b/src/filedata/filedata.cc
index 76f8866..ee779ff 100644
--- a/src/filedata/filedata.cc
+++ b/src/filedata/filedata.cc
@@ -23,6 +23,7 @@
#include "filedata.h"
+#include <glib/gstdio.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -1997,6 +1998,60 @@ gboolean FileData::file_data_sc_update_ci_unspecified_list(GList *fd_list, const
* it should detect all possible problems with the planned operation
*/
+/**
+ * @brief Determine if file is readable, do not follow symlinks
+ * @param path
+ * @returns
+ *
+ *
+ */
+static gboolean file_is_readable_no_follow(const gchar *path)
+{
+ gboolean readable = FALSE;
+ GStatBuf statbuf;
+
+ if (g_lstat(path, &statbuf) != 0)
+ {
+ log_printf("g_lstat failed: %s\n", strerror(errno));
+
+ return readable;
+ }
+
+ if (S_IRUSR & statbuf.st_mode)
+ {
+ readable = TRUE;
+ }
+
+ return readable;
+}
+
+/**
+ * @brief Determine if file is writable, do not follow symlinks
+ * @param path
+ * @returns
+ *
+ *
+ */
+static gboolean file_is_writable_no_follow(const gchar *path)
+{
+ gboolean writable = FALSE;
+ GStatBuf statbuf;
+
+ if (g_lstat(path, &statbuf) != 0)
+ {
+ log_printf("g_lstat failed: %s\n", strerror(errno));
+
+ return writable;
+ }
+
+ if (S_IWUSR & statbuf.st_mode)
+ {
+ writable = TRUE;
+ }
+
+ return writable;
+}
+
gint FileData::file_data_verify_ci(FileData *fd, GList *list)
{
gint ret = CHANGE_OK;
@@ -2032,7 +2087,7 @@ gint FileData::file_data_verify_ci(FileData *fd, GList *list)
if (fd->change->type != FILEDATA_CHANGE_DELETE &&
fd->change->type != FILEDATA_CHANGE_WRITE_METADATA &&
- !access_file(fd->path, R_OK))
+ !file_is_readable_no_follow(fd->path))
{
ret |= CHANGE_NO_READ_PERM;
DEBUG_1("Change checked: no read permission: %s", fd->path);
@@ -2046,7 +2101,7 @@ gint FileData::file_data_verify_ci(FileData *fd, GList *list)
else if (fd->change->type != FILEDATA_CHANGE_COPY &&
fd->change->type != FILEDATA_CHANGE_UNSPECIFIED &&
fd->change->type != FILEDATA_CHANGE_WRITE_METADATA &&
- !access_file(fd->path, W_OK))
+ !file_is_writable_no_follow(fd->path))
{
ret |= CHANGE_WARN_NO_WRITE_PERM;
DEBUG_1("Change checked: no write permission: %s", fd->path);
|