[PATCH] shell32: Don't use Carbon on Mac OS to find the Trash.

Charles Davis cdavis5x at gmail.com
Thu Jul 19 15:08:11 CDT 2018


Due to a weird interaction between Wine and (what I believe to be)
os_log/os_signpost, we can't use FSPathMakeRef() (nor any other function
that calls that) from a Wine process. We also can't use the
NSSearchPathForDirectoriesInDomains() function. Setting aside the fact
that it's Objective-C (something we can work around, given that NS and
CF types are toll-free bridged), a) support for getting the Trash folder
was only added in 10.8 (when FSFindFolder() was deprecated), and b) it
doesn't even support volume-specific Trash folders.

For now, just hardcode the paths to the Trash folder.

Signed-off-by: Charles Davis <cdavis5x at gmail.com>
---
 dlls/shell32/trash.c | 130 ++++++++++++++++++++++++++++---------------
 1 file changed, 86 insertions(+), 44 deletions(-)

diff --git a/dlls/shell32/trash.c b/dlls/shell32/trash.c
index 7bc035fd5387..858304e08a2e 100644
--- a/dlls/shell32/trash.c
+++ b/dlls/shell32/trash.c
@@ -22,24 +22,18 @@
 
 #include "config.h"
 
-#ifdef HAVE_CORESERVICES_CORESERVICES_H
-#define GetCurrentThread MacGetCurrentThread
-#define LoadResource MacLoadResource
-#include <CoreServices/CoreServices.h>
-#undef GetCurrentThread
-#undef LoadResource
-#undef DPRINTF
-#endif
-
 #include <stdarg.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <time.h>
+#include <sys/types.h>
 #ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
-#include <sys/types.h>
+#ifdef HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif
 #include <stdlib.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
@@ -47,6 +41,9 @@
 #ifdef HAVE_DIRENT_H
 # include <dirent.h>
 #endif
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
 
 #include "windef.h"
 #include "winbase.h"
@@ -109,44 +106,98 @@ HRESULT TRASH_UnpackItemID(LPCSHITEMID id, WIN32_FIND_DATAW *data)
     return S_OK;
 }
 
-#ifdef HAVE_CORESERVICES_CORESERVICES_H
+#ifdef __APPLE__
+
+static char *TRASH_GetTrashPath(const char *unix_path, const char **base_name)
+{
+    struct statfs stfs, home_stfs;
+    struct passwd *user = getpwuid(geteuid());
+    char *trash_path;
+    size_t name_size;
+
+    if (statfs(unix_path, &stfs) == -1)
+        return NULL;
+    if (statfs(user->pw_dir, &home_stfs) == -1)
+        return NULL;
+
+    *base_name = strrchr(unix_path, '/');
+    if (!*base_name)
+        *base_name = unix_path;
+    else
+        ++*base_name;
+    name_size = lstrlenA(*base_name);
+
+    /* If the file exists on the same volume as the user's home directory,
+     * we can use the User domain Trash folder. Otherwise, we have to use
+     * <volume>/.Trashes/<uid>.
+     */
+    if (memcmp(&stfs.f_fsid, &home_stfs.f_fsid, sizeof(fsid_t)) == 0)
+    {
+        size_t home_size = lstrlenA(user->pw_dir);
+        trash_path = heap_alloc(home_size + sizeof("/.Trash/") + name_size);
+        if (!trash_path)
+            return NULL;
+        memcpy(trash_path, user->pw_dir, home_size);
+        memcpy(trash_path+home_size, "/.Trash", sizeof("/.Trash"));
+    }
+    else
+    {
+        size_t vol_size = lstrlenA(stfs.f_mntonname);
+        /* 10 for the maximum length of a 32-bit integer + 1 for the \0 */
+        size_t trash_size = vol_size + sizeof("/.Trashes/") + 10 + 1 + name_size + 1;
+        trash_path = heap_alloc(trash_size);
+        if (!trash_path)
+            return NULL;
+        snprintf(trash_path, trash_size, "%s/.Trashes/%u", stfs.f_mntonname, geteuid());
+    }
+    return trash_path;
+}
 
 BOOL TRASH_CanTrashFile(LPCWSTR wszPath)
 {
-    char *unix_path;
-    OSStatus status;
-    FSRef ref;
-    FSCatalogInfo catalogInfo;
+    char *unix_path, *trash_path;
+    const char *base_name;
+    BOOL can_trash;
+    struct stat st;
 
     TRACE("(%s)\n", debugstr_w(wszPath));
+
     if (!(unix_path = wine_get_unix_file_name(wszPath)))
         return FALSE;
-
-    status = FSPathMakeRef((UInt8*)unix_path, &ref, NULL);
+    if (!(trash_path = TRASH_GetTrashPath(unix_path, &base_name)))
+    {
+        heap_free(unix_path);
+        return FALSE;
+    }
+    can_trash = stat(trash_path, &st) == 0;
     heap_free(unix_path);
-    if (status == noErr)
-        status = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &catalogInfo, NULL,
-                                  NULL, NULL);
-    if (status == noErr)
-        status = FSFindFolder(catalogInfo.volume, kTrashFolderType,
-                              kCreateFolder, &ref);
-
-    return (status == noErr);
+    heap_free(trash_path);
+    return can_trash;
 }
 
 BOOL TRASH_TrashFile(LPCWSTR wszPath)
 {
-    char *unix_path;
-    OSStatus status;
+    char *unix_path, *trash_path;
+    const char *base_name;
+    int res;
 
     TRACE("(%s)\n", debugstr_w(wszPath));
     if (!(unix_path = wine_get_unix_file_name(wszPath)))
         return FALSE;
+    if (!(trash_path = TRASH_GetTrashPath(unix_path, &base_name)))
+    {
+        heap_free(unix_path);
+        return FALSE;
+    }
 
-    status = FSPathMoveObjectToTrashSync(unix_path, NULL, kFSFileOperationSkipPreflight);
+    lstrcatA(trash_path, "/");
+    lstrcatA(trash_path, base_name);
+
+    res = rename(unix_path, trash_path);
 
     heap_free(unix_path);
-    return (status == noErr);
+    heap_free(trash_path);
+    return (res != -1);
 }
 
 /* TODO:
@@ -186,10 +237,8 @@ HRESULT TRASH_GetDetails(const char *trash_path, const char *name, WIN32_FIND_DA
 HRESULT TRASH_EnumItems(const WCHAR *path, LPITEMIDLIST **pidls, int *count)
 {
     WCHAR volume_path[MAX_PATH];
-    char *unix_path, trash_path[MAX_PATH];
-    FSCatalogInfo catalog_info;
-    OSStatus status;
-    FSRef ref;
+    char *unix_path, *trash_path;
+    const char *base_name;
     struct dirent *entry;
     DIR *dir;
     LPITEMIDLIST *ret;
@@ -211,15 +260,8 @@ HRESULT TRASH_EnumItems(const WCHAR *path, LPITEMIDLIST **pidls, int *count)
     if(!(unix_path = wine_get_unix_file_name(volume_path)))
         return E_OUTOFMEMORY;
 
-    status = FSPathMakeRef((UInt8*)unix_path, &ref, NULL);
-    heap_free(unix_path);
-    if(status != noErr) return E_FAIL;
-    status = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &catalog_info, NULL, NULL, NULL);
-    if(status != noErr) return E_FAIL;
-    status = FSFindFolder(catalog_info.volume, kTrashFolderType, kCreateFolder, &ref);
-    if(status != noErr) return E_FAIL;
-    status = FSRefMakePath(&ref, (UInt8*)trash_path, MAX_PATH);
-    if(status != noErr) return E_FAIL;
+    if(!(trash_path = TRASH_GetTrashPath(unix_path, &base_name)))
+        return E_OUTOFMEMORY;
 
     if(!(dir = opendir(trash_path))) return E_FAIL;
     ret = heap_alloc(ret_size * sizeof(*ret));
@@ -282,7 +324,7 @@ HRESULT TRASH_EraseItem(LPCITEMIDLIST pidl)
     return E_NOTIMPL;
 }
 
-#else /* HAVE_CORESERVICES_CORESERVICES_H */
+#else /* __APPLE__ */
 
 static CRITICAL_SECTION TRASH_Creating;
 static CRITICAL_SECTION_DEBUG TRASH_Creating_Debug =
@@ -790,4 +832,4 @@ HRESULT TRASH_EraseItem(LPCITEMIDLIST pidl)
     return S_OK;
 }
 
-#endif /* HAVE_CORESERVICES_CORESERVICES_H */
+#endif /* __APPLE__ */
-- 
2.18.0




More information about the wine-devel mailing list