Fix some bugs which were preventing enumeration of all deleted files

Add a system-wide recycle bin, which federates all individual recycle bins
Add a COM interface to the recycle bin library
Use COM ref counting instead of a house-made system

svn path=/trunk/; revision=29998
This commit is contained in:
Hervé Poussineau 2007-10-31 08:57:35 +00:00
parent 61edd081e9
commit 25e2d0f59e
13 changed files with 1979 additions and 1124 deletions

View file

@ -0,0 +1,14 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/guid.c
* PURPOSE: Define GUID values
* PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
*/
#define INITGUID
#include <initguid.h>
DEFINE_GUID(IID_IRecycleBin, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x80);
DEFINE_GUID(IID_IRecycleBinEnumList, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x81);
DEFINE_GUID(IID_IRecycleBinFile, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x82);
DEFINE_GUID(IID_IRecycleBin5, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x83);

View file

@ -1,315 +0,0 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/openclose.c
* PURPOSE: Open/close recycle bins
* PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "recyclebin_private.h"
BOOL
IntCheckDeletedFileHandle(
IN HANDLE hDeletedFile)
{
if (hDeletedFile == NULL || hDeletedFile == INVALID_HANDLE_VALUE)
return FALSE;
if (((PDELETED_FILE_HANDLE)hDeletedFile)->magic != DELETEDFILE_MAGIC)
return FALSE;
return TRUE;
}
static BOOL
IntCloseRecycleBinHandle(
IN PREFCOUNT_DATA pData)
{
PRECYCLE_BIN bin;
bin = CONTAINING_RECORD(pData, RECYCLE_BIN, refCount);
if (!CloseHandle(bin->hInfo))
return FALSE;
RemoveEntryList(&bin->ListEntry);
HeapFree(GetProcessHeap(), 0, bin);
return TRUE;
}
static BOOL
IntCreateEmptyRecycleBin(
IN PRECYCLE_BIN bin,
IN PSID OwnerSid OPTIONAL)
{
LPWSTR BufferName = NULL;
LPWSTR Separator; /* Pointer into BufferName buffer */
LPWSTR FileName; /* Pointer into BufferName buffer */
LPCSTR DesktopIniContents = "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
DWORD Info2Contents[] = { 5, 0, 0, 0x320, 0 };
SIZE_T BytesToWrite, BytesWritten, Needed;
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL ret = FALSE;
Needed = (wcslen(bin->Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR);
BufferName = HeapAlloc(GetProcessHeap(), 0, Needed);
if (!BufferName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
wcscpy(BufferName, bin->Folder);
Separator = wcsstr(&BufferName[3], L"\\");
if (Separator)
*Separator = UNICODE_NULL;
ret = CreateDirectoryW(BufferName, NULL);
if (!ret && GetLastError() != ERROR_ALREADY_EXISTS)
goto cleanup;
SetFileAttributesW(BufferName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
if (Separator)
{
*Separator = L'\\';
ret = CreateDirectoryW(BufferName, NULL);
if (!ret && GetLastError() != ERROR_ALREADY_EXISTS)
goto cleanup;
}
if (OwnerSid)
{
//DWORD rc;
/* Add ACL to allow only user/SYSTEM to open it */
/* FIXME: rc = SetNamedSecurityInfo(
BufferName,
SE_FILE_OBJECT,
???,
OwnerSid,
NULL,
???,
???);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
*/
}
wcscat(BufferName, L"\\");
FileName = &BufferName[wcslen(BufferName)];
/* Create desktop.ini */
wcscpy(FileName, L"desktop.ini");
hFile = CreateFileW(BufferName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL);
if (hFile == INVALID_HANDLE_VALUE)
goto cleanup;
BytesToWrite = strlen(DesktopIniContents);
ret = WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten, NULL);
if (!ret)
goto cleanup;
if (BytesWritten != BytesToWrite)
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
/* Create empty INFO2 file */
wcscpy(FileName, RECYCLE_BIN_FILE_NAME);
hFile = CreateFileW(BufferName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
if (hFile == INVALID_HANDLE_VALUE)
goto cleanup;
BytesToWrite = sizeof(Info2Contents);
ret = WriteFile(hFile, Info2Contents, (DWORD)BytesToWrite, &BytesWritten, NULL);
if (!ret)
goto cleanup;
if (BytesWritten != BytesToWrite)
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
bin->hInfo = hFile;
ret = TRUE;
cleanup:
HeapFree(GetProcessHeap(), 0, BufferName);
if (!ret)
{
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
}
return ret;
}
PRECYCLE_BIN
IntReferenceRecycleBin(
IN WCHAR driveLetter)
{
PLIST_ENTRY ListEntry;
PRECYCLE_BIN bin = NULL, ret = NULL;
WCHAR RootPath[4];
DWORD FileSystemFlags;
LPCWSTR RecycleBinDirectory;
HANDLE tokenHandle = INVALID_HANDLE_VALUE;
PTOKEN_USER TokenUserInfo = NULL;
LPWSTR StringSid = NULL;
SIZE_T Needed, DirectoryLength;
INFO2_HEADER Header;
BOOL AlreadyCreated = FALSE;
DWORD bytesRead;
static LIST_ENTRY ListHead;
static BOOL ListInitialized = FALSE;
if (!ListInitialized)
{
InitializeListHead(&ListHead);
ListInitialized = TRUE;
}
/* Search if the recycle bin has already been opened */
driveLetter = (WCHAR)toupper(driveLetter);
ListEntry = ListHead.Flink;
while (ListEntry != &ListHead)
{
bin = CONTAINING_RECORD(ListEntry, RECYCLE_BIN, ListEntry);
if (bin->Folder[0] == driveLetter)
{
ReferenceHandle(&bin->refCount);
return bin;
}
ListEntry = ListEntry->Flink;
}
bin = NULL;
/* We need to create a new recycle bin */
/* Get information about file system */
wsprintfW(RootPath, L"%c:\\", driveLetter);
if (!GetVolumeInformationW(
RootPath,
NULL,
0,
NULL,
NULL,
&FileSystemFlags,
NULL,
0))
{
goto cleanup;
}
if (!(FileSystemFlags & FILE_PERSISTENT_ACLS))
RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL;
else
{
RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL;
/* Get user SID */
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle))
goto cleanup;
if (GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &Needed))
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto cleanup;
TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed);
if (!TokenUserInfo)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
if (!GetTokenInformation(tokenHandle, TokenUser, TokenUserInfo, (DWORD)Needed, &Needed))
goto cleanup;
if (!ConvertSidToStringSidW(TokenUserInfo->User.Sid, &StringSid))
goto cleanup;
}
/* Create RECYCLEBIN structure */
openfile:
DirectoryLength = 3 + wcslen(RecycleBinDirectory) + 1;
if (StringSid)
DirectoryLength += wcslen(StringSid) + 1;
Needed = FIELD_OFFSET(RECYCLE_BIN, Folder) + (2 * DirectoryLength + 2 + wcslen(RECYCLE_BIN_FILE_NAME))* sizeof(WCHAR);
bin = HeapAlloc(GetProcessHeap(), 0, Needed);
if (!bin)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
memset(bin, 0, Needed);
InitializeHandle(&bin->refCount, IntCloseRecycleBinHandle);
bin->magic = RECYCLEBIN_MAGIC;
bin->hInfo = INVALID_HANDLE_VALUE;
bin->InfoFile = &bin->Folder[DirectoryLength];
bin->Folder[0] = driveLetter;
bin->Folder[1] = '\0';
wcscat(bin->Folder, L":\\");
wcscat(bin->Folder, RecycleBinDirectory);
if (StringSid)
{
wcscat(bin->Folder, L"\\");
wcscat(bin->Folder, StringSid);
}
wcscpy(bin->InfoFile, bin->Folder);
wcscat(bin->InfoFile, L"\\");
wcscat(bin->InfoFile, RECYCLE_BIN_FILE_NAME);
InsertTailList(&ListHead, &bin->ListEntry);
/* Open info file */
bin->hInfo = CreateFileW(bin->InfoFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (bin->hInfo == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND)
{
if (!IntCreateEmptyRecycleBin(bin, TokenUserInfo ? TokenUserInfo->User.Sid : NULL))
goto cleanup;
AlreadyCreated = TRUE;
}
}
if (bin->hInfo == INVALID_HANDLE_VALUE)
goto cleanup;
if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
goto cleanup;
if (!ReadFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesRead, NULL))
goto cleanup;
if (bytesRead != sizeof(INFO2_HEADER) && !AlreadyCreated)
{
/* Create a new file */
if (!DereferenceHandle(&bin->refCount))
goto cleanup;
if (!DeleteFileW(bin->InfoFile))
goto cleanup;
goto openfile;
}
switch (Header.dwVersion)
{
case 5:
InitializeCallbacks5(&bin->Callbacks);
break;
default:
/* Unknown recycle bin version */
SetLastError(ERROR_NOT_SUPPORTED);
goto cleanup;
}
ret = bin;
cleanup:
if (tokenHandle != INVALID_HANDLE_VALUE)
CloseHandle(tokenHandle);
HeapFree(GetProcessHeap(), 0, TokenUserInfo);
if (StringSid)
LocalFree(StringSid);
if (!ret)
{
if (bin && bin->hInfo != INVALID_HANDLE_VALUE)
DereferenceHandle(&bin->refCount);
HeapFree(GetProcessHeap(), 0, bin);
}
return ret;
}

View file

@ -1,7 +1,6 @@
This library deals with Recycle bin.
It is aimed to be compatible with Windows 2000/XP/2003 (at least) on FAT or NTFS volumes.
TODO
- Empty a recycle bin containing directories (v5)
- Set security on recycle bin folder
@ -9,7 +8,6 @@ TODO
- Make the library thread-safe
3 levels
- 1: recyclebin.c: Public interface
- 2a: openclose.c: Open/close recycle bins
- 2b: refcount.c: Do reference counting on objects
- 3: recyclebin_v5.c: Deals with recycle bins of Windows 2000/XP/2003
- 1: recyclebin.c : Public C interface
- 2: recyclebin_generic.c : 'System-wide' recycle bin, which knows no implementation detail
- 3: recyclebin_v5.c : Deals with recycle bins of Windows 2000/XP/2003

View file

@ -1,35 +1,30 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/openclose.c
* FILE: lib/recyclebin/recyclebin.c
* PURPOSE: Public interface
* PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
* PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
#define COBJMACROS
#include "recyclebin_private.h"
typedef struct _ENUMERATE_RECYCLE_BIN_CONTEXT
{
PRECYCLE_BIN bin;
PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback;
PVOID Context;
} ENUMERATE_RECYCLE_BIN_CONTEXT, *PENUMERATE_RECYCLE_BIN_CONTEXT;
#include <stdio.h>
BOOL WINAPI
CloseRecycleBinHandle(
IN HANDLE hDeletedFile)
{
BOOL ret = FALSE;
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
HRESULT hr;
if (!IntCheckDeletedFileHandle(hDeletedFile))
SetLastError(ERROR_INVALID_HANDLE);
hr = IRecycleBinFile_Release(rbf);
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
{
PDELETED_FILE_HANDLE file = (PDELETED_FILE_HANDLE)hDeletedFile;
ret = DereferenceHandle(&file->refCount);
}
return ret;
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
BOOL WINAPI
@ -70,89 +65,78 @@ BOOL WINAPI
DeleteFileToRecycleBinW(
IN LPCWSTR FileName)
{
LPWSTR FullFileName = NULL;
DWORD dwBufferLength = 0;
LPWSTR lpFilePart;
DWORD len;
PRECYCLE_BIN bin = NULL;
BOOL ret = FALSE;
IRecycleBin *prb;
HRESULT hr;
/* Check parameters */
if (FileName == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
/* Get full file name */
while (TRUE)
{
len = GetFullPathNameW(FileName, dwBufferLength, FullFileName, &lpFilePart);
if (len == 0)
goto cleanup;
else if (len < dwBufferLength)
break;
HeapFree(GetProcessHeap(), 0, FullFileName);
dwBufferLength = len;
FullFileName = HeapAlloc(GetProcessHeap(), 0, dwBufferLength * sizeof(WCHAR));
if (!FullFileName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
}
if (!lpFilePart || dwBufferLength < 2 || FullFileName[1] != ':')
{
/* Only a directory name, or not a local file */
SetLastError(ERROR_INVALID_NAME);
}
/* Open recycle bin */
bin = IntReferenceRecycleBin(FullFileName[0]);
if (!bin)
hr = GetDefaultRecycleBin(NULL, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
if (bin->Callbacks.DeleteFile)
ret = bin->Callbacks.DeleteFile(bin, FullFileName, lpFilePart);
else
SetLastError(ERROR_NOT_SUPPORTED);
hr = IRecycleBin_DeleteFile(prb, FileName);
IRecycleBin_Release(prb);
cleanup:
HeapFree(GetProcessHeap(), 0, FullFileName);
if (bin)
DereferenceHandle(&bin->refCount);
return ret;
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 CHAR driveLetter)
IN LPCSTR pszRoot OPTIONAL)
{
return EmptyRecycleBinW((WCHAR)driveLetter);
int len;
LPWSTR szRootW = NULL;
BOOL ret = FALSE;
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 WCHAR driveLetter)
IN LPCWSTR pszRoot OPTIONAL)
{
PRECYCLE_BIN bin = NULL;
BOOL ret = FALSE;
IRecycleBin *prb;
HRESULT hr;
/* Open recycle bin */
bin = IntReferenceRecycleBin(driveLetter);
if (!bin)
hr = GetDefaultRecycleBin(pszRoot, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
if (bin->Callbacks.EmptyRecycleBin)
ret = bin->Callbacks.EmptyRecycleBin(&bin);
else
SetLastError(ERROR_NOT_SUPPORTED);
hr = IRecycleBin_EmptyRecycleBin(prb);
IRecycleBin_Release(prb);
cleanup:
if (bin)
DereferenceHandle(&bin->refCount);
return ret;
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
BOOL WINAPI
@ -164,92 +148,54 @@ EnumerateRecycleBinA(
return EnumerateRecycleBinW((WCHAR)driveLetter, pFnCallback, Context);
}
static BOOL
IntCloseDeletedFileHandle(
IN PREFCOUNT_DATA pData)
{
PDELETED_FILE_HANDLE file;
file = CONTAINING_RECORD(pData, DELETED_FILE_HANDLE, refCount);
if (!DereferenceHandle(&file->bin->refCount))
return FALSE;
file->magic = 0;
HeapFree(GetProcessHeap(), 0, file);
return TRUE;
}
static BOOL
IntEnumerateRecycleBinCallback(
IN PVOID Context,
IN HANDLE hDeletedFile)
{
PENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext = (PENUMERATE_RECYCLE_BIN_CONTEXT)Context;
PDELETED_FILE_HANDLE DeletedFileHandle = NULL;
BOOL ret = FALSE;
DeletedFileHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(DELETED_FILE_HANDLE));
if (!DeletedFileHandle)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
ReferenceHandle(&CallbackContext->bin->refCount);
InitializeHandle(&DeletedFileHandle->refCount, IntCloseDeletedFileHandle);
DeletedFileHandle->magic = DELETEDFILE_MAGIC;
DeletedFileHandle->bin = CallbackContext->bin;
DeletedFileHandle->hDeletedFile = hDeletedFile;
ret = CallbackContext->pFnCallback(CallbackContext->Context, DeletedFileHandle);
cleanup:
if (!ret)
{
if (DeletedFileHandle)
DereferenceHandle(&DeletedFileHandle->refCount);
}
return ret;
}
BOOL WINAPI
EnumerateRecycleBinW(
IN WCHAR driveLetter,
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
IN PVOID Context OPTIONAL)
{
PRECYCLE_BIN bin = NULL;
BOOL ret = FALSE;
IRecycleBin *prb = NULL;
IRecycleBinEnumList *prbel = NULL;
IRecycleBinFile *prbf;
HRESULT hr;
/* Check parameters */
if (pFnCallback == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
/* Open recycle bin */
bin = IntReferenceRecycleBin(driveLetter);
if (!bin)
hr = GetDefaultRecycleBin(NULL, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
if (bin->Callbacks.EnumerateFiles)
hr = IRecycleBin_EnumObjects(prb, &prbel);
if (!SUCCEEDED(hr))
goto cleanup;
while (TRUE)
{
ENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext;
CallbackContext.bin = bin;
CallbackContext.pFnCallback = pFnCallback;
CallbackContext.Context = Context;
ret = bin->Callbacks.EnumerateFiles(bin, IntEnumerateRecycleBinCallback, &CallbackContext);
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, (HANDLE)prbf))
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
IRecycleBinFile_Release(prbf);
}
else
SetLastError(ERROR_NOT_SUPPORTED);
cleanup:
if (bin)
DereferenceHandle(&bin->refCount);
return ret;
if (prb)
IRecycleBin_Release(prb);
if (prbel)
IRecycleBinEnumList_Release(prb);
if (SUCCEEDED(hr))
return TRUE;
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
SetLastError(HRESULT_CODE(hr));
else
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
BOOL WINAPI
@ -284,7 +230,7 @@ GetDeletedFileDetailsA(
if (FileDetails)
{
memcpy(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
CopyMemory(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL))
goto cleanup;
}
@ -302,38 +248,92 @@ GetDeletedFileDetailsW(
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
OUT LPDWORD RequiredSize OPTIONAL)
{
BOOL ret = FALSE;
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
HRESULT hr;
SIZE_T NameSize, Needed;
if (!IntCheckDeletedFileHandle(hDeletedFile))
SetLastError(ERROR_INVALID_HANDLE);
else
hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
if (!SUCCEEDED(hr))
goto cleanup;
Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + NameSize;
if (RequiredSize)
*RequiredSize = (DWORD)Needed;
if (Needed > BufferSize)
{
PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile;
if (DeletedFile->bin->Callbacks.GetDetails)
ret = DeletedFile->bin->Callbacks.GetDetails(DeletedFile->bin, DeletedFile->hDeletedFile, BufferSize, FileDetails, RequiredSize);
else
SetLastError(ERROR_NOT_SUPPORTED);
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
goto cleanup;
}
hr = IRecycleBinFile_GetFileName(rbf, NameSize, FileDetails->FileName, NULL);
if (!SUCCEEDED(hr))
goto cleanup;
hr = IRecycleBinFile_GetLastModificationTime(rbf, &FileDetails->LastModification);
if (!SUCCEEDED(hr))
goto cleanup;
hr = IRecycleBinFile_GetDeletionTime(rbf, &FileDetails->DeletionTime);
if (!SUCCEEDED(hr))
goto cleanup;
hr = IRecycleBinFile_GetFileSize(rbf, &FileDetails->FileSize);
if (!SUCCEEDED(hr))
goto cleanup;
hr = IRecycleBinFile_GetPhysicalFileSize(rbf, &FileDetails->PhysicalFileSize);
if (!SUCCEEDED(hr))
goto cleanup;
hr = IRecycleBinFile_GetAttributes(rbf, &FileDetails->Attributes);
if (!SUCCEEDED(hr))
goto cleanup;
return ret;
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
RestoreFile(
IN HANDLE hDeletedFile)
{
BOOL ret = FALSE;
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
HRESULT hr;
if (!IntCheckDeletedFileHandle(hDeletedFile))
SetLastError(ERROR_INVALID_HANDLE);
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;
}
HRESULT WINAPI
GetDefaultRecycleBin(
IN LPCWSTR pszVolume OPTIONAL,
OUT IRecycleBin **pprb)
{
IUnknown *pUnk;
HRESULT hr;
if (!pprb)
return E_POINTER;
if (!pszVolume)
hr = RecycleBinGeneric_Constructor(&pUnk);
else
{
PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile;
if (DeletedFile->bin->Callbacks.RestoreFile)
ret = DeletedFile->bin->Callbacks.RestoreFile(DeletedFile->bin, DeletedFile->hDeletedFile);
else
SetLastError(ERROR_NOT_SUPPORTED);
}
/* FIXME: do a better validation! */
if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
return ret;
/* 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;
}

View file

@ -54,10 +54,10 @@ DeleteFileToRecycleBinW(
BOOL WINAPI
EmptyRecycleBinA(
IN CHAR driveLetter);
IN LPCSTR pszRoot);
BOOL WINAPI
EmptyRecycleBinW(
IN WCHAR driveLetter);
IN LPCWSTR pszRoot);
#ifdef UNICODE
#define EmptyRecycleBin EmptyRecycleBinW
#else
@ -102,6 +102,190 @@ BOOL WINAPI
RestoreFile(
IN HANDLE hDeletedFile);
/* COM interface */
typedef interface IRecycleBinFile IRecycleBinFile;
EXTERN_C const IID IID_IRecycleBinFile;
typedef struct IRecycleBinFileVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
IN IRecycleBinFile *This,
IN REFIID riid,
OUT void **ppvObject);
ULONG (STDMETHODCALLTYPE *AddRef)(
IN IRecycleBinFile *This);
ULONG (STDMETHODCALLTYPE *Release)(
IN IRecycleBinFile *This);
HRESULT (STDMETHODCALLTYPE *GetLastModificationTime)(
IN IRecycleBinFile *This,
OUT FILETIME *pLastModificationTime);
HRESULT (STDMETHODCALLTYPE *GetDeletionTime)(
IN IRecycleBinFile *This,
OUT FILETIME *pDeletionTime);
HRESULT (STDMETHODCALLTYPE *GetFileSize)(
IN IRecycleBinFile *This,
OUT ULARGE_INTEGER *pFileSize);
HRESULT (STDMETHODCALLTYPE *GetPhysicalFileSize)(
IN IRecycleBinFile *This,
OUT ULARGE_INTEGER *pPhysicalFileSize);
HRESULT (STDMETHODCALLTYPE *GetAttributes)(
IN IRecycleBinFile *This,
OUT DWORD *pAttributes);
HRESULT (STDMETHODCALLTYPE *GetFileName)(
IN IRecycleBinFile *This,
IN SIZE_T BufferSize,
IN OUT LPWSTR Buffer,
OUT SIZE_T *RequiredSize);
HRESULT (STDMETHODCALLTYPE *Delete)(
IN IRecycleBinFile *This);
HRESULT (STDMETHODCALLTYPE *Restore)(
IN IRecycleBinFile *This);
} IRecycleBinFileVtbl;
interface IRecycleBinFile
{
CONST_VTBL struct IRecycleBinFileVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define IRecycleBinFile_QueryInterface(This, riid, ppvObject) \
(This)->lpVtbl->QueryInterface(This, riid, ppvObject)
#define IRecycleBinFile_AddRef(This) \
(This)->lpVtbl->AddRef(This)
#define IRecycleBinFile_Release(This) \
(This)->lpVtbl->Release(This)
#define IRecycleBinFile_GetLastModificationTime(This, pLastModificationTime) \
(This)->lpVtbl->GetLastModificationTime(This, pLastModificationTime)
#define IRecycleBinFile_GetDeletionTime(This, pDeletionTime) \
(This)->lpVtbl->GetDeletionTime(This, pDeletionTime)
#define IRecycleBinFile_GetFileSize(This, pFileSize) \
(This)->lpVtbl->GetFileSize(This, pFileSize)
#define IRecycleBinFile_GetPhysicalFileSize(This, pPhysicalFileSize) \
(This)->lpVtbl->GetPhysicalFileSize(This, pPhysicalFileSize)
#define IRecycleBinFile_GetAttributes(This, pAttributes) \
(This)->lpVtbl->GetAttributes(This, pAttributes)
#define IRecycleBinFile_GetFileName(This, BufferSize, Buffer, RequiredSize) \
(This)->lpVtbl->GetFileName(This, BufferSize, Buffer, RequiredSize)
#define IRecycleBinFile_Delete(This) \
(This)->lpVtbl->Delete(This)
#define IRecycleBinFile_Restore(This) \
(This)->lpVtbl->Restore(This)
#endif
typedef interface IRecycleBinEnumList IRecycleBinEnumList;
EXTERN_C const IID IID_IRecycleBinEnumList;
typedef struct IRecycleBinEnumListVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
IN IRecycleBinEnumList *This,
IN REFIID riid,
OUT void **ppvObject);
ULONG (STDMETHODCALLTYPE *AddRef)(
IN IRecycleBinEnumList *This);
ULONG (STDMETHODCALLTYPE *Release)(
IN IRecycleBinEnumList *This);
HRESULT (STDMETHODCALLTYPE *Next)(
IN IRecycleBinEnumList *This,
IN DWORD celt,
IN OUT IRecycleBinFile **rgelt,
OUT DWORD *pceltFetched);
HRESULT (STDMETHODCALLTYPE *Skip)(
IN IRecycleBinEnumList *This,
IN DWORD celt);
HRESULT (STDMETHODCALLTYPE *Reset)(
IN IRecycleBinEnumList *This);
} IRecycleBinEnumListVtbl;
interface IRecycleBinEnumList
{
CONST_VTBL struct IRecycleBinEnumListVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define IRecycleBinEnumList_QueryInterface(This, riid, ppvObject) \
(This)->lpVtbl->QueryInterface(This, riid, ppvObject)
#define IRecycleBinEnumList_AddRef(This) \
(This)->lpVtbl->AddRef(This)
#define IRecycleBinEnumList_Release(This) \
(This)->lpVtbl->Release(This)
#define IRecycleBinEnumList_Next(This, celt, rgelt, pceltFetched) \
(This)->lpVtbl->Next(This, celt, rgelt, pceltFetched)
#define IRecycleBinEnumList_Skip(This, celt) \
(This)->lpVtbl->Skip(This, celt)
#define IRecycleBinEnumList_Reset(This) \
(This)->lpVtbl->Reset(This)
#endif
typedef interface IRecycleBin IRecycleBin;
EXTERN_C const IID IID_IRecycleBin;
typedef struct IRecycleBinVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
IN IRecycleBin *This,
IN REFIID riid,
OUT void **ppvObject);
ULONG (STDMETHODCALLTYPE *AddRef)(
IN IRecycleBin *This);
ULONG (STDMETHODCALLTYPE *Release)(
IN IRecycleBin *This);
HRESULT (STDMETHODCALLTYPE *DeleteFile)(
IN IRecycleBin *This,
IN LPCWSTR szFileName);
HRESULT (STDMETHODCALLTYPE *EmptyRecycleBin)(
IN IRecycleBin *This);
HRESULT (STDMETHODCALLTYPE *EnumObjects)(
IN IRecycleBin *This,
OUT IRecycleBinEnumList **ppEnumList);
} IRecycleBinVtbl;
interface IRecycleBin
{
CONST_VTBL struct IRecycleBinVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define IRecycleBin_QueryInterface(This, riid, ppvObject) \
(This)->lpVtbl->QueryInterface(This, riid, ppvObject)
#define IRecycleBin_AddRef(This) \
(This)->lpVtbl->AddRef(This)
#define IRecycleBin_Release(This) \
(This)->lpVtbl->Release(This)
#define IRecycleBin_DeleteFile(This, szFileName) \
(This)->lpVtbl->DeleteFile(This, szFileName)
#define IRecycleBin_EmptyRecycleBin(This) \
(This)->lpVtbl->EmptyRecycleBin(This)
#define IRecycleBin_EnumObjects(This, ppEnumList) \
(This)->lpVtbl->EnumObjects(This, ppEnumList)
#endif
HRESULT WINAPI
GetDefaultRecycleBin(
IN LPCWSTR pszVolume OPTIONAL,
OUT IRecycleBin **pprb);
#ifdef __cplusplus
}
#endif

View file

@ -1,9 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
<module name="recyclebin" type="staticlibrary">
<define name="__USE_W32API" />
<file>openclose.c</file>
<file>guid.c</file>
<file>recyclebin.c</file>
<file>recyclebin_generic.c</file>
<file>recyclebin_generic_enumerator.c</file>
<file>recyclebin_v5.c</file>
<file>refcount.c</file>
<file>recyclebin_v5_enumerator.c</file>
</module>

View file

@ -0,0 +1,200 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/recyclebin_generic.c
* PURPOSE: Deals with a system-wide recycle bin
* PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
*/
#define COBJMACROS
#include "recyclebin_private.h"
#include <stdio.h>
struct RecycleBinGeneric
{
ULONG ref;
IRecycleBin recycleBinImpl;
};
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_QueryInterface(
IRecycleBin *This,
REFIID riid,
void **ppvObject)
{
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, &IID_IUnknown))
*ppvObject = &s->recycleBinImpl;
else if (IsEqualIID(riid, &IID_IRecycleBin))
*ppvObject = &s->recycleBinImpl;
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef(This);
return S_OK;
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_AddRef(
IRecycleBin *This)
{
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
return refCount;
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_Release(
IRecycleBin *This)
{
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
ULONG refCount;
if (!This)
return E_POINTER;
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
CoTaskMemFree(s);
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_DeleteFile(
IN IRecycleBin *This,
IN LPCWSTR szFileName)
{
IRecycleBin *prb;
LPWSTR szFullName = NULL;
DWORD dwBufferLength = 0;
DWORD len;
WCHAR szVolume[MAX_PATH];
HRESULT hr;
/* Get full file name */
while (TRUE)
{
len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, NULL);
if (len == 0)
{
if (szFullName)
CoTaskMemFree(szFullName);
return HRESULT_FROM_WIN32(GetLastError());
}
else if (len < dwBufferLength)
break;
if (szFullName)
CoTaskMemFree(szFullName);
dwBufferLength = len;
szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
if (!szFullName)
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
/* Get associated volume path */
#ifndef __REACTOS__
if (!GetVolumePathNameW(szFullName, szVolume, MAX_PATH))
{
CoTaskMemFree(szFullName);
return HRESULT_FROM_WIN32(GetLastError());
}
#else
swprintf(szVolume, L"%c:\\", szFullName[0]);
#endif
/* Skip namespace (if any) */
if (szVolume[0] == '\\'
&& szVolume[1] == '\\'
&& (szVolume[2] == '.' || szVolume[2] == '?')
&& szVolume[3] == '\\')
{
MoveMemory(szVolume, &szVolume[4], (MAX_PATH - 4) * sizeof(WCHAR));
}
hr = GetDefaultRecycleBin(szVolume, &prb);
if (!SUCCEEDED(hr))
{
CoTaskMemFree(szFullName);
return hr;
}
hr = IRecycleBin_DeleteFile(prb, szFullName);
CoTaskMemFree(szFullName);
IRecycleBin_Release(prb);
return hr;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin(
IN IRecycleBin *This)
{
WCHAR szVolumeName[MAX_PATH];
DWORD dwLogicalDrives, i;
IRecycleBin *prb;
HRESULT hr;
dwLogicalDrives = GetLogicalDrives();
if (dwLogicalDrives == 0)
return HRESULT_FROM_WIN32(GetLastError());
for (i = 0; i < 26; i++)
{
if (!(dwLogicalDrives & (1 << i)))
continue;
swprintf(szVolumeName, L"%c:\\", 'A' + i);
if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
continue;
hr = GetDefaultRecycleBin(szVolumeName, &prb);
if (!SUCCEEDED(hr))
return hr;
hr = IRecycleBin_EmptyRecycleBin(prb);
IRecycleBin_Release(prb);
}
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_EnumObjects(
IN IRecycleBin *This,
OUT IRecycleBinEnumList **ppEnumList)
{
return RecycleBinGeneric_Enumerator_Constructor(ppEnumList);
}
CONST_VTBL struct IRecycleBinVtbl RecycleBinGenericVtbl =
{
RecycleBinGenericVtbl_RecycleBin_QueryInterface,
RecycleBinGenericVtbl_RecycleBin_AddRef,
RecycleBinGenericVtbl_RecycleBin_Release,
RecycleBinGenericVtbl_RecycleBin_DeleteFile,
RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin,
RecycleBinGenericVtbl_RecycleBin_EnumObjects,
};
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown)
{
/* This RecycleBin implementation was introduced to be able to manage all
* drives at once, and instanciate the 'real' implementations when needed */
struct RecycleBinGeneric *s;
s = CoTaskMemAlloc(sizeof(struct RecycleBinGeneric));
if (!s)
return E_OUTOFMEMORY;
s->ref = 1;
s->recycleBinImpl.lpVtbl = &RecycleBinGenericVtbl;
*ppUnknown = (IUnknown *)&s->recycleBinImpl;
return S_OK;
}

View file

@ -0,0 +1,221 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/recyclebin_generic_enumerator.c
* PURPOSE: Enumerates contents of all recycle bins
* PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
*/
#define COBJMACROS
#include "recyclebin.h"
#include <stdio.h>
struct RecycleBinGenericEnum
{
ULONG ref;
IRecycleBinEnumList recycleBinEnumImpl;
IRecycleBinEnumList *current;
DWORD dwLogicalDrives;
SIZE_T skip;
};
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_QueryInterface(
IN IRecycleBinEnumList *This,
IN REFIID riid,
OUT void **ppvObject)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, &IID_IUnknown))
*ppvObject = &s->recycleBinEnumImpl;
else if (IsEqualIID(riid, &IID_IRecycleBinEnumList))
*ppvObject = &s->recycleBinEnumImpl;
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef(This);
return S_OK;
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_AddRef(
IN IRecycleBinEnumList *This)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
return refCount;
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Release(
IN IRecycleBinEnumList *This)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
ULONG refCount;
if (!This)
return E_POINTER;
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
{
if (s->current)
IRecycleBinEnumList_Release(s->current);
CoTaskMemFree(s);
}
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Next(
IN IRecycleBinEnumList *This,
IN DWORD celt,
IN OUT IRecycleBinFile **rgelt,
OUT DWORD *pceltFetched)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
IRecycleBin *prb;
DWORD i;
DWORD fetched = 0, newFetched;
HRESULT hr;
if (!rgelt)
return E_POINTER;
if (!pceltFetched && celt > 1)
return E_INVALIDARG;
while (TRUE)
{
/* Get enumerator implementation */
if (!s->current && s->dwLogicalDrives)
{
for (i = 0; i < 26; i++)
if (s->dwLogicalDrives & (1 << i))
{
WCHAR szVolumeName[4];
szVolumeName[0] = (WCHAR)('A' + i);
szVolumeName[1] = ':';
szVolumeName[2] = '\\';
szVolumeName[3] = UNICODE_NULL;
if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
{
s->dwLogicalDrives &= ~(1 << i);
continue;
}
hr = GetDefaultRecycleBin(szVolumeName, &prb);
if (!SUCCEEDED(hr))
return hr;
hr = IRecycleBin_EnumObjects(prb, &s->current);
IRecycleBin_Release(prb);
if (!SUCCEEDED(hr))
return hr;
s->dwLogicalDrives &= ~(1 << i);
break;
}
}
if (!s->current)
{
/* Nothing more to enumerate */
if (pceltFetched)
*pceltFetched = fetched;
return S_FALSE;
}
/* Skip some elements */
while (s->skip > 0)
{
IRecycleBinFile *rbf;
hr = IRecycleBinEnumList_Next(s->current, 1, &rbf, NULL);
if (hr == S_OK)
hr = IRecycleBinFile_Release(rbf);
else if (hr == S_FALSE)
break;
else if (!SUCCEEDED(hr))
return hr;
}
if (s->skip > 0)
continue;
/* Fill area */
hr = IRecycleBinEnumList_Next(s->current, celt - fetched, &rgelt[fetched], &newFetched);
if (SUCCEEDED(hr))
fetched += newFetched;
if (hr == S_FALSE || newFetched == 0)
{
hr = IRecycleBinEnumList_Release(s->current);
s->current = NULL;
}
else if (!SUCCEEDED(hr))
return hr;
if (fetched == celt)
{
if (pceltFetched)
*pceltFetched = fetched;
return S_OK;
}
}
/* Never go here */
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Skip(
IN IRecycleBinEnumList *This,
IN DWORD celt)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
s->skip += celt;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Reset(
IN IRecycleBinEnumList *This)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
if (s->current)
{
IRecycleBinEnumList_Release(s->current);
s->current = NULL;
s->skip = 0;
}
s->dwLogicalDrives = GetLogicalDrives();
return S_OK;
}
CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBinGenericEnumVtbl =
{
RecycleBinGenericEnum_RecycleBinEnumList_QueryInterface,
RecycleBinGenericEnum_RecycleBinEnumList_AddRef,
RecycleBinGenericEnum_RecycleBinEnumList_Release,
RecycleBinGenericEnum_RecycleBinEnumList_Next,
RecycleBinGenericEnum_RecycleBinEnumList_Skip,
RecycleBinGenericEnum_RecycleBinEnumList_Reset,
};
HRESULT
RecycleBinGeneric_Enumerator_Constructor(
OUT IRecycleBinEnumList **pprbel)
{
struct RecycleBinGenericEnum *s;
s = CoTaskMemAlloc(sizeof(struct RecycleBinGenericEnum));
if (!s)
return E_OUTOFMEMORY;
ZeroMemory(s, sizeof(struct RecycleBinGenericEnum));
s->ref = 1;
s->recycleBinEnumImpl.lpVtbl = &RecycleBinGenericEnumVtbl;
*pprbel = &s->recycleBinEnumImpl;
return IRecycleBinEnumList_Reset(*pprbel);
}

View file

@ -17,55 +17,6 @@
#define RemoveEntryList(Entry) { PLIST_ENTRY _EX_Blink, _EX_Flink; _EX_Flink = (Entry)->Flink; _EX_Blink = (Entry)->Blink; _EX_Blink->Flink = _EX_Flink; _EX_Flink->Blink = _EX_Blink; }
/* Typedefs */
struct _RECYCLE_BIN;
typedef struct _RECYCLE_BIN *PRECYCLE_BIN;
struct _REFCOUNT_DATA;
typedef struct _REFCOUNT_DATA *PREFCOUNT_DATA;
typedef BOOL (*PINT_ENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context OPTIONAL, IN HANDLE hDeletedFile);
typedef BOOL (*PDESTROY_DATA) (IN PREFCOUNT_DATA pData);
typedef BOOL (*PCLOSE_HANDLE) (IN HANDLE hHandle);
typedef BOOL (*PDELETE_FILE) (IN PRECYCLE_BIN bin, IN LPCWSTR FullPath, IN LPCWSTR FileName);
typedef BOOL (*PEMPTY_RECYCLEBIN)(IN PRECYCLE_BIN* bin);
typedef BOOL (*PENUMERATE_FILES) (IN PRECYCLE_BIN bin, IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, IN PVOID Context OPTIONAL);
typedef BOOL (*PGET_DETAILS) (IN PRECYCLE_BIN bin, IN HANDLE hDeletedFile, IN DWORD BufferSize, IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL, OUT LPDWORD RequiredSize OPTIONAL);
typedef BOOL (*PRESTORE_FILE) (IN PRECYCLE_BIN bin, IN HANDLE hDeletedFile);
typedef struct _RECYCLEBIN_CALLBACKS
{
PCLOSE_HANDLE CloseHandle;
PDELETE_FILE DeleteFile;
PEMPTY_RECYCLEBIN EmptyRecycleBin;
PENUMERATE_FILES EnumerateFiles;
PGET_DETAILS GetDetails;
PRESTORE_FILE RestoreFile;
} RECYCLEBIN_CALLBACKS, *PRECYCLEBIN_CALLBACKS;
typedef struct _REFCOUNT_DATA
{
DWORD ReferenceCount;
PDESTROY_DATA Close;
} REFCOUNT_DATA;
typedef struct _RECYCLE_BIN
{
DWORD magic; /* RECYCLEBIN_MAGIC */
LIST_ENTRY ListEntry;
REFCOUNT_DATA refCount;
HANDLE hInfo;
RECYCLEBIN_CALLBACKS Callbacks;
LPWSTR InfoFile;
WCHAR Folder[ANY_SIZE]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */
} RECYCLE_BIN;
typedef struct _DELETED_FILE_HANDLE
{
DWORD magic; /* DELETEDFILE_MAGIC */
REFCOUNT_DATA refCount;
PRECYCLE_BIN bin;
HANDLE hDeletedFile; /* specific to recycle bin format */
} DELETED_FILE_HANDLE, *PDELETED_FILE_HANDLE;
/* Structures on disk */
@ -84,33 +35,14 @@ typedef struct _INFO2_HEADER
/* Prototypes */
/* openclose.c */
/* recyclebin_generic.c */
BOOL
IntCheckDeletedFileHandle(
IN HANDLE hDeletedFile);
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown);
PRECYCLE_BIN
IntReferenceRecycleBin(
IN WCHAR driveLetter);
/* recyclebin_generic_enumerator.c */
HRESULT RecycleBinGeneric_Enumerator_Constructor(OUT IRecycleBinEnumList **pprbel);
/* recyclebin_v5.c */
VOID
InitializeCallbacks5(
IN OUT PRECYCLEBIN_CALLBACKS Callbacks);
/* refcount.c */
BOOL
InitializeHandle(
IN PREFCOUNT_DATA pData,
IN PDESTROY_DATA pFnClose OPTIONAL);
BOOL
ReferenceHandle(
IN PREFCOUNT_DATA pData);
BOOL
DereferenceHandle(
IN PREFCOUNT_DATA pData);
HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown);

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,10 @@
#include "recyclebin_private.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <pshpack1.h>
/* MS Windows 2000/XP/2003 */
@ -20,57 +24,86 @@ typedef struct _DELETED_FILE_RECORD
#include <poppack.h>
static BOOL
CloseHandle5(
IN HANDLE hDeletedFile);
/* COM interface */
static BOOL
DeleteFile5(
IN PRECYCLE_BIN bin,
IN LPCWSTR FullPath,
IN LPCWSTR FileName);
typedef interface IRecycleBin5 IRecycleBin5;
EXTERN_C const IID IID_IRecycleBin5;
static BOOL
EmptyRecycleBin5(
IN PRECYCLE_BIN* bin);
typedef struct IRecycleBin5Vtbl
{
/* IRecycleBin interface */
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
IN IRecycleBin5 *This,
IN REFIID riid,
OUT void **ppvObject);
static BOOL
EnumerateFiles5(
IN PRECYCLE_BIN bin,
IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
IN PVOID Context OPTIONAL);
ULONG (STDMETHODCALLTYPE *AddRef)(
IN IRecycleBin5 *This);
static BOOL
GetDetails5(
IN PRECYCLE_BIN bin,
IN HANDLE hDeletedFile,
IN DWORD BufferSize,
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
OUT LPDWORD RequiredSize OPTIONAL);
ULONG (STDMETHODCALLTYPE *Release)(
IN IRecycleBin5 *This);
static BOOL
RestoreFile5(
IN PRECYCLE_BIN bin,
IN HANDLE hDeletedFile);
HRESULT (STDMETHODCALLTYPE *DeleteFile)(
IN IRecycleBin5 *This,
IN LPCWSTR szFileName);
static BOOL
IntDeleteRecursive(
IN LPCWSTR FullName);
HRESULT (STDMETHODCALLTYPE *EmptyRecycleBin)(
IN IRecycleBin5 *This);
static BOOL
IntEmptyRecycleBinCallback(
IN PVOID Context,
IN HANDLE hDeletedFile);
HRESULT (STDMETHODCALLTYPE *EnumObjects)(
IN IRecycleBin5 *This,
OUT IRecycleBinEnumList **ppEnumList);
static BOOL
IntGetFullName(
IN PRECYCLE_BIN bin,
IN PDELETED_FILE_RECORD pDeletedFile,
OUT LPWSTR* pFullName);
/* IRecycleBin5 interface */
HRESULT (STDMETHODCALLTYPE *Delete)(
IN IRecycleBin5 *This,
IN LPCWSTR pDeletedFileName,
IN DELETED_FILE_RECORD *pDeletedFile);
static BOOL
IntSearchRecord(
IN PRECYCLE_BIN bin,
IN HANDLE hDeletedFile,
OUT PDELETED_FILE_RECORD DeletedFile,
OUT PLARGE_INTEGER Position OPTIONAL);
HRESULT (STDMETHODCALLTYPE *Restore)(
IN IRecycleBin5 *This,
IN LPCWSTR pDeletedFileName,
IN DELETED_FILE_RECORD *pDeletedFile);
HRESULT (STDMETHODCALLTYPE *OnClosing)(
IN IRecycleBin5 *This,
IN IRecycleBinEnumList *prb5el);
} IRecycleBin5Vtbl;
interface IRecycleBin5
{
CONST_VTBL struct IRecycleBin5Vtbl *lpVtbl;
};
#ifdef COBJMACROS
#define IRecycleBin5_QueryInterface(This, riid, ppvObject) \
(This)->lpVtbl->QueryInterface(This, riid, ppvObject)
#define IRecycleBin5_AddRef(This) \
(This)->lpVtbl->AddRef(This)
#define IRecycleBin5_Release(This) \
(This)->lpVtbl->Release(This)
#define IRecycleBin5_DeleteFile(This, szFileName) \
(This)->lpVtbl->DeleteFile(This, szFileName)
#define IRecycleBin5_EmptyRecycleBin(This) \
(This)->lpVtbl->EmptyRecycleBin(This)
#define IRecycleBin5_EnumObjects(This, ppEnumList) \
(This)->lpVtbl->EnumObjects(This, ppEnumList)
#define IRecycleBin5_Delete(This, pDeletedFileName, pDeletedFile) \
(This)->lpVtbl->Delete(This, pDeletedFileName, pDeletedFile)
#define IRecycleBin5_Restore(This, pDeletedFileName, pDeletedFile) \
(This)->lpVtbl->Restore(This, pDeletedFileName, pDeletedFile)
#define IRecycleBin5_OnClosing(This, prb5el) \
(This)->lpVtbl->OnClosing(This, prb5el)
#endif
HRESULT
RecycleBin5_Enumerator_Constructor(
IN IRecycleBin5 *prb,
IN HANDLE hInfo,
IN HANDLE hInfoMapped,
IN LPCWSTR szPrefix,
OUT IUnknown **ppUnknown);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,450 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/recyclebin_v5_enumerator.c
* PURPOSE: Enumerates contents of a MS Windows 2000/XP/2003 recyclebin
* PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
#define COBJMACROS
#include "recyclebin_v5.h"
struct RecycleBin5File
{
ULONG ref;
IRecycleBin5 *recycleBin;
DELETED_FILE_RECORD deletedFile;
IRecycleBinFile recycleBinFileImpl;
WCHAR FullName[ANY_SIZE];
};
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_QueryInterface(
IN IRecycleBinFile *This,
IN REFIID riid,
OUT void **ppvObject)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, &IID_IUnknown))
*ppvObject = &s->recycleBinFileImpl;
else if (IsEqualIID(riid, &IID_IRecycleBinFile))
*ppvObject = &s->recycleBinFileImpl;
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef(This);
return S_OK;
}
static ULONG STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_AddRef(
IN IRecycleBinFile *This)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
return refCount;
}
static ULONG STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_Release(
IN IRecycleBinFile *This)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
ULONG refCount;
if (!This)
return E_POINTER;
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
{
IRecycleBin5_Release(s->recycleBin);
CoTaskMemFree(s);
}
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetLastModificationTime(
IN IRecycleBinFile *This,
OUT FILETIME *pLastModificationTime)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
HRESULT hr;
DWORD dwAttributes;
HANDLE hFile;
dwAttributes = GetFileAttributesW(s->FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
else
hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
if (GetFileTime(hFile, NULL, NULL, pLastModificationTime))
hr = S_OK;
else
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hFile);
return hr;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetDeletionTime(
IN IRecycleBinFile *This,
OUT FILETIME *pDeletionTime)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
*pDeletionTime = s->deletedFile.DeletionTime;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetFileSize(
IN IRecycleBinFile *This,
OUT ULARGE_INTEGER *pFileSize)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
HRESULT hr;
DWORD dwAttributes;
HANDLE hFile;
dwAttributes = GetFileAttributesW(s->FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
pFileSize->QuadPart = 0;
return S_OK;
}
hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
pFileSize->u.LowPart = GetFileSize(hFile, &pFileSize->u.HighPart);
if (pFileSize->u.LowPart != INVALID_FILE_SIZE)
hr = S_OK;
else
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hFile);
return hr;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetPhysicalFileSize(
IN IRecycleBinFile *This,
OUT ULARGE_INTEGER *pPhysicalFileSize)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
pPhysicalFileSize->u.HighPart = 0;
pPhysicalFileSize->u.LowPart = s->deletedFile.dwPhysicalFileSize;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetAttributes(
IN IRecycleBinFile *This,
OUT DWORD *pAttributes)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
DWORD dwAttributes;
dwAttributes = GetFileAttributesW(s->FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
*pAttributes = dwAttributes;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetFileName(
IN IRecycleBinFile *This,
IN DWORD BufferSize,
IN OUT LPWSTR Buffer,
OUT DWORD *RequiredSize)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
DWORD dwRequired;
dwRequired = (DWORD)(wcslen(s->deletedFile.FileNameW) + 1) * sizeof(WCHAR);
if (RequiredSize)
*RequiredSize = dwRequired;
if (BufferSize == 0 && !Buffer)
return S_OK;
if (BufferSize < dwRequired)
return E_OUTOFMEMORY;
CopyMemory(Buffer, s->deletedFile.FileNameW, dwRequired);
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_Delete(
IN IRecycleBinFile *This)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
return IRecycleBin5_Delete(s->recycleBin, s->FullName, &s->deletedFile);
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_Restore(
IN IRecycleBinFile *This)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
return IRecycleBin5_Restore(s->recycleBin, s->FullName, &s->deletedFile);
}
CONST_VTBL struct IRecycleBinFileVtbl RecycleBin5FileVtbl =
{
RecycleBin5File_RecycleBinFile_QueryInterface,
RecycleBin5File_RecycleBinFile_AddRef,
RecycleBin5File_RecycleBinFile_Release,
RecycleBin5File_RecycleBinFile_GetLastModificationTime,
RecycleBin5File_RecycleBinFile_GetDeletionTime,
RecycleBin5File_RecycleBinFile_GetFileSize,
RecycleBin5File_RecycleBinFile_GetPhysicalFileSize,
RecycleBin5File_RecycleBinFile_GetAttributes,
RecycleBin5File_RecycleBinFile_GetFileName,
RecycleBin5File_RecycleBinFile_Delete,
RecycleBin5File_RecycleBinFile_Restore,
};
static HRESULT
RecycleBin5_File_Constructor(
IN IRecycleBin5 *prb,
IN LPCWSTR Folder,
IN PDELETED_FILE_RECORD pDeletedFile,
OUT IRecycleBinFile **ppFile)
{
struct RecycleBin5File *s = NULL;
LPCWSTR Extension;
SIZE_T Needed;
if (!ppFile)
return E_POINTER;
Extension = wcsrchr(pDeletedFile->FileNameW, '.');
if (Extension < wcsrchr(pDeletedFile->FileNameW, '\\'))
Extension = NULL;
Needed = wcslen(Folder) + 13;
if (Extension)
Needed += wcslen(Extension);
Needed *= sizeof(WCHAR);
s = CoTaskMemAlloc(sizeof(struct RecycleBin5File) + Needed);
if (!s)
return E_OUTOFMEMORY;
ZeroMemory(s, sizeof(struct RecycleBin5File) + Needed);
s->recycleBinFileImpl.lpVtbl = &RecycleBin5FileVtbl;
s->ref = 1;
s->deletedFile = *pDeletedFile;
s->recycleBin = prb;
IRecycleBin5_AddRef(s->recycleBin);
*ppFile = &s->recycleBinFileImpl;
wsprintfW(s->FullName, L"%s\\D%c%lu%s", Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension);
return S_OK;
}
struct RecycleBin5Enum
{
ULONG ref;
IRecycleBin5 *recycleBin;
HANDLE hInfo;
INFO2_HEADER *pInfo;
DWORD dwCurrent;
IRecycleBinEnumList recycleBinEnumImpl;
WCHAR szPrefix[ANY_SIZE];
};
static HRESULT STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_QueryInterface(
IN IRecycleBinEnumList *This,
IN REFIID riid,
OUT void **ppvObject)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, &IID_IUnknown))
*ppvObject = &s->recycleBinEnumImpl;
else if (IsEqualIID(riid, &IID_IRecycleBinEnumList))
*ppvObject = &s->recycleBinEnumImpl;
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef(This);
return S_OK;
}
static ULONG STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_AddRef(
IN IRecycleBinEnumList *This)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
return refCount;
}
static ULONG STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Release(
IN IRecycleBinEnumList *This)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
ULONG refCount;
if (!This)
return E_POINTER;
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
{
IRecycleBin5_OnClosing(s->recycleBin, This);
UnmapViewOfFile(s->pInfo);
IRecycleBin5_Release(s->recycleBin);
CoTaskMemFree(s);
}
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Next(
IRecycleBinEnumList *This,
IN DWORD celt,
IN OUT IRecycleBinFile **rgelt,
OUT DWORD *pceltFetched)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
ULARGE_INTEGER FileSize;
INFO2_HEADER *pHeader = s->pInfo;
DELETED_FILE_RECORD *pDeletedFile;
DWORD fetched = 0, i;
DWORD dwEntries;
HRESULT hr;
if (!rgelt)
return E_POINTER;
if (!pceltFetched && celt > 1)
return E_INVALIDARG;
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
if (FileSize.u.LowPart == 0)
return HRESULT_FROM_WIN32(GetLastError());
dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
i = s->dwCurrent;
pDeletedFile = (DELETED_FILE_RECORD *)(pHeader + 1) + i;
for (; i < dwEntries && fetched < celt; i++)
{
hr = RecycleBin5_File_Constructor(s->recycleBin, s->szPrefix, pDeletedFile, &rgelt[fetched]);
if (!SUCCEEDED(hr))
{
for (i = 0; i < fetched; i++)
IRecycleBinFile_Release(rgelt[i]);
return hr;
}
pDeletedFile++;
fetched++;
}
s->dwCurrent = i;
if (pceltFetched)
*pceltFetched = fetched;
if (fetched == celt)
return S_OK;
else
return S_FALSE;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Skip(
IN IRecycleBinEnumList *This,
IN DWORD celt)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
s->dwCurrent += celt;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Reset(
IN IRecycleBinEnumList *This)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
s->dwCurrent = 0;
return S_OK;
}
CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBin5EnumVtbl =
{
RecycleBin5Enum_RecycleBinEnumList_QueryInterface,
RecycleBin5Enum_RecycleBinEnumList_AddRef,
RecycleBin5Enum_RecycleBinEnumList_Release,
RecycleBin5Enum_RecycleBinEnumList_Next,
RecycleBin5Enum_RecycleBinEnumList_Skip,
RecycleBin5Enum_RecycleBinEnumList_Reset,
};
HRESULT
RecycleBin5_Enumerator_Constructor(
IN IRecycleBin5 *prb,
IN HANDLE hInfo,
IN HANDLE hInfoMapped,
IN LPCWSTR szPrefix,
OUT IUnknown **ppUnknown)
{
struct RecycleBin5Enum *s = NULL;
SIZE_T Needed;
if (!ppUnknown)
return E_POINTER;
Needed = (wcslen(szPrefix) + 1) * sizeof(WCHAR);
s = CoTaskMemAlloc(sizeof(struct RecycleBin5Enum) + Needed);
if (!s)
return E_OUTOFMEMORY;
ZeroMemory(s, sizeof(struct RecycleBin5Enum) + Needed);
s->recycleBinEnumImpl.lpVtbl = &RecycleBin5EnumVtbl;
s->ref = 1;
s->recycleBin = prb;
wcscpy(s->szPrefix, szPrefix);
s->hInfo = hInfo;
s->pInfo = MapViewOfFile(hInfoMapped, FILE_MAP_READ, 0, 0, 0);
if (!s->pInfo)
{
CoTaskMemFree(s);
return HRESULT_FROM_WIN32(GetLastError());
}
if (s->pInfo->dwVersion != 5 || s->pInfo->dwRecordSize != sizeof(DELETED_FILE_RECORD))
{
UnmapViewOfFile(s->pInfo);
CoTaskMemFree(s);
return E_FAIL;
}
IRecycleBin5_AddRef(s->recycleBin);
*ppUnknown = (IUnknown *)&s->recycleBinEnumImpl;
return S_OK;
}

View file

@ -1,42 +0,0 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/openclose.c
* PURPOSE: Do reference counting on objects
* PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "recyclebin_private.h"
BOOL
InitializeHandle(
IN PREFCOUNT_DATA pData,
IN PDESTROY_DATA pFnClose OPTIONAL)
{
pData->ReferenceCount = 1;
pData->Close = pFnClose;
return TRUE;
}
BOOL
ReferenceHandle(
IN PREFCOUNT_DATA pData)
{
pData->ReferenceCount++;
return TRUE;
}
BOOL
DereferenceHandle(
IN PREFCOUNT_DATA pData)
{
pData->ReferenceCount--;
if (pData->ReferenceCount == 0)
{
if (pData->Close)
return pData->Close(pData);
else
return TRUE;
}
return TRUE;
}