mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 08:53:02 +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.
|
This library deals with Recycle bin.
|
||||||
It is aimed to be compatible with Windows 2000/XP/2003 (at least) on FAT or NTFS volumes.
|
It is aimed to be compatible with Windows 2000/XP/2003 (at least) on FAT or NTFS volumes.
|
||||||
|
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
- Empty a recycle bin containing directories (v5)
|
- Empty a recycle bin containing directories (v5)
|
||||||
- Set security on recycle bin folder
|
- Set security on recycle bin folder
|
||||||
|
@ -9,7 +8,6 @@ TODO
|
||||||
- Make the library thread-safe
|
- Make the library thread-safe
|
||||||
|
|
||||||
3 levels
|
3 levels
|
||||||
- 1: recyclebin.c: Public interface
|
- 1: recyclebin.c : Public C interface
|
||||||
- 2a: openclose.c: Open/close recycle bins
|
- 2: recyclebin_generic.c : 'System-wide' recycle bin, which knows no implementation detail
|
||||||
- 2b: refcount.c: Do reference counting on objects
|
- 3: recyclebin_v5.c : Deals with recycle bins of Windows 2000/XP/2003
|
||||||
- 3: recyclebin_v5.c: Deals with recycle bins of Windows 2000/XP/2003
|
|
|
@ -1,35 +1,30 @@
|
||||||
/*
|
/*
|
||||||
* PROJECT: Recycle bin management
|
* PROJECT: Recycle bin management
|
||||||
* LICENSE: GPL v2 - See COPYING in the top level directory
|
* LICENSE: GPL v2 - See COPYING in the top level directory
|
||||||
* FILE: lib/recyclebin/openclose.c
|
* FILE: lib/recyclebin/recyclebin.c
|
||||||
* PURPOSE: Public interface
|
* 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"
|
#include "recyclebin_private.h"
|
||||||
|
#include <stdio.h>
|
||||||
typedef struct _ENUMERATE_RECYCLE_BIN_CONTEXT
|
|
||||||
{
|
|
||||||
PRECYCLE_BIN bin;
|
|
||||||
PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback;
|
|
||||||
PVOID Context;
|
|
||||||
} ENUMERATE_RECYCLE_BIN_CONTEXT, *PENUMERATE_RECYCLE_BIN_CONTEXT;
|
|
||||||
|
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
CloseRecycleBinHandle(
|
CloseRecycleBinHandle(
|
||||||
IN HANDLE hDeletedFile)
|
IN HANDLE hDeletedFile)
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
if (!IntCheckDeletedFileHandle(hDeletedFile))
|
hr = IRecycleBinFile_Release(rbf);
|
||||||
SetLastError(ERROR_INVALID_HANDLE);
|
if (SUCCEEDED(hr))
|
||||||
|
return TRUE;
|
||||||
|
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||||
|
SetLastError(HRESULT_CODE(hr));
|
||||||
else
|
else
|
||||||
{
|
SetLastError(ERROR_GEN_FAILURE);
|
||||||
PDELETED_FILE_HANDLE file = (PDELETED_FILE_HANDLE)hDeletedFile;
|
return FALSE;
|
||||||
ret = DereferenceHandle(&file->refCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
|
@ -70,89 +65,78 @@ BOOL WINAPI
|
||||||
DeleteFileToRecycleBinW(
|
DeleteFileToRecycleBinW(
|
||||||
IN LPCWSTR FileName)
|
IN LPCWSTR FileName)
|
||||||
{
|
{
|
||||||
LPWSTR FullFileName = NULL;
|
IRecycleBin *prb;
|
||||||
DWORD dwBufferLength = 0;
|
HRESULT hr;
|
||||||
LPWSTR lpFilePart;
|
|
||||||
DWORD len;
|
|
||||||
PRECYCLE_BIN bin = NULL;
|
|
||||||
BOOL ret = FALSE;
|
|
||||||
|
|
||||||
/* Check parameters */
|
hr = GetDefaultRecycleBin(NULL, &prb);
|
||||||
if (FileName == NULL)
|
if (!SUCCEEDED(hr))
|
||||||
{
|
|
||||||
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)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (bin->Callbacks.DeleteFile)
|
hr = IRecycleBin_DeleteFile(prb, FileName);
|
||||||
ret = bin->Callbacks.DeleteFile(bin, FullFileName, lpFilePart);
|
IRecycleBin_Release(prb);
|
||||||
else
|
|
||||||
SetLastError(ERROR_NOT_SUPPORTED);
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
HeapFree(GetProcessHeap(), 0, FullFileName);
|
if (SUCCEEDED(hr))
|
||||||
if (bin)
|
return TRUE;
|
||||||
DereferenceHandle(&bin->refCount);
|
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||||
return ret;
|
SetLastError(HRESULT_CODE(hr));
|
||||||
|
else
|
||||||
|
SetLastError(ERROR_GEN_FAILURE);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
EmptyRecycleBinA(
|
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
|
BOOL WINAPI
|
||||||
EmptyRecycleBinW(
|
EmptyRecycleBinW(
|
||||||
IN WCHAR driveLetter)
|
IN LPCWSTR pszRoot OPTIONAL)
|
||||||
{
|
{
|
||||||
PRECYCLE_BIN bin = NULL;
|
IRecycleBin *prb;
|
||||||
BOOL ret = FALSE;
|
HRESULT hr;
|
||||||
|
|
||||||
/* Open recycle bin */
|
hr = GetDefaultRecycleBin(pszRoot, &prb);
|
||||||
bin = IntReferenceRecycleBin(driveLetter);
|
if (!SUCCEEDED(hr))
|
||||||
if (!bin)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (bin->Callbacks.EmptyRecycleBin)
|
hr = IRecycleBin_EmptyRecycleBin(prb);
|
||||||
ret = bin->Callbacks.EmptyRecycleBin(&bin);
|
IRecycleBin_Release(prb);
|
||||||
else
|
|
||||||
SetLastError(ERROR_NOT_SUPPORTED);
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (bin)
|
if (SUCCEEDED(hr))
|
||||||
DereferenceHandle(&bin->refCount);
|
return TRUE;
|
||||||
return ret;
|
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||||
|
SetLastError(HRESULT_CODE(hr));
|
||||||
|
else
|
||||||
|
SetLastError(ERROR_GEN_FAILURE);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
|
@ -164,92 +148,54 @@ EnumerateRecycleBinA(
|
||||||
return EnumerateRecycleBinW((WCHAR)driveLetter, pFnCallback, Context);
|
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
|
BOOL WINAPI
|
||||||
EnumerateRecycleBinW(
|
EnumerateRecycleBinW(
|
||||||
IN WCHAR driveLetter,
|
IN WCHAR driveLetter,
|
||||||
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
|
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
|
||||||
IN PVOID Context OPTIONAL)
|
IN PVOID Context OPTIONAL)
|
||||||
{
|
{
|
||||||
PRECYCLE_BIN bin = NULL;
|
IRecycleBin *prb = NULL;
|
||||||
BOOL ret = FALSE;
|
IRecycleBinEnumList *prbel = NULL;
|
||||||
|
IRecycleBinFile *prbf;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
/* Check parameters */
|
hr = GetDefaultRecycleBin(NULL, &prb);
|
||||||
if (pFnCallback == NULL)
|
if (!SUCCEEDED(hr))
|
||||||
{
|
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open recycle bin */
|
|
||||||
bin = IntReferenceRecycleBin(driveLetter);
|
|
||||||
if (!bin)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (bin->Callbacks.EnumerateFiles)
|
hr = IRecycleBin_EnumObjects(prb, &prbel);
|
||||||
|
if (!SUCCEEDED(hr))
|
||||||
|
goto cleanup;
|
||||||
|
while (TRUE)
|
||||||
{
|
{
|
||||||
ENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext;
|
hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
|
||||||
|
if (hr == S_FALSE)
|
||||||
CallbackContext.bin = bin;
|
{
|
||||||
CallbackContext.pFnCallback = pFnCallback;
|
hr = S_OK;
|
||||||
CallbackContext.Context = Context;
|
goto cleanup;
|
||||||
|
}
|
||||||
ret = bin->Callbacks.EnumerateFiles(bin, IntEnumerateRecycleBinCallback, &CallbackContext);
|
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:
|
cleanup:
|
||||||
if (bin)
|
if (prb)
|
||||||
DereferenceHandle(&bin->refCount);
|
IRecycleBin_Release(prb);
|
||||||
return ret;
|
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
|
BOOL WINAPI
|
||||||
|
@ -284,7 +230,7 @@ GetDeletedFileDetailsA(
|
||||||
|
|
||||||
if (FileDetails)
|
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))
|
if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -302,38 +248,92 @@ GetDeletedFileDetailsW(
|
||||||
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
|
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
|
||||||
OUT LPDWORD RequiredSize OPTIONAL)
|
OUT LPDWORD RequiredSize OPTIONAL)
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||||
|
HRESULT hr;
|
||||||
|
SIZE_T NameSize, Needed;
|
||||||
|
|
||||||
if (!IntCheckDeletedFileHandle(hDeletedFile))
|
hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
|
||||||
SetLastError(ERROR_INVALID_HANDLE);
|
if (!SUCCEEDED(hr))
|
||||||
else
|
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;
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||||
if (DeletedFile->bin->Callbacks.GetDetails)
|
goto cleanup;
|
||||||
ret = DeletedFile->bin->Callbacks.GetDetails(DeletedFile->bin, DeletedFile->hDeletedFile, BufferSize, FileDetails, RequiredSize);
|
|
||||||
else
|
|
||||||
SetLastError(ERROR_NOT_SUPPORTED);
|
|
||||||
}
|
}
|
||||||
|
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
|
BOOL WINAPI
|
||||||
RestoreFile(
|
RestoreFile(
|
||||||
IN HANDLE hDeletedFile)
|
IN HANDLE hDeletedFile)
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
if (!IntCheckDeletedFileHandle(hDeletedFile))
|
hr = IRecycleBinFile_Restore(rbf);
|
||||||
SetLastError(ERROR_INVALID_HANDLE);
|
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
|
else
|
||||||
{
|
{
|
||||||
PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile;
|
/* FIXME: do a better validation! */
|
||||||
if (DeletedFile->bin->Callbacks.RestoreFile)
|
if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
|
||||||
ret = DeletedFile->bin->Callbacks.RestoreFile(DeletedFile->bin, DeletedFile->hDeletedFile);
|
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
|
||||||
else
|
|
||||||
SetLastError(ERROR_NOT_SUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
BOOL WINAPI
|
||||||
EmptyRecycleBinA(
|
EmptyRecycleBinA(
|
||||||
IN CHAR driveLetter);
|
IN LPCSTR pszRoot);
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
EmptyRecycleBinW(
|
EmptyRecycleBinW(
|
||||||
IN WCHAR driveLetter);
|
IN LPCWSTR pszRoot);
|
||||||
#ifdef UNICODE
|
#ifdef UNICODE
|
||||||
#define EmptyRecycleBin EmptyRecycleBinW
|
#define EmptyRecycleBin EmptyRecycleBinW
|
||||||
#else
|
#else
|
||||||
|
@ -102,6 +102,190 @@ BOOL WINAPI
|
||||||
RestoreFile(
|
RestoreFile(
|
||||||
IN HANDLE hDeletedFile);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
|
<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
|
||||||
<module name="recyclebin" type="staticlibrary">
|
<module name="recyclebin" type="staticlibrary">
|
||||||
<define name="__USE_W32API" />
|
<file>guid.c</file>
|
||||||
<file>openclose.c</file>
|
|
||||||
<file>recyclebin.c</file>
|
<file>recyclebin.c</file>
|
||||||
|
<file>recyclebin_generic.c</file>
|
||||||
|
<file>recyclebin_generic_enumerator.c</file>
|
||||||
<file>recyclebin_v5.c</file>
|
<file>recyclebin_v5.c</file>
|
||||||
<file>refcount.c</file>
|
<file>recyclebin_v5_enumerator.c</file>
|
||||||
</module>
|
</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; }
|
#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 */
|
/* 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 */
|
/* Structures on disk */
|
||||||
|
|
||||||
|
@ -84,33 +35,14 @@ typedef struct _INFO2_HEADER
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
|
|
||||||
/* openclose.c */
|
/* recyclebin_generic.c */
|
||||||
|
|
||||||
BOOL
|
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown);
|
||||||
IntCheckDeletedFileHandle(
|
|
||||||
IN HANDLE hDeletedFile);
|
|
||||||
|
|
||||||
PRECYCLE_BIN
|
/* recyclebin_generic_enumerator.c */
|
||||||
IntReferenceRecycleBin(
|
|
||||||
IN WCHAR driveLetter);
|
HRESULT RecycleBinGeneric_Enumerator_Constructor(OUT IRecycleBinEnumList **pprbel);
|
||||||
|
|
||||||
/* recyclebin_v5.c */
|
/* recyclebin_v5.c */
|
||||||
|
|
||||||
VOID
|
HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown);
|
||||||
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);
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
#include "recyclebin_private.h"
|
#include "recyclebin_private.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <pshpack1.h>
|
#include <pshpack1.h>
|
||||||
|
|
||||||
/* MS Windows 2000/XP/2003 */
|
/* MS Windows 2000/XP/2003 */
|
||||||
|
@ -20,57 +24,86 @@ typedef struct _DELETED_FILE_RECORD
|
||||||
|
|
||||||
#include <poppack.h>
|
#include <poppack.h>
|
||||||
|
|
||||||
static BOOL
|
/* COM interface */
|
||||||
CloseHandle5(
|
|
||||||
IN HANDLE hDeletedFile);
|
|
||||||
|
|
||||||
static BOOL
|
typedef interface IRecycleBin5 IRecycleBin5;
|
||||||
DeleteFile5(
|
EXTERN_C const IID IID_IRecycleBin5;
|
||||||
IN PRECYCLE_BIN bin,
|
|
||||||
IN LPCWSTR FullPath,
|
|
||||||
IN LPCWSTR FileName);
|
|
||||||
|
|
||||||
static BOOL
|
typedef struct IRecycleBin5Vtbl
|
||||||
EmptyRecycleBin5(
|
{
|
||||||
IN PRECYCLE_BIN* bin);
|
/* IRecycleBin interface */
|
||||||
|
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
|
||||||
|
IN IRecycleBin5 *This,
|
||||||
|
IN REFIID riid,
|
||||||
|
OUT void **ppvObject);
|
||||||
|
|
||||||
static BOOL
|
ULONG (STDMETHODCALLTYPE *AddRef)(
|
||||||
EnumerateFiles5(
|
IN IRecycleBin5 *This);
|
||||||
IN PRECYCLE_BIN bin,
|
|
||||||
IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
|
|
||||||
IN PVOID Context OPTIONAL);
|
|
||||||
|
|
||||||
static BOOL
|
ULONG (STDMETHODCALLTYPE *Release)(
|
||||||
GetDetails5(
|
IN IRecycleBin5 *This);
|
||||||
IN PRECYCLE_BIN bin,
|
|
||||||
IN HANDLE hDeletedFile,
|
|
||||||
IN DWORD BufferSize,
|
|
||||||
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
|
|
||||||
OUT LPDWORD RequiredSize OPTIONAL);
|
|
||||||
|
|
||||||
static BOOL
|
HRESULT (STDMETHODCALLTYPE *DeleteFile)(
|
||||||
RestoreFile5(
|
IN IRecycleBin5 *This,
|
||||||
IN PRECYCLE_BIN bin,
|
IN LPCWSTR szFileName);
|
||||||
IN HANDLE hDeletedFile);
|
|
||||||
|
|
||||||
static BOOL
|
HRESULT (STDMETHODCALLTYPE *EmptyRecycleBin)(
|
||||||
IntDeleteRecursive(
|
IN IRecycleBin5 *This);
|
||||||
IN LPCWSTR FullName);
|
|
||||||
|
|
||||||
static BOOL
|
HRESULT (STDMETHODCALLTYPE *EnumObjects)(
|
||||||
IntEmptyRecycleBinCallback(
|
IN IRecycleBin5 *This,
|
||||||
IN PVOID Context,
|
OUT IRecycleBinEnumList **ppEnumList);
|
||||||
IN HANDLE hDeletedFile);
|
|
||||||
|
|
||||||
static BOOL
|
/* IRecycleBin5 interface */
|
||||||
IntGetFullName(
|
HRESULT (STDMETHODCALLTYPE *Delete)(
|
||||||
IN PRECYCLE_BIN bin,
|
IN IRecycleBin5 *This,
|
||||||
IN PDELETED_FILE_RECORD pDeletedFile,
|
IN LPCWSTR pDeletedFileName,
|
||||||
OUT LPWSTR* pFullName);
|
IN DELETED_FILE_RECORD *pDeletedFile);
|
||||||
|
|
||||||
static BOOL
|
HRESULT (STDMETHODCALLTYPE *Restore)(
|
||||||
IntSearchRecord(
|
IN IRecycleBin5 *This,
|
||||||
IN PRECYCLE_BIN bin,
|
IN LPCWSTR pDeletedFileName,
|
||||||
IN HANDLE hDeletedFile,
|
IN DELETED_FILE_RECORD *pDeletedFile);
|
||||||
OUT PDELETED_FILE_RECORD DeletedFile,
|
|
||||||
OUT PLARGE_INTEGER Position OPTIONAL);
|
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