mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 17:05:45 +00:00
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:
parent
61edd081e9
commit
25e2d0f59e
13 changed files with 1979 additions and 1124 deletions
14
reactos/lib/recyclebin/guid.c
Normal file
14
reactos/lib/recyclebin/guid.c
Normal 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);
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
200
reactos/lib/recyclebin/recyclebin_generic.c
Normal file
200
reactos/lib/recyclebin/recyclebin_generic.c
Normal 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;
|
||||
}
|
221
reactos/lib/recyclebin/recyclebin_generic_enumerator.c
Normal file
221
reactos/lib/recyclebin/recyclebin_generic_enumerator.c
Normal 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);
|
||||
}
|
|
@ -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
|
@ -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
|
||||
|
|
450
reactos/lib/recyclebin/recyclebin_v5_enumerator.c
Normal file
450
reactos/lib/recyclebin/recyclebin_v5_enumerator.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue