Author: hpoussin
Date: Wed Oct 31 11:57:35 2007
New Revision: 29998
URL:
http://svn.reactos.org/svn/reactos?rev=29998&view=rev
Log:
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
Added:
trunk/reactos/lib/recyclebin/guid.c (with props)
trunk/reactos/lib/recyclebin/recyclebin_generic.c (with props)
trunk/reactos/lib/recyclebin/recyclebin_generic_enumerator.c (with props)
trunk/reactos/lib/recyclebin/recyclebin_v5_enumerator.c (with props)
Removed:
trunk/reactos/lib/recyclebin/openclose.c
trunk/reactos/lib/recyclebin/refcount.c
Modified:
trunk/reactos/lib/recyclebin/readme.txt
trunk/reactos/lib/recyclebin/recyclebin.c
trunk/reactos/lib/recyclebin/recyclebin.h
trunk/reactos/lib/recyclebin/recyclebin.rbuild
trunk/reactos/lib/recyclebin/recyclebin_private.h
trunk/reactos/lib/recyclebin/recyclebin_v5.c
trunk/reactos/lib/recyclebin/recyclebin_v5.h
Added: trunk/reactos/lib/recyclebin/guid.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/guid.c?rev=…
==============================================================================
--- trunk/reactos/lib/recyclebin/guid.c (added)
+++ trunk/reactos/lib/recyclebin/guid.c Wed Oct 31 11:57:35 2007
@@ -1,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(a)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);
Propchange: trunk/reactos/lib/recyclebin/guid.c
------------------------------------------------------------------------------
svn:eol-style = native
Removed: trunk/reactos/lib/recyclebin/openclose.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/openclose.c…
==============================================================================
--- trunk/reactos/lib/recyclebin/openclose.c (original)
+++ trunk/reactos/lib/recyclebin/openclose.c (removed)
@@ -1,315 +1,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(a)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;
-}
Modified: trunk/reactos/lib/recyclebin/readme.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/readme.txt?…
==============================================================================
--- trunk/reactos/lib/recyclebin/readme.txt (original)
+++ trunk/reactos/lib/recyclebin/readme.txt Wed Oct 31 11:57:35 2007
@@ -1,6 +1,5 @@
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)
@@ -9,7 +8,6 @@
- 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
Modified: trunk/reactos/lib/recyclebin/recyclebin.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin.…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin.c (original)
+++ trunk/reactos/lib/recyclebin/recyclebin.c Wed Oct 31 11:57:35 2007
@@ -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(a)reactos.org)
+ * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin(a)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;
-
- if (!IntCheckDeletedFileHandle(hDeletedFile))
- SetLastError(ERROR_INVALID_HANDLE);
- else
- {
- PDELETED_FILE_HANDLE file = (PDELETED_FILE_HANDLE)hDeletedFile;
- ret = DereferenceHandle(&file->refCount);
- }
-
- return ret;
+ IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
+ HRESULT hr;
+
+ hr = IRecycleBinFile_Release(rbf);
+ if (SUCCEEDED(hr))
+ return TRUE;
+ if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
+ SetLastError(HRESULT_CODE(hr));
+ else
+ SetLastError(ERROR_GEN_FAILURE);
+ return FALSE;
}
BOOL WINAPI
@@ -70,89 +65,78 @@
DeleteFileToRecycleBinW(
IN LPCWSTR FileName)
{
- LPWSTR FullFileName = NULL;
- DWORD dwBufferLength = 0;
- LPWSTR lpFilePart;
- DWORD len;
- PRECYCLE_BIN bin = NULL;
+ IRecycleBin *prb;
+ HRESULT hr;
+
+ hr = GetDefaultRecycleBin(NULL, &prb);
+ if (!SUCCEEDED(hr))
+ goto cleanup;
+
+ hr = IRecycleBin_DeleteFile(prb, FileName);
+ IRecycleBin_Release(prb);
+
+cleanup:
+ if (SUCCEEDED(hr))
+ return TRUE;
+ if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
+ SetLastError(HRESULT_CODE(hr));
+ else
+ SetLastError(ERROR_GEN_FAILURE);
+ return FALSE;
+}
+
+BOOL WINAPI
+EmptyRecycleBinA(
+ IN LPCSTR pszRoot OPTIONAL)
+{
+ int len;
+ LPWSTR szRootW = NULL;
BOOL ret = FALSE;
- /* Check parameters */
- if (FileName == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- goto cleanup;
- }
-
- /* Get full file name */
- while (TRUE)
- {
- len = GetFullPathNameW(FileName, dwBufferLength, FullFileName, &lpFilePart);
+ if (pszRoot)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
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)
+ szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (!szRootW)
{
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;
-
- if (bin->Callbacks.DeleteFile)
- ret = bin->Callbacks.DeleteFile(bin, FullFileName, lpFilePart);
- else
- SetLastError(ERROR_NOT_SUPPORTED);
-
-cleanup:
- HeapFree(GetProcessHeap(), 0, FullFileName);
- if (bin)
- DereferenceHandle(&bin->refCount);
+ if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
+ goto cleanup;
+ }
+
+ ret = EmptyRecycleBinW(szRootW);
+
+cleanup:
+ HeapFree(GetProcessHeap(), 0, szRootW);
return ret;
}
BOOL WINAPI
-EmptyRecycleBinA(
- IN CHAR driveLetter)
-{
- return EmptyRecycleBinW((WCHAR)driveLetter);
-}
-
-BOOL WINAPI
EmptyRecycleBinW(
- IN WCHAR driveLetter)
-{
- PRECYCLE_BIN bin = NULL;
- BOOL ret = FALSE;
-
- /* Open recycle bin */
- bin = IntReferenceRecycleBin(driveLetter);
- if (!bin)
- goto cleanup;
-
- if (bin->Callbacks.EmptyRecycleBin)
- ret = bin->Callbacks.EmptyRecycleBin(&bin);
- else
- SetLastError(ERROR_NOT_SUPPORTED);
-
-cleanup:
- if (bin)
- DereferenceHandle(&bin->refCount);
- return ret;
+ IN LPCWSTR pszRoot OPTIONAL)
+{
+ IRecycleBin *prb;
+ HRESULT hr;
+
+ hr = GetDefaultRecycleBin(pszRoot, &prb);
+ if (!SUCCEEDED(hr))
+ goto cleanup;
+
+ hr = IRecycleBin_EmptyRecycleBin(prb);
+ IRecycleBin_Release(prb);
+
+cleanup:
+ if (SUCCEEDED(hr))
+ return TRUE;
+ if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
+ SetLastError(HRESULT_CODE(hr));
+ else
+ SetLastError(ERROR_GEN_FAILURE);
+ return FALSE;
}
BOOL WINAPI
@@ -164,92 +148,54 @@
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;
-
- /* Check parameters */
- if (pFnCallback == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- goto cleanup;
- }
-
- /* Open recycle bin */
- bin = IntReferenceRecycleBin(driveLetter);
- if (!bin)
- goto cleanup;
-
- if (bin->Callbacks.EnumerateFiles)
- {
- ENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext;
-
- CallbackContext.bin = bin;
- CallbackContext.pFnCallback = pFnCallback;
- CallbackContext.Context = Context;
-
- ret = bin->Callbacks.EnumerateFiles(bin, IntEnumerateRecycleBinCallback,
&CallbackContext);
- }
- else
- SetLastError(ERROR_NOT_SUPPORTED);
-
-cleanup:
- if (bin)
- DereferenceHandle(&bin->refCount);
- return ret;
+ IRecycleBin *prb = NULL;
+ IRecycleBinEnumList *prbel = NULL;
+ IRecycleBinFile *prbf;
+ HRESULT hr;
+
+ hr = GetDefaultRecycleBin(NULL, &prb);
+ if (!SUCCEEDED(hr))
+ goto cleanup;
+
+ hr = IRecycleBin_EnumObjects(prb, &prbel);
+ if (!SUCCEEDED(hr))
+ goto cleanup;
+ while (TRUE)
+ {
+ hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
+ if (hr == S_FALSE)
+ {
+ hr = S_OK;
+ goto cleanup;
+ }
+ else if (!SUCCEEDED(hr))
+ goto cleanup;
+ if (!pFnCallback(Context, (HANDLE)prbf))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ IRecycleBinFile_Release(prbf);
+ }
+
+cleanup:
+ 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 @@
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 @@
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
OUT LPDWORD RequiredSize OPTIONAL)
{
- BOOL ret = FALSE;
-
- if (!IntCheckDeletedFileHandle(hDeletedFile))
- SetLastError(ERROR_INVALID_HANDLE);
- else
- {
- 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);
- }
-
- return ret;
+ IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
+ HRESULT hr;
+ SIZE_T NameSize, Needed;
+
+ 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)
+ {
+ 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;
+
+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;
-
- if (!IntCheckDeletedFileHandle(hDeletedFile))
- SetLastError(ERROR_INVALID_HANDLE);
- 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);
- }
-
- return ret;
-}
+ IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
+ HRESULT hr;
+
+ 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
+ {
+ /* FIXME: do a better validation! */
+ if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] !=
'\\')
+ return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
+
+ /* For now, only support this type of recycle bins... */
+ hr = RecycleBin5_Constructor(pszVolume, &pUnk);
+ }
+ if (!SUCCEEDED(hr))
+ return hr;
+ hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBin, (void **)pprb);
+ IUnknown_Release(pUnk);
+ return hr;
+}
Modified: trunk/reactos/lib/recyclebin/recyclebin.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin.…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin.h (original)
+++ trunk/reactos/lib/recyclebin/recyclebin.h Wed Oct 31 11:57:35 2007
@@ -54,10 +54,10 @@
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 @@
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
Modified: trunk/reactos/lib/recyclebin/recyclebin.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin.…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin.rbuild (original)
+++ trunk/reactos/lib/recyclebin/recyclebin.rbuild Wed Oct 31 11:57:35 2007
@@ -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>
Added: trunk/reactos/lib/recyclebin/recyclebin_generic.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin_generic.c (added)
+++ trunk/reactos/lib/recyclebin/recyclebin_generic.c Wed Oct 31 11:57:35 2007
@@ -1,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(a)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;
+}
Propchange: trunk/reactos/lib/recyclebin/recyclebin_generic.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/lib/recyclebin/recyclebin_generic_enumerator.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin_generic_enumerator.c (added)
+++ trunk/reactos/lib/recyclebin/recyclebin_generic_enumerator.c Wed Oct 31 11:57:35 2007
@@ -1,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(a)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);
+}
Propchange: trunk/reactos/lib/recyclebin/recyclebin_generic_enumerator.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/lib/recyclebin/recyclebin_private.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin_private.h (original)
+++ trunk/reactos/lib/recyclebin/recyclebin_private.h Wed Oct 31 11:57:35 2007
@@ -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 @@
/* 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);
Modified: trunk/reactos/lib/recyclebin/recyclebin_v5.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin_v5.c (original)
+++ trunk/reactos/lib/recyclebin/recyclebin_v5.c Wed Oct 31 11:57:35 2007
@@ -1,547 +1,726 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
- * FILE: lib/recyclebin/openclose.c
+ * FILE: lib/recyclebin/recyclebin_v5.c
* PURPOSE: Deals with recycle bins of Windows 2000/XP/2003
- * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin(a)reactos.org)
+ * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin(a)reactos.org)
*/
+#define COBJMACROS
#include "recyclebin_v5.h"
-
-VOID
-InitializeCallbacks5(
- IN OUT PRECYCLEBIN_CALLBACKS Callbacks)
-{
- Callbacks->CloseHandle = CloseHandle5;
- Callbacks->DeleteFile = DeleteFile5;
- Callbacks->EmptyRecycleBin = EmptyRecycleBin5;
- Callbacks->EnumerateFiles = EnumerateFiles5;
- Callbacks->GetDetails = GetDetails5;
- Callbacks->RestoreFile = RestoreFile5;
-}
+#include <stdio.h>
static BOOL
-CloseHandle5(
- IN HANDLE hDeletedFile)
-{
- UNREFERENCED_PARAMETER(hDeletedFile);
- /* Nothing to do, as hDeletedFile is simply a DWORD... */
- return TRUE;
-}
-
-static BOOL
-DeleteFile5(
- IN PRECYCLE_BIN bin,
- IN LPCWSTR FullPath,
- IN LPCWSTR FileName)
-{
+IntDeleteRecursive(
+ IN LPCWSTR FullName)
+{
+ DWORD RemovableAttributes = FILE_ATTRIBUTE_READONLY;
+ DWORD FileAttributes;
+ BOOL ret = FALSE;
+
+ FileAttributes = GetFileAttributesW(FullName);
+ if (FileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ if (GetLastError() == ERROR_FILE_NOT_FOUND)
+ ret = TRUE;
+ goto cleanup;
+ }
+ if (FileAttributes & RemovableAttributes)
+ {
+ if (!SetFileAttributesW(FullName, FileAttributes & ~RemovableAttributes))
+ goto cleanup;
+ }
+ if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ /* Recursive deletion */
+ /* FIXME: recursive deletion */
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ goto cleanup;
+
+ if (!RemoveDirectoryW(FullName))
+ goto cleanup;
+ }
+ else
+ {
+ if (!DeleteFileW(FullName))
+ goto cleanup;
+ }
+ ret = TRUE;
+
+cleanup:
+ return ret;
+}
+
+struct RecycleBin5
+{
+ ULONG ref;
+ IRecycleBin5 recycleBinImpl;
+ HANDLE hInfo;
+ HANDLE hInfoMapped;
+
+ DWORD EnumeratorCount;
+
+ LPWSTR VolumePath;
+ WCHAR Folder[ANY_SIZE]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */
+};
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_QueryInterface(
+ IRecycleBin5 *This,
+ REFIID riid,
+ void **ppvObject)
+{
+ struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+
+ if (!ppvObject)
+ return E_POINTER;
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppvObject = &s->recycleBinImpl;
+ else if (IsEqualIID(riid, &IID_IRecycleBin))
+ *ppvObject = &s->recycleBinImpl;
+ else if (IsEqualIID(riid, &IID_IRecycleBin5))
+ *ppvObject = &s->recycleBinImpl;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef(This);
+ return S_OK;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_AddRef(
+ IRecycleBin5 *This)
+{
+ struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+ ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
+ return refCount;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_Release(
+ IRecycleBin5 *This)
+{
+ struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+ ULONG refCount;
+
+ if (!This)
+ return E_POINTER;
+
+ refCount = InterlockedDecrement((PLONG)&s->ref);
+
+ if (refCount == 0)
+ {
+ CloseHandle(s->hInfo);
+ CloseHandle(s->hInfoMapped);
+ CoTaskMemFree(s);
+ }
+
+ return refCount;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_DeleteFile(
+ IN IRecycleBin5 *This,
+ IN LPCWSTR szFileName)
+{
+ struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+ LPWSTR szFullName = NULL;
+ DWORD dwBufferLength = 0;
+ LPWSTR lpFilePart;
+ LPCWSTR Extension;
+ WCHAR DeletedFileName[MAX_PATH];
+ DWORD len;
HANDLE hFile = INVALID_HANDLE_VALUE;
- INFO2_HEADER Header;
- DELETED_FILE_RECORD DeletedFile;
- DWORD bytesRead, bytesWritten;
+ PINFO2_HEADER pHeader = NULL;
+ PDELETED_FILE_RECORD pDeletedFile;
ULARGE_INTEGER fileSize;
+ DWORD dwAttributes;
SYSTEMTIME SystemTime;
- WCHAR RootDir[4];
- WCHAR DeletedFileName[2 * MAX_PATH];
- LPCWSTR Extension;
DWORD ClusterSize, BytesPerSector, SectorsPerCluster;
- BOOL ret = FALSE;
-
- if (wcslen(FullPath) >= MAX_PATH)
- {
- /* Unable to store a too long path in recycle bin */
- SetLastError(ERROR_INVALID_NAME);
- goto cleanup;
- }
-
- hFile = CreateFileW(FullPath, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+ HRESULT hr;
+
+ if (s->EnumeratorCount != 0)
+ return E_FAIL;
+
+ /* Get full file name */
+ while (TRUE)
+ {
+ len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, &lpFilePart);
+ 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);
+ }
+
+ /* Check if file exists */
+ dwAttributes = GetFileAttributesW(szFullName);
+ if (dwAttributes == INVALID_FILE_ATTRIBUTES)
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ if (dwBufferLength < 2 || szFullName[1] != ':')
+ {
+ /* Not a local file */
+ CoTaskMemFree(szFullName);
+ return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
+ }
+
+ hFile = CreateFileW(szFullName, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == 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) || Header.dwRecordSize == 0)
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
-
- if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+
+ /* Increase INFO2 file size */
+ CloseHandle(s->hInfoMapped);
+ SetFilePointer(s->hInfo, sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
+ SetEndOfFile(s->hInfo);
+ s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT,
0, 0, NULL);
+ if (!s->hInfoMapped)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+
+ /* Open INFO2 file */
+ pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
+ if (!pHeader)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ pDeletedFile = ((PDELETED_FILE_RECORD)(pHeader + 1)) + pHeader->dwNumberOfEntries;
/* Get file size */
#if 0
- if (!GetFileSizeEx(hFile, &fileSize))
- goto cleanup;
+ if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&fileSize))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
#else
fileSize.u.LowPart = GetFileSize(hFile, &fileSize.u.HighPart);
if (fileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
- goto cleanup;
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
#endif
/* Check if file size is > 4Gb */
if (fileSize.u.HighPart != 0)
{
/* FIXME: how to delete files >= 4Gb? */
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- goto cleanup;
- }
- Header.dwTotalLogicalSize += fileSize.u.LowPart;
+ hr = E_NOTIMPL;
+ goto cleanup;
+ }
+ pHeader->dwTotalLogicalSize += fileSize.u.LowPart;
/* Generate new name */
- Header.dwHighestRecordUniqueId++;
- Extension = wcsrchr(FileName, '.');
- wsprintfW(DeletedFileName, L"%s\\D%c%lu%s", bin->Folder, FullPath[0] -
'A' + 'a', Header.dwHighestRecordUniqueId, Extension);
+ pHeader->dwHighestRecordUniqueId++;
+ Extension = wcsrchr(szFullName, '.');
+ ZeroMemory(pDeletedFile, sizeof(DELETED_FILE_RECORD));
+ pDeletedFile->dwRecordUniqueId = pHeader->dwHighestRecordUniqueId;
+ pDeletedFile->dwDriveNumber = tolower(szFullName[0]) - 'a';
+ _snwprintf(DeletedFileName, MAX_PATH, L"%s\\D%c%lu%s", s->Folder,
pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId,
Extension);
/* Get cluster size */
- wsprintfW(RootDir, L"%c:\\", bin->Folder[0]);
- if (!GetDiskFreeSpaceW(RootDir, &SectorsPerCluster, &BytesPerSector, NULL,
NULL))
- goto cleanup;
+ if (!GetDiskFreeSpaceW(s->VolumePath, &SectorsPerCluster, &BytesPerSector,
NULL, NULL))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
ClusterSize = BytesPerSector * SectorsPerCluster;
/* Get current time */
GetSystemTime(&SystemTime);
- if (!SystemTimeToFileTime(&SystemTime, &DeletedFile.DeletionTime))
- goto cleanup;
-
- /* Update INFO2 */
- memset(&DeletedFile, 0, sizeof(DELETED_FILE_RECORD));
- if (WideCharToMultiByte(CP_ACP, 0, FullPath, -1, DeletedFile.FileNameA, MAX_PATH, NULL,
NULL) == 0)
- {
+ if (!SystemTimeToFileTime(&SystemTime, &pDeletedFile->DeletionTime))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ pDeletedFile->dwPhysicalFileSize = ROUND_UP(fileSize.u.LowPart, ClusterSize);
+
+ /* Set name */
+ wcscpy(pDeletedFile->FileNameW, szFullName);
+ if (WideCharToMultiByte(CP_ACP, 0, pDeletedFile->FileNameW, -1,
pDeletedFile->FileNameA, MAX_PATH, NULL, NULL) == 0)
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
SetLastError(ERROR_INVALID_NAME);
goto cleanup;
}
- DeletedFile.dwRecordUniqueId = Header.dwHighestRecordUniqueId;
- DeletedFile.dwDriveNumber = tolower(bin->Folder[0]) - 'a';
- DeletedFile.dwPhysicalFileSize = ROUND_UP(fileSize.u.LowPart, ClusterSize);
- wcscpy(DeletedFile.FileNameW, FullPath);
-
- if (!SetFilePointer(bin->hInfo, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
- goto cleanup;
- if (!WriteFile(bin->hInfo, &DeletedFile, sizeof(DELETED_FILE_RECORD),
&bytesWritten, NULL))
- goto cleanup;
- if (bytesWritten != sizeof(DELETED_FILE_RECORD))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
- Header.dwNumberOfEntries++;
- if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
- {
- goto cleanup;
- }
- if (!WriteFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesWritten,
NULL))
- goto cleanup;
- if (bytesWritten != sizeof(INFO2_HEADER))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
+ pHeader->dwNumberOfEntries++;
/* Move file */
- if (!MoveFileW(FullPath, DeletedFileName))
- goto cleanup;
-
- ret = TRUE;
+ if (MoveFileW(szFullName, DeletedFileName))
+ hr = S_OK;
+ else
+ hr = HRESULT_FROM_WIN32(GetLastError());
cleanup:
+ if (pHeader)
+ UnmapViewOfFile(pHeader);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
- return ret;
-}
-
-static BOOL
-EmptyRecycleBin5(
- IN PRECYCLE_BIN* bin)
-{
- LPWSTR InfoFile = NULL;
- BOOL ret = FALSE;
-
- InfoFile = HeapAlloc(GetProcessHeap(), 0, wcslen((*bin)->InfoFile) * sizeof(WCHAR) +
sizeof(UNICODE_NULL));
- if (!InfoFile)
- {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- goto cleanup;
- }
- wcscpy(InfoFile, (*bin)->InfoFile);
-
- /* Delete all files in the recycle bin */
- if (!EnumerateFiles5(*bin, IntEmptyRecycleBinCallback, *bin))
- goto cleanup;
-
- /* Delete INFO2 */
- if (!DereferenceHandle(&(*bin)->refCount))
- goto cleanup;
- if (!DeleteFileW(InfoFile))
- goto cleanup;
- *bin = NULL;
- ret = TRUE;
+ CoTaskMemFree(szFullName);
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_EmptyRecycleBin(
+ IN IRecycleBin5 *This)
+{
+ IRecycleBinEnumList *prbel;
+ IRecycleBinFile *prbf;
+ HRESULT hr;
+
+ while (TRUE)
+ {
+ hr = IRecycleBin5_EnumObjects(This, &prbel);
+ if (!SUCCEEDED(hr))
+ return hr;
+ hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
+ IRecycleBinEnumList_Release(prbel);
+ if (hr == S_FALSE)
+ return S_OK;
+ hr = IRecycleBinFile_Delete(prbf);
+ IRecycleBinFile_Release(prbf);
+ if (!SUCCEEDED(hr))
+ return hr;
+ }
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_EnumObjects(
+ IN IRecycleBin5 *This,
+ OUT IRecycleBinEnumList **ppEnumList)
+{
+ struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+ IRecycleBinEnumList *prbel;
+ HRESULT hr;
+ IUnknown *pUnk;
+
+ hr = RecycleBin5_Enumerator_Constructor(This, s->hInfo, s->hInfoMapped,
s->Folder, &pUnk);
+ if (!SUCCEEDED(hr))
+ return hr;
+
+ hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBinEnumList, (void **)&prbel);
+ if (SUCCEEDED(hr))
+ {
+ s->EnumeratorCount++;
+ *ppEnumList = prbel;
+ }
+ IUnknown_Release(pUnk);
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_Delete(
+ IN IRecycleBin5 *This,
+ IN LPCWSTR pDeletedFileName,
+ IN DELETED_FILE_RECORD *pDeletedFile)
+{
+ struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+ ULARGE_INTEGER FileSize;
+ PINFO2_HEADER pHeader;
+ DELETED_FILE_RECORD *pRecord, *pLast;
+ DWORD dwEntries, i;
+
+ if (s->EnumeratorCount != 0)
+ return E_FAIL;
+
+ pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
+ if (!pHeader)
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
+ if (FileSize.u.LowPart == 0)
+ {
+ UnmapViewOfFile(pHeader);
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+ dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) /
sizeof(DELETED_FILE_RECORD));
+
+ pRecord = (DELETED_FILE_RECORD *)(pHeader + 1);
+ for (i = 0; i < dwEntries; i++)
+ {
+ if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId)
+ {
+ /* Delete file */
+ if (!IntDeleteRecursive(pDeletedFileName))
+ {
+ UnmapViewOfFile(pHeader);
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ /* Clear last entry in the file */
+ MoveMemory(pRecord, pRecord + 1, (dwEntries - i - 1) * sizeof(DELETED_FILE_RECORD));
+ pLast = pRecord + (dwEntries - i - 1);
+ ZeroMemory(pLast, sizeof(DELETED_FILE_RECORD));
+ UnmapViewOfFile(pHeader);
+
+ /* Resize file */
+ CloseHandle(s->hInfoMapped);
+ SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
+ SetEndOfFile(s->hInfo);
+ s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT,
0, 0, NULL);
+ if (!s->hInfoMapped)
+ return HRESULT_FROM_WIN32(GetLastError());
+ return S_OK;
+ }
+ pRecord++;
+ }
+ UnmapViewOfFile(pHeader);
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_Restore(
+ IN IRecycleBin5 *This,
+ IN LPCWSTR pDeletedFileName,
+ IN DELETED_FILE_RECORD *pDeletedFile)
+{
+ struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+ ULARGE_INTEGER FileSize;
+ PINFO2_HEADER pHeader;
+ DELETED_FILE_RECORD *pRecord, *pLast;
+ DWORD dwEntries, i;
+
+ if (s->EnumeratorCount != 0)
+ return E_FAIL;
+
+ pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
+ if (!pHeader)
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
+ if (FileSize.u.LowPart == 0)
+ {
+ UnmapViewOfFile(pHeader);
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+ dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) /
sizeof(DELETED_FILE_RECORD));
+
+ pRecord = (DELETED_FILE_RECORD *)(pHeader + 1);
+ for (i = 0; i < dwEntries; i++)
+ {
+ if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId)
+ {
+ /* Restore file */
+ if (!MoveFileW(pDeletedFileName, pDeletedFile->FileNameW))
+ {
+ UnmapViewOfFile(pHeader);
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ /* Clear last entry in the file */
+ MoveMemory(pRecord, pRecord + 1, (dwEntries - i - 1) * sizeof(DELETED_FILE_RECORD));
+ pLast = pRecord + (dwEntries - i - 1);
+ ZeroMemory(pLast, sizeof(DELETED_FILE_RECORD));
+ UnmapViewOfFile(pHeader);
+
+ /* Resize file */
+ CloseHandle(s->hInfoMapped);
+ SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
+ SetEndOfFile(s->hInfo);
+ s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT,
0, 0, NULL);
+ if (!s->hInfoMapped)
+ return HRESULT_FROM_WIN32(GetLastError());
+ return S_OK;
+ }
+ pRecord++;
+ }
+
+ UnmapViewOfFile(pHeader);
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_OnClosing(
+ IN IRecycleBin5 *This,
+ IN IRecycleBinEnumList *prb5el)
+{
+ struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+ s->EnumeratorCount--;
+ return S_OK;
+}
+
+CONST_VTBL struct IRecycleBin5Vtbl RecycleBin5Vtbl =
+{
+ RecycleBin5_RecycleBin5_QueryInterface,
+ RecycleBin5_RecycleBin5_AddRef,
+ RecycleBin5_RecycleBin5_Release,
+ RecycleBin5_RecycleBin5_DeleteFile,
+ RecycleBin5_RecycleBin5_EmptyRecycleBin,
+ RecycleBin5_RecycleBin5_EnumObjects,
+ RecycleBin5_RecycleBin5_Delete,
+ RecycleBin5_RecycleBin5_Restore,
+ RecycleBin5_RecycleBin5_OnClosing,
+};
+
+static HRESULT
+RecycleBin5_Create(
+ IN LPCWSTR Folder,
+ 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";
+ INFO2_HEADER Info2Contents[] = { { 5, 0, 0, 0x320, 0 } };
+ SIZE_T BytesToWrite, BytesWritten, Needed;
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ HRESULT hr;
+
+ Needed = (wcslen(Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME),
wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR);
+ BufferName = HeapAlloc(GetProcessHeap(), 0, Needed);
+ if (!BufferName)
+ {
+ hr = ERROR_NOT_ENOUGH_MEMORY;
+ goto cleanup;
+ }
+
+ wcscpy(BufferName, Folder);
+ Separator = wcsstr(&BufferName[3], L"\\");
+ if (Separator)
+ *Separator = UNICODE_NULL;
+ if (!CreateDirectoryW(BufferName, NULL) && GetLastError() !=
ERROR_ALREADY_EXISTS)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ SetFileAttributesW(BufferName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
+ if (Separator)
+ {
+ *Separator = L'\\';
+ if (!CreateDirectoryW(BufferName, NULL) && GetLastError() !=
ERROR_ALREADY_EXISTS)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ 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)
+ {
+ hr = HRESULT_FROM_WIN32(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)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ BytesToWrite = strlen(DesktopIniContents);
+ if (!WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten,
NULL))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ if (BytesWritten != BytesToWrite)
+ {
+ hr = E_FAIL;
+ 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)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ BytesToWrite = sizeof(Info2Contents);
+ if (!WriteFile(hFile, Info2Contents, (DWORD)BytesToWrite, &BytesWritten, NULL))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ if (BytesWritten == BytesToWrite)
+ hr = S_OK;
+ else
+ hr = E_FAIL;
cleanup:
- HeapFree(GetProcessHeap(), 0, InfoFile);
- return ret;
-}
-
-static BOOL
-EnumerateFiles5(
- IN PRECYCLE_BIN bin,
- IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
- IN PVOID Context OPTIONAL)
-{
- INFO2_HEADER Header;
- DELETED_FILE_RECORD DeletedFile;
- DWORD bytesRead, dwEntries;
- BOOL ret = FALSE;
-
- 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) || Header.dwRecordSize == 0)
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
-
- if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
-
- SetLastError(ERROR_SUCCESS);
- for (dwEntries = 0; dwEntries < Header.dwNumberOfEntries; dwEntries++)
- {
- if (!ReadFile(bin->hInfo, &DeletedFile, Header.dwRecordSize, &bytesRead,
NULL))
- goto cleanup;
- if (bytesRead != Header.dwRecordSize)
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
- if (!pFnCallback(Context, (HANDLE)(ULONG_PTR)DeletedFile.dwRecordUniqueId))
- goto cleanup;
- if (SetFilePointer(bin->hInfo, sizeof(INFO2_HEADER) + Header.dwRecordSize *
dwEntries, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
- goto cleanup;
- }
-
- ret = TRUE;
-
-cleanup:
- return ret;
-}
-
-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)
-{
- DELETED_FILE_RECORD DeletedFile;
- SIZE_T Needed;
- LPWSTR FullName = NULL;
- HANDLE hFile = INVALID_HANDLE_VALUE;
- BOOL ret = FALSE;
-
- /* Check parameters */
- if (BufferSize > 0 && FileDetails == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- goto cleanup;
- }
-
- if (!IntSearchRecord(bin, hDeletedFile, &DeletedFile, NULL))
- goto cleanup;
- Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + (wcslen(DeletedFile.FileNameW)
+ 1) * sizeof(WCHAR);
- if (RequiredSize)
- *RequiredSize = (DWORD)Needed;
- if (Needed > BufferSize)
- {
- SetLastError(ERROR_INSUFFICIENT_BUFFER);
- goto cleanup;
- }
-
- if (!IntGetFullName(bin, &DeletedFile, &FullName))
- goto cleanup;
-
- /* Open file */
- FileDetails->Attributes = GetFileAttributesW(FullName);
- if (FileDetails->Attributes == INVALID_FILE_ATTRIBUTES)
- goto cleanup;
- if (FileDetails->Attributes & FILE_ATTRIBUTE_DIRECTORY)
- hFile = CreateFileW(FullName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- else
- hFile = CreateFileW(FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,
NULL);
- if (hFile == INVALID_HANDLE_VALUE)
- goto cleanup;
-
- /* Fill returned structure */
- if (!GetFileTime(hFile, NULL, NULL, &FileDetails->LastModification))
- goto cleanup;
- memcpy(&FileDetails->DeletionTime, &DeletedFile.DeletionTime,
sizeof(FILETIME));
- FileDetails->FileSize.u.LowPart = GetFileSize(hFile,
&FileDetails->FileSize.u.HighPart);
- if (FileDetails->FileSize.u.LowPart == INVALID_FILE_SIZE)
- goto cleanup;
- FileDetails->PhysicalFileSize.u.HighPart = 0;
- FileDetails->PhysicalFileSize.u.LowPart = DeletedFile.dwPhysicalFileSize;
- wcscpy(FileDetails->FileName, DeletedFile.FileNameW);
-
- ret = TRUE;
-
-cleanup:
- HeapFree(GetProcessHeap(), 0, FullName);
+ HeapFree(GetProcessHeap(), 0, BufferName);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
- return ret;
-}
-
-static BOOL
-RestoreFile5(
- IN PRECYCLE_BIN bin,
- IN HANDLE hDeletedFile)
-{
- INFO2_HEADER Header;
- DWORD bytesRead, bytesWritten;
- LARGE_INTEGER Position;
- DELETED_FILE_RECORD DeletedFile, LastFile;
- LPWSTR FullName = NULL;
- BOOL ret = FALSE;
-
- 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) || Header.dwRecordSize == 0)
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
-
- if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
-
- /* Search deleted entry */
- if (!IntSearchRecord(bin, hDeletedFile, &DeletedFile, &Position))
- goto cleanup;
- /* Get destination full name */
- if (!IntGetFullName(bin, &DeletedFile, &FullName))
- goto cleanup;
- /* Restore file */
- if (!MoveFileW(FullName, DeletedFile.FileNameW))
- goto cleanup;
-
- /* Update INFO2 */
- /* 1) If not last entry, copy last entry to the current one */
- if (SetFilePointer(bin->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END) ==
INVALID_SET_FILE_POINTER)
- goto cleanup;
- if (!ReadFile(bin->hInfo, &LastFile, sizeof(DELETED_FILE_RECORD), &bytesRead,
NULL))
- goto cleanup;
- if (bytesRead != sizeof(DELETED_FILE_RECORD))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
- if (LastFile.dwRecordUniqueId != DeletedFile.dwRecordUniqueId)
- {
- /* Move the last entry to the current one */
- if (SetFilePointer(bin->hInfo, Position.u.LowPart, &Position.u.HighPart,
FILE_BEGIN) == INVALID_SET_FILE_POINTER)
- goto cleanup;
- if (!WriteFile(bin->hInfo, &LastFile, sizeof(DELETED_FILE_RECORD),
&bytesWritten, NULL))
- goto cleanup;
- if (bytesWritten != sizeof(DELETED_FILE_RECORD))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
- }
- /* 2) Update the header */
- Header.dwNumberOfEntries--;
- if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
- goto cleanup;
- if (!WriteFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesWritten,
NULL))
- goto cleanup;
- if (bytesWritten != sizeof(INFO2_HEADER))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
- /* 3) Truncate file */
- if (SetFilePointer(bin->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END) ==
INVALID_SET_FILE_POINTER)
- goto cleanup;
- if (!SetEndOfFile(bin->hInfo))
- goto cleanup;
- ret = TRUE;
+ return hr;
+}
+
+HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown)
+{
+ struct RecycleBin5 *s = NULL;
+ DWORD FileSystemFlags;
+ LPCWSTR RecycleBinDirectory;
+ HANDLE tokenHandle = INVALID_HANDLE_VALUE;
+ PTOKEN_USER TokenUserInfo = NULL;
+ LPWSTR StringSid = NULL, p;
+ SIZE_T Needed, DirectoryLength;
+ INT len;
+ HRESULT hr;
+
+ if (!ppUnknown)
+ return E_POINTER;
+
+ /* Get information about file system */
+ if (!GetVolumeInformationW(
+ VolumePath,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ &FileSystemFlags,
+ NULL,
+ 0))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ 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))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ if (GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &Needed))
+ {
+ hr = E_FAIL;
+ goto cleanup;
+ }
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed);
+ if (!TokenUserInfo)
+ {
+ hr = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+ if (!GetTokenInformation(tokenHandle, TokenUser, TokenUserInfo, (DWORD)Needed,
&Needed))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ if (!ConvertSidToStringSidW(TokenUserInfo->User.Sid, &StringSid))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ }
+
+ DirectoryLength = wcslen(VolumePath) + wcslen(RecycleBinDirectory) + 1;
+ if (StringSid)
+ DirectoryLength += wcslen(StringSid) + 1;
+ DirectoryLength += 1 + wcslen(RECYCLE_BIN_FILE_NAME);
+ DirectoryLength += wcslen(VolumePath) + 1;
+ Needed = (DirectoryLength + 1) * sizeof(WCHAR);
+
+ s = CoTaskMemAlloc(sizeof(struct RecycleBin5) + Needed);
+ if (!s)
+ {
+ hr = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+ ZeroMemory(s, sizeof(struct RecycleBin5));
+ s->recycleBinImpl.lpVtbl = &RecycleBin5Vtbl;
+ s->ref = 1;
+ if (StringSid)
+ len = swprintf(s->Folder, L"%s%s\\%s", VolumePath, RecycleBinDirectory,
StringSid);
+ else
+ len = swprintf(s->Folder, L"%s%s", VolumePath, RecycleBinDirectory);
+ p = &s->Folder[len];
+ wcscpy(p, L"\\" RECYCLE_BIN_FILE_NAME);
+ s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
+ if (s->hInfo == INVALID_HANDLE_VALUE && (GetLastError() ==
ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND))
+ {
+ *p = UNICODE_NULL;
+ hr = RecycleBin5_Create(s->Folder, TokenUserInfo ? TokenUserInfo->User.Sid :
NULL);
+ *p = L'\\';
+ if (!SUCCEEDED(hr))
+ goto cleanup;
+ s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
+ }
+ if (s->hInfo == INVALID_HANDLE_VALUE)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT,
0, 0, NULL);
+ if (!s->hInfoMapped)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto cleanup;
+ }
+ *p = UNICODE_NULL;
+ s->VolumePath = p + 1;
+ wcscpy(s->VolumePath, VolumePath);
+
+ *ppUnknown = (IUnknown *)&s->recycleBinImpl;
+
+ hr = S_OK;
cleanup:
- HeapFree(GetProcessHeap(), 0, FullName);
- return ret;
-}
-
-static BOOL
-IntDeleteRecursive(
- IN LPCWSTR FullName)
-{
- DWORD RemovableAttributes = FILE_ATTRIBUTE_READONLY;
- DWORD FileAttributes;
- BOOL ret = FALSE;
-
- FileAttributes = GetFileAttributesW(FullName);
- if (FileAttributes == INVALID_FILE_ATTRIBUTES)
- {
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- ret = TRUE;
- goto cleanup;
- }
- if (FileAttributes & RemovableAttributes)
- {
- if (!SetFileAttributesW(FullName, FileAttributes & ~RemovableAttributes))
- goto cleanup;
- }
- if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- /* Recursive deletion */
- /* FIXME: recursive deletion */
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- goto cleanup;
-
- if (!RemoveDirectoryW(FullName))
- goto cleanup;
- }
- else
- {
- if (!DeleteFileW(FullName))
- goto cleanup;
- }
- ret = TRUE;
-
-cleanup:
- return ret;
-}
-
-static BOOL
-IntEmptyRecycleBinCallback(
- IN PVOID Context,
- IN HANDLE hDeletedFile)
-{
- PRECYCLE_BIN bin = (PRECYCLE_BIN)Context;
- DELETED_FILE_RECORD DeletedFile;
- LPWSTR FullName = NULL;
- BOOL ret = FALSE;
-
- if (!IntSearchRecord(bin, hDeletedFile, &DeletedFile, NULL))
- goto cleanup;
-
- if (!IntGetFullName(bin, &DeletedFile, &FullName))
- goto cleanup;
-
- if (!IntDeleteRecursive(FullName))
- goto cleanup;
- ret = TRUE;
-
-cleanup:
- HeapFree(GetProcessHeap(), 0, FullName);
- return ret;
-}
-
-static BOOL
-IntGetFullName(
- IN PRECYCLE_BIN bin,
- IN PDELETED_FILE_RECORD pDeletedFile,
- OUT LPWSTR* pFullName)
-{
- SIZE_T Needed;
- LPCWSTR Extension;
- LPWSTR FullName = NULL;
- BOOL ret = FALSE;
-
- *pFullName = NULL;
- Extension = wcsrchr(pDeletedFile->FileNameW, '.');
- if (Extension < wcsrchr(pDeletedFile->FileNameW, '\\'))
- Extension = NULL;
- Needed = wcslen(bin->Folder) + 13;
- if (Extension)
- Needed += wcslen(Extension);
- FullName = HeapAlloc(GetProcessHeap(), 0, Needed * sizeof(WCHAR));
- if (!FullName)
- {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- goto cleanup;
- }
- wsprintfW(FullName, L"%s\\D%c%lu%s", bin->Folder,
pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId,
Extension);
- *pFullName = FullName;
- ret = TRUE;
-
-cleanup:
- if (!ret)
- HeapFree(GetProcessHeap(), 0, FullName);
- return ret;
-}
-
-static BOOL
-IntSearchRecord(
- IN PRECYCLE_BIN bin,
- IN HANDLE hDeletedFile,
- OUT PDELETED_FILE_RECORD pDeletedFile,
- OUT PLARGE_INTEGER Position OPTIONAL)
-{
- INFO2_HEADER Header;
- DELETED_FILE_RECORD DeletedFile;
- DWORD bytesRead, dwEntries;
- BOOL ret = FALSE;
-
- 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) || Header.dwRecordSize == 0)
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
-
- if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD))
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
-
- SetLastError(ERROR_SUCCESS);
- for (dwEntries = 0; dwEntries < Header.dwNumberOfEntries; dwEntries++)
- {
- if (Position)
- {
- LARGE_INTEGER Zero;
- Zero.QuadPart = 0;
- if (!SetFilePointerEx(bin->hInfo, Zero, Position, FILE_CURRENT))
- goto cleanup;
- }
- if (!ReadFile(bin->hInfo, &DeletedFile, Header.dwRecordSize, &bytesRead,
NULL))
- goto cleanup;
- if (bytesRead != Header.dwRecordSize)
- {
- SetLastError(ERROR_GEN_FAILURE);
- goto cleanup;
- }
- if (DeletedFile.dwRecordUniqueId == (DWORD)(ULONG_PTR)hDeletedFile)
- {
- memcpy(pDeletedFile, &DeletedFile, Header.dwRecordSize);
- ret = TRUE;
- goto cleanup;
- }
- }
-
- /* Entry not found */
- SetLastError(ERROR_INVALID_HANDLE);
-
-cleanup:
- return ret;
-}
+ if (tokenHandle != INVALID_HANDLE_VALUE)
+ CloseHandle(tokenHandle);
+ HeapFree(GetProcessHeap(), 0, TokenUserInfo);
+ if (StringSid)
+ LocalFree(StringSid);
+ if (!SUCCEEDED(hr))
+ {
+ if (s)
+ {
+ if (s->hInfo && s->hInfo != INVALID_HANDLE_VALUE)
+ CloseHandle(s->hInfo);
+ if (s->hInfoMapped)
+ CloseHandle(s->hInfoMapped);
+ CoTaskMemFree(s);
+ }
+ }
+ return hr;
+}
Modified: trunk/reactos/lib/recyclebin/recyclebin_v5.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin_v5.h (original)
+++ trunk/reactos/lib/recyclebin/recyclebin_v5.h Wed Oct 31 11:57:35 2007
@@ -4,6 +4,10 @@
*/
#include "recyclebin_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
#include <pshpack1.h>
@@ -20,57 +24,86 @@
#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
Added: trunk/reactos/lib/recyclebin/recyclebin_v5_enumerator.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_…
==============================================================================
--- trunk/reactos/lib/recyclebin/recyclebin_v5_enumerator.c (added)
+++ trunk/reactos/lib/recyclebin/recyclebin_v5_enumerator.c Wed Oct 31 11:57:35 2007
@@ -1,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(a)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;
+}
Propchange: trunk/reactos/lib/recyclebin/recyclebin_v5_enumerator.c
------------------------------------------------------------------------------
svn:eol-style = native
Removed: trunk/reactos/lib/recyclebin/refcount.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/recyclebin/refcount.c?…
==============================================================================
--- trunk/reactos/lib/recyclebin/refcount.c (original)
+++ trunk/reactos/lib/recyclebin/refcount.c (removed)
@@ -1,42 +1,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(a)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;
-}