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:
parent
bb264a0ac6
commit
efac5d0672
|
@ -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);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
can_trash = stat(trash_path, &st) == 0;
|
||||||
|
if (!can_trash && errno == ENOENT)
|
||||||
|
{
|
||||||
|
/* Recursively create the Trash folder. */
|
||||||
|
char *p = trash_path;
|
||||||
|
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(unix_path);
|
||||||
if (status == noErr)
|
heap_free(trash_path);
|
||||||
status = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &catalogInfo, NULL,
|
return can_trash;
|
||||||
NULL, NULL);
|
|
||||||
if (status == noErr)
|
|
||||||
status = FSFindFolder(catalogInfo.volume, kTrashFolderType,
|
|
||||||
kCreateFolder, &ref);
|
|
||||||
|
|
||||||
return (status == noErr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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__ */
|
||||||
|
|
Loading…
Reference in New Issue