[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