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

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>
Signed-off-by: Ken Thomases <ken@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Chip Davis 2018-07-19 15:50:48 -05:00 committed by Alexandre Julliard
parent bb264a0ac6
commit efac5d0672
1 changed files with 104 additions and 44 deletions

View File

@ -22,24 +22,18 @@
#include "config.h" #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 <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <sys/types.h>
#ifdef HAVE_SYS_STAT_H #ifdef HAVE_SYS_STAT_H
# include <sys/stat.h> # include <sys/stat.h>
#endif #endif
#include <sys/types.h> #ifdef HAVE_SYS_MOUNT_H
# include <sys/mount.h>
#endif
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
@ -47,6 +41,9 @@
#ifdef HAVE_DIRENT_H #ifdef HAVE_DIRENT_H
# include <dirent.h> # include <dirent.h>
#endif #endif
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
@ -109,44 +106,116 @@ HRESULT TRASH_UnpackItemID(LPCSHITEMID id, WIN32_FIND_DATAW *data)
return S_OK; 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) BOOL TRASH_CanTrashFile(LPCWSTR wszPath)
{ {
char *unix_path; char *unix_path, *trash_path;
OSStatus status; const char *base_name;
FSRef ref; BOOL can_trash;
FSCatalogInfo catalogInfo; struct stat st;
TRACE("(%s)\n", debugstr_w(wszPath)); TRACE("(%s)\n", debugstr_w(wszPath));
if (!(unix_path = wine_get_unix_file_name(wszPath))) if (!(unix_path = wine_get_unix_file_name(wszPath)))
return FALSE; return FALSE;
if (!(trash_path = TRASH_GetTrashPath(unix_path, &base_name)))
status = FSPathMakeRef((UInt8*)unix_path, &ref, NULL); {
heap_free(unix_path); heap_free(unix_path);
if (status == noErr) return FALSE;
status = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &catalogInfo, NULL, }
NULL, NULL); can_trash = stat(trash_path, &st) == 0;
if (status == noErr) if (!can_trash && errno == ENOENT)
status = FSFindFolder(catalogInfo.volume, kTrashFolderType, {
kCreateFolder, &ref); /* Recursively create the Trash folder. */
char *p = trash_path;
return (status == noErr); if (*p == '/') ++p;
while ((p = strchr(p, '/')) != NULL)
{
*p = '\0';
if (mkdir(trash_path, 0755) == -1 && errno != EEXIST)
{
heap_free(unix_path);
heap_free(trash_path);
return FALSE;
}
*p++ = '/';
}
can_trash = TRUE;
}
heap_free(unix_path);
heap_free(trash_path);
return can_trash;
} }
BOOL TRASH_TrashFile(LPCWSTR wszPath) BOOL TRASH_TrashFile(LPCWSTR wszPath)
{ {
char *unix_path; char *unix_path, *trash_path;
OSStatus status; const char *base_name;
int res;
TRACE("(%s)\n", debugstr_w(wszPath)); TRACE("(%s)\n", debugstr_w(wszPath));
if (!(unix_path = wine_get_unix_file_name(wszPath))) if (!(unix_path = wine_get_unix_file_name(wszPath)))
return FALSE; 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); heap_free(unix_path);
return (status == noErr); heap_free(trash_path);
return (res != -1);
} }
/* TODO: /* TODO:
@ -186,10 +255,8 @@ HRESULT TRASH_GetDetails(const char *trash_path, const char *name, WIN32_FIND_DA
HRESULT TRASH_EnumItems(const WCHAR *path, LPITEMIDLIST **pidls, int *count) HRESULT TRASH_EnumItems(const WCHAR *path, LPITEMIDLIST **pidls, int *count)
{ {
WCHAR volume_path[MAX_PATH]; WCHAR volume_path[MAX_PATH];
char *unix_path, trash_path[MAX_PATH]; char *unix_path, *trash_path;
FSCatalogInfo catalog_info; const char *base_name;
OSStatus status;
FSRef ref;
struct dirent *entry; struct dirent *entry;
DIR *dir; DIR *dir;
LPITEMIDLIST *ret; LPITEMIDLIST *ret;
@ -211,15 +278,8 @@ HRESULT TRASH_EnumItems(const WCHAR *path, LPITEMIDLIST **pidls, int *count)
if(!(unix_path = wine_get_unix_file_name(volume_path))) if(!(unix_path = wine_get_unix_file_name(volume_path)))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
status = FSPathMakeRef((UInt8*)unix_path, &ref, NULL); if(!(trash_path = TRASH_GetTrashPath(unix_path, &base_name)))
heap_free(unix_path); return E_OUTOFMEMORY;
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(!(dir = opendir(trash_path))) return E_FAIL; if(!(dir = opendir(trash_path))) return E_FAIL;
ret = heap_alloc(ret_size * sizeof(*ret)); ret = heap_alloc(ret_size * sizeof(*ret));
@ -282,7 +342,7 @@ HRESULT TRASH_EraseItem(LPCITEMIDLIST pidl)
return E_NOTIMPL; return E_NOTIMPL;
} }
#else /* HAVE_CORESERVICES_CORESERVICES_H */ #else /* __APPLE__ */
static CRITICAL_SECTION TRASH_Creating; static CRITICAL_SECTION TRASH_Creating;
static CRITICAL_SECTION_DEBUG TRASH_Creating_Debug = static CRITICAL_SECTION_DEBUG TRASH_Creating_Debug =
@ -790,4 +850,4 @@ HRESULT TRASH_EraseItem(LPCITEMIDLIST pidl)
return S_OK; return S_OK;
} }
#endif /* HAVE_CORESERVICES_CORESERVICES_H */ #endif /* __APPLE__ */