mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 04:13:34 +00:00
364 lines
8.5 KiB
C
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;
|
|
}
|