Files

364 lines
8.5 KiB
C

/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/recyclebin.c
* PURPOSE: Public interface
* PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau ([email protected])
*/
#include "recyclebin_private.h"
BOOL WINAPI
CloseRecycleBinHandle(
IN HDELFILE hDeletedFile)
{
IRecycleBinFile *rbf = IRecycleBinFileFromHDELFILE(hDeletedFile);
HRESULT hr;
TRACE("(%p)\n", hDeletedFile);
hr = IRecycleBinFile_Release(rbf);
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
BOOL WINAPI
DeleteFileToRecycleBinA(
IN LPCSTR FileName)
{
int len;
LPWSTR FileNameW = NULL;
BOOL ret = FALSE;
TRACE("(%s)\n", debugstr_a(FileName));
/* Check parameters */
if (FileName == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
len = MultiByteToWideChar(CP_ACP, 0, FileName, -1, NULL, 0);
if (len == 0)
goto cleanup;
FileNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!FileNameW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
if (MultiByteToWideChar(CP_ACP, 0, FileName, -1, FileNameW, len) == 0)
goto cleanup;
ret = DeleteFileToRecycleBinW(FileNameW);
cleanup:
HeapFree(GetProcessHeap(), 0, FileNameW);
return ret;
}
BOOL WINAPI
DeleteFileToRecycleBinW(
IN LPCWSTR FileName)
{
IRecycleBin *prb;
HRESULT hr;
TRACE("(%s)\n", debugstr_w(FileName));
hr = GetDefaultRecycleBin(NULL, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
hr = IRecycleBin_DeleteFile(prb, FileName);
IRecycleBin_Release(prb);
cleanup:
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
BOOL WINAPI
DeleteFileInRecycleBin(
IN HDELFILE hDeletedFile)
{
IRecycleBinFile *rbf = IRecycleBinFileFromHDELFILE(hDeletedFile);
HRESULT hr;
TRACE("(%p)\n", hDeletedFile);
hr = IRecycleBinFile_Delete(rbf);
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
BOOL WINAPI
EmptyRecycleBinA(
IN LPCSTR pszRoot OPTIONAL)
{
int len;
LPWSTR szRootW = NULL;
BOOL ret = FALSE;
TRACE("(%s)\n", debugstr_a(pszRoot));
if (pszRoot)
{
len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
if (len == 0)
goto cleanup;
szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!szRootW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
goto cleanup;
}
ret = EmptyRecycleBinW(szRootW);
cleanup:
HeapFree(GetProcessHeap(), 0, szRootW);
return ret;
}
BOOL WINAPI
EmptyRecycleBinW(
IN LPCWSTR pszRoot OPTIONAL)
{
IRecycleBin *prb;
HRESULT hr;
TRACE("(%s)\n", debugstr_w(pszRoot));
hr = GetDefaultRecycleBin(pszRoot, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
hr = IRecycleBin_EmptyRecycleBin(prb);
IRecycleBin_Release(prb);
cleanup:
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
BOOL WINAPI
EnumerateRecycleBinA(
IN LPCSTR pszRoot OPTIONAL,
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
IN PVOID Context OPTIONAL)
{
int len;
LPWSTR szRootW = NULL;
BOOL ret = FALSE;
TRACE("(%s, %p, %p)\n", debugstr_a(pszRoot), pFnCallback, Context);
if (pszRoot)
{
len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
if (len == 0)
goto cleanup;
szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!szRootW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
goto cleanup;
}
ret = EnumerateRecycleBinW(szRootW, pFnCallback, Context);
cleanup:
HeapFree(GetProcessHeap(), 0, szRootW);
return ret;
}
BOOL WINAPI
EnumerateRecycleBinW(
IN LPCWSTR pszRoot OPTIONAL,
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
IN PVOID Context OPTIONAL)
{
IRecycleBin *prb = NULL;
IRecycleBinEnumList *prbel = NULL;
IRecycleBinFile *prbf;
HRESULT hr;
TRACE("(%s, %p, %p)\n", debugstr_w(pszRoot), pFnCallback, Context);
hr = GetDefaultRecycleBin(NULL, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
hr = IRecycleBin_EnumObjects(prb, &prbel);
if (!SUCCEEDED(hr))
goto cleanup;
while (TRUE)
{
hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
if (hr == S_FALSE)
{
hr = S_OK;
goto cleanup;
}
else if (!SUCCEEDED(hr))
goto cleanup;
if (!pFnCallback(Context, (HDELFILE)prbf))
{
UINT error = GetLastError();
hr = HRESULT_FROM_WIN32(error);
goto cleanup;
}
}
cleanup:
if (prb)
IRecycleBin_Release(prb);
if (prbel)
IRecycleBinEnumList_Release(prbel);
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
typedef struct _BBENUMFILECONTEXT
{
const RECYCLEBINFILEIDENTITY *pFI;
HDELFILE hDelFile;
} BBENUMFILECONTEXT;
static BOOL CALLBACK
GetRecycleBinFileHandleCallback(IN PVOID Context, IN HDELFILE hDeletedFile)
{
BBENUMFILECONTEXT *pCtx = (BBENUMFILECONTEXT*)Context;
IRecycleBinFile *pRBF = IRecycleBinFileFromHDELFILE(hDeletedFile);
if (IRecycleBinFile_IsEqualIdentity(pRBF, pCtx->pFI) == S_OK)
{
pCtx->hDelFile = hDeletedFile;
return FALSE;
}
CloseRecycleBinHandle(hDeletedFile);
return TRUE;
}
EXTERN_C HDELFILE
GetRecycleBinFileHandle(
IN LPCWSTR pszRoot OPTIONAL,
IN const RECYCLEBINFILEIDENTITY *pFI)
{
BBENUMFILECONTEXT context = { pFI, NULL };
EnumerateRecycleBinW(pszRoot, GetRecycleBinFileHandleCallback, &context);
return context.hDelFile;
}
EXTERN_C BOOL
RemoveFromRecycleBinDatabase(
IN const RECYCLEBINFILEIDENTITY *pFI)
{
BOOL ret = FALSE;
HDELFILE hDelFile = GetRecycleBinFileHandle(NULL, pFI);
if (hDelFile)
{
IRecycleBinFile *rbf = IRecycleBinFileFromHDELFILE(hDelFile);
ret = SUCCEEDED(IRecycleBinFile_RemoveFromDatabase(rbf));
CloseRecycleBinHandle(hDelFile);
}
return ret;
}
BOOL WINAPI
RestoreFileFromRecycleBin(
IN HDELFILE hDeletedFile)
{
IRecycleBinFile *rbf = IRecycleBinFileFromHDELFILE(hDeletedFile);
HRESULT hr;
TRACE("(%p)\n", hDeletedFile);
hr = IRecycleBinFile_Restore(rbf);
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
EXTERN_C HRESULT
GetDefaultRecycleBin(
IN LPCWSTR pszVolume OPTIONAL,
OUT IRecycleBin **pprb)
{
IUnknown *pUnk;
HRESULT hr;
TRACE("(%s, %p)\n", debugstr_w(pszVolume), pprb);
if (!pprb)
return E_POINTER;
if (!pszVolume)
hr = RecycleBinGeneric_Constructor(&pUnk);
else
{
/* FIXME: do a better validation! */
if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
/* For now, only support this type of recycle bins... */
hr = RecycleBin5_Constructor(pszVolume, &pUnk);
}
if (!SUCCEEDED(hr))
return hr;
hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBin, (void **)pprb);
IUnknown_Release(pUnk);
return hr;
}
EXTERN_C HRESULT
GetRecycleBinPathFromDriveNumber(UINT Drive, LPWSTR Path)
{
const WCHAR volume[] = { LOWORD('A' + Drive), ':', '\\', '\0' };
IRecycleBin *pRB;
HRESULT hr = GetDefaultRecycleBin(volume, &pRB);
if (SUCCEEDED(hr))
{
hr = IRecycleBin_GetDirectory(pRB, Path);
IRecycleBin_Release(pRB);
}
return hr;
}