From 2d4d1e54d6943cdd7a818324110789a59622f2a0 Mon Sep 17 00:00:00 2001
From: Alexander Schwinn <alexxcons@xfce.org>
Date: Thu, 9 Feb 2023 22:49:56 +0100
Subject: [PATCH] Support undo trash for linked pathes (#1030)

---
 thunar/thunar-gio-extensions.c | 41 ++++++++++++++++++++++++++++++++++
 thunar/thunar-gio-extensions.h |  3 ++-
 thunar/thunar-job-operation.c  | 27 ++++++++++++++++++++--
 3 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/thunar/thunar-gio-extensions.c b/thunar/thunar-gio-extensions.c
index b24368022..64431baf7 100644
--- a/thunar/thunar-gio-extensions.c
+++ b/thunar/thunar-gio-extensions.c
@@ -29,6 +29,10 @@
 #include <gio/gdesktopappinfo.h>
 #endif
 
+#ifndef HAVE_REALPATH
+#define realpath(path, resolved_path) NULL
+#endif
+
 #include <libxfce4util/libxfce4util.h>
 
 #include <thunar/thunar-file.h>
@@ -1418,4 +1422,41 @@ thunar_g_file_get_link_path_for_symlink (GFile *file_to_link,
     link_path = g_strconcat ("/", relative_path, NULL);
     g_free (relative_path);
     return link_path;
+}
+
+
+
+/**
+ * thunar_g_file_get_resolved_path:
+ * @file : #GFile for which the path will be resolved
+ *
+ * Gets the local pathname with resolved symlinks for GFile, if one exists.
+ * If non-NULL, this is guaranteed to be an absolute, canonical path.
+ *
+ * This only will work if all components of the #GFile path actually do exist
+ *
+ * Return value: (nullable) (transfer full): A #gchar on success and %NULL on failure.
+ * The returned string should be freed with g_free() when no longer needed.
+ **/
+char*
+thunar_g_file_get_resolved_path (GFile *file)
+{
+  gchar *path;
+  gchar *real_path;
+
+  _thunar_return_val_if_fail (G_IS_FILE (file), NULL);
+
+  path = g_file_get_path (file);
+
+  /* No local path for file found */
+  if (path == NULL)
+    return NULL;
+
+  real_path = realpath (path, NULL);
+
+  if (real_path == NULL)
+    g_warning ("Failed to resolve path: '%s' Error: %s\n", path, strerror (errno));
+
+  g_free (path);
+  return real_path;
 }
\ No newline at end of file
diff --git a/thunar/thunar-gio-extensions.h b/thunar/thunar-gio-extensions.h
index 07433a234..03715ae41 100644
--- a/thunar/thunar-gio-extensions.h
+++ b/thunar/thunar-gio-extensions.h
@@ -121,8 +121,9 @@ gboolean     thunar_g_file_set_executable_flags        (GFile             *file,
                                                         GError           **error);
 gboolean     thunar_g_file_is_in_xdg_data_dir          (GFile             *file);
 gboolean     thunar_g_file_is_desktop_file             (GFile             *file);
-char *       thunar_g_file_get_link_path_for_symlink   (GFile             *file_to_link,
+char        *thunar_g_file_get_link_path_for_symlink   (GFile             *file_to_link,
                                                         GFile             *symlink);
+char        *thunar_g_file_get_resolved_path           (GFile             *file);
 G_END_DECLS
 
 #endif /* !__THUNAR_GIO_EXTENSIONS_H__ */
diff --git a/thunar/thunar-job-operation.c b/thunar/thunar-job-operation.c
index e2ef4495c..6861bd169 100644
--- a/thunar/thunar-job-operation.c
+++ b/thunar/thunar-job-operation.c
@@ -663,12 +663,35 @@ thunar_job_operation_restore_from_trash (ThunarJobOperation  *operation,
     }
 
   /* set up a hash table for the files we deleted */
-  files_trashed = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, NULL, NULL);
+  files_trashed = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL);
 
   /* add all the files that were deleted in the hash table so we can check if a file
    * was deleted as a part of this operation or not in constant time. */
   for (GList *lp = operation->target_file_list; lp != NULL; lp = lp->next)
-    g_hash_table_add (files_trashed, lp->data);
+  {
+    GFile *parent = g_file_get_parent (lp->data);
+    gchar *real_path = NULL;
+    
+    /* Try to resolve symlinks, otherwise Gfiles wont match */
+    /* (All files located in trash have symlinks resolved) */
+    if (parent != NULL)
+      {
+        gchar *real_path_parent = NULL;
+        gchar *basename = g_file_get_basename (lp->data);
+        real_path_parent = thunar_g_file_get_resolved_path (parent);
+        g_object_unref (parent);
+        if (real_path_parent != NULL && basename != NULL)
+          real_path = g_build_filename (real_path_parent, basename, NULL);
+        g_free (basename);
+        g_free (real_path_parent);
+      }
+
+    if (real_path != NULL)
+      g_hash_table_add (files_trashed, g_file_new_for_path (real_path));
+    else
+      g_hash_table_add (files_trashed, g_object_ref (lp->data));
+    g_free (real_path);
+  }
 
   /* iterate over the files in the trash, adding them to source and target lists of
    * the files which are to be restored and their original paths */
-- 
GitLab