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: Chip Davis cdavis@codeweavers.com --- Resending from my work email... --- 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__ */
On Jul 19, 2018, at 3:16 PM, Chip Davis cdavis@codeweavers.com wrote:
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);
The old code would attempt to create the Trash folder if it doesn't exist, but your new code doesn't.
- 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);
trash_path is just big enough for the path to the Trash directory. You can't concatenate to it without reallocating it larger.
res = rename(unix_path, trash_path);
heap_free(unix_path);
- return (status == noErr);
- heap_free(trash_path);
- return (res != -1);
}
-Ken
July 19, 2018 3:34 PM, "Ken Thomases" ken@codeweavers.com wrote:
On Jul 19, 2018, at 3:16 PM, Chip Davis cdavis@codeweavers.com wrote:
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);
The old code would attempt to create the Trash folder if it doesn't exist, but your new code doesn't.
Yeah, I realized that after I sent this. Will fix.
- 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);
trash_path is just big enough for the path to the Trash directory. You can't concatenate to it without reallocating it larger.
Actually, that's why I added the size of the base_name to the total size--specifically so I could do that.
- res = rename(unix_path, trash_path);
heap_free(unix_path);
- return (status == noErr);
- heap_free(trash_path);
- return (res != -1);
}
-Ken
Chip
On Jul 19, 2018, at 3:37 PM, Chip Davis cdavis@codeweavers.com wrote:
July 19, 2018 3:34 PM, "Ken Thomases" ken@codeweavers.com wrote:
trash_path is just big enough for the path to the Trash directory. You can't concatenate to it without reallocating it larger.
Actually, that's why I added the size of the base_name to the total size--specifically so I could do that.
Ah, right. Sorry. :)
-Ken