Fix some bugs which were preventing enumeration of all deleted files
authorHervé Poussineau <hpoussin@reactos.org>
Wed, 31 Oct 2007 08:57:35 +0000 (08:57 +0000)
committerHervé Poussineau <hpoussin@reactos.org>
Wed, 31 Oct 2007 08:57:35 +0000 (08:57 +0000)
Add a system-wide recycle bin, which federates all individual recycle bins
Add a COM interface to the recycle bin library
Use COM ref counting instead of a house-made system

svn path=/trunk/; revision=29998

13 files changed:
reactos/lib/recyclebin/guid.c [new file with mode: 0644]
reactos/lib/recyclebin/openclose.c [deleted file]
reactos/lib/recyclebin/readme.txt
reactos/lib/recyclebin/recyclebin.c
reactos/lib/recyclebin/recyclebin.h
reactos/lib/recyclebin/recyclebin.rbuild
reactos/lib/recyclebin/recyclebin_generic.c [new file with mode: 0644]
reactos/lib/recyclebin/recyclebin_generic_enumerator.c [new file with mode: 0644]
reactos/lib/recyclebin/recyclebin_private.h
reactos/lib/recyclebin/recyclebin_v5.c
reactos/lib/recyclebin/recyclebin_v5.h
reactos/lib/recyclebin/recyclebin_v5_enumerator.c [new file with mode: 0644]
reactos/lib/recyclebin/refcount.c [deleted file]

diff --git a/reactos/lib/recyclebin/guid.c b/reactos/lib/recyclebin/guid.c
new file mode 100644 (file)
index 0000000..3080cf8
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * PROJECT:     Recycle bin management
+ * LICENSE:     GPL v2 - See COPYING in the top level directory
+ * FILE:        lib/recyclebin/guid.c
+ * PURPOSE:     Define GUID values
+ * PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+#define INITGUID
+#include <initguid.h>
+DEFINE_GUID(IID_IRecycleBin, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x80);
+DEFINE_GUID(IID_IRecycleBinEnumList, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x81);
+DEFINE_GUID(IID_IRecycleBinFile, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x82);
+DEFINE_GUID(IID_IRecycleBin5, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x83);
diff --git a/reactos/lib/recyclebin/openclose.c b/reactos/lib/recyclebin/openclose.c
deleted file mode 100644 (file)
index 760561e..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * PROJECT:     Recycle bin management
- * LICENSE:     GPL v2 - See COPYING in the top level directory
- * FILE:        lib/recyclebin/openclose.c
- * PURPOSE:     Open/close recycle bins
- * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
- */
-
-#include "recyclebin_private.h"
-
-BOOL
-IntCheckDeletedFileHandle(
-       IN HANDLE hDeletedFile)
-{
-       if (hDeletedFile == NULL || hDeletedFile == INVALID_HANDLE_VALUE)
-               return FALSE;
-
-       if (((PDELETED_FILE_HANDLE)hDeletedFile)->magic != DELETEDFILE_MAGIC)
-               return FALSE;
-
-       return TRUE;
-}
-
-static BOOL
-IntCloseRecycleBinHandle(
-       IN PREFCOUNT_DATA pData)
-{
-       PRECYCLE_BIN bin;
-
-       bin = CONTAINING_RECORD(pData, RECYCLE_BIN, refCount);
-       if (!CloseHandle(bin->hInfo))
-               return FALSE;
-
-       RemoveEntryList(&bin->ListEntry);
-       HeapFree(GetProcessHeap(), 0, bin);
-       return TRUE;
-}
-
-static BOOL
-IntCreateEmptyRecycleBin(
-       IN PRECYCLE_BIN bin,
-       IN PSID OwnerSid OPTIONAL)
-{
-       LPWSTR BufferName = NULL;
-       LPWSTR Separator; /* Pointer into BufferName buffer */
-       LPWSTR FileName; /* Pointer into BufferName buffer */
-       LPCSTR DesktopIniContents = "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
-       DWORD Info2Contents[] = { 5, 0, 0, 0x320, 0 };
-       SIZE_T BytesToWrite, BytesWritten, Needed;
-       HANDLE hFile = INVALID_HANDLE_VALUE;
-       BOOL ret = FALSE;
-
-       Needed = (wcslen(bin->Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR);
-       BufferName = HeapAlloc(GetProcessHeap(), 0, Needed);
-       if (!BufferName)
-       {
-               SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-               goto cleanup;
-       }
-
-       wcscpy(BufferName, bin->Folder);
-       Separator = wcsstr(&BufferName[3], L"\\");
-       if (Separator)
-               *Separator = UNICODE_NULL;
-       ret = CreateDirectoryW(BufferName, NULL);
-       if (!ret && GetLastError() != ERROR_ALREADY_EXISTS)
-               goto cleanup;
-       SetFileAttributesW(BufferName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-       if (Separator)
-       {
-               *Separator = L'\\';
-               ret = CreateDirectoryW(BufferName, NULL);
-               if (!ret && GetLastError() != ERROR_ALREADY_EXISTS)
-                       goto cleanup;
-       }
-
-       if (OwnerSid)
-       {
-               //DWORD rc;
-
-               /* Add ACL to allow only user/SYSTEM to open it */
-               /* FIXME: rc = SetNamedSecurityInfo(
-                       BufferName,
-                       SE_FILE_OBJECT,
-                       ???,
-                       OwnerSid,
-                       NULL,
-                       ???,
-                       ???);
-               if (rc != ERROR_SUCCESS)
-               {
-                       SetLastError(rc);
-                       goto cleanup;
-               }
-               */
-       }
-
-       wcscat(BufferName, L"\\");
-       FileName = &BufferName[wcslen(BufferName)];
-
-       /* Create desktop.ini */
-       wcscpy(FileName, L"desktop.ini");
-       hFile = CreateFileW(BufferName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL);
-       if (hFile == INVALID_HANDLE_VALUE)
-               goto cleanup;
-       BytesToWrite = strlen(DesktopIniContents);
-       ret = WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten, NULL);
-       if (!ret)
-               goto cleanup;
-       if (BytesWritten != BytesToWrite)
-       {
-               SetLastError(ERROR_GEN_FAILURE);
-               goto cleanup;
-       }
-       CloseHandle(hFile);
-       hFile = INVALID_HANDLE_VALUE;
-
-       /* Create empty INFO2 file */
-       wcscpy(FileName, RECYCLE_BIN_FILE_NAME);
-       hFile = CreateFileW(BufferName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
-       if (hFile == INVALID_HANDLE_VALUE)
-               goto cleanup;
-       BytesToWrite = sizeof(Info2Contents);
-       ret = WriteFile(hFile, Info2Contents, (DWORD)BytesToWrite, &BytesWritten, NULL);
-       if (!ret)
-               goto cleanup;
-       if (BytesWritten != BytesToWrite)
-       {
-               SetLastError(ERROR_GEN_FAILURE);
-               goto cleanup;
-       }
-
-       bin->hInfo = hFile;
-       ret = TRUE;
-
-cleanup:
-       HeapFree(GetProcessHeap(), 0, BufferName);
-       if (!ret)
-       {
-               if (hFile != INVALID_HANDLE_VALUE)
-                       CloseHandle(hFile);
-       }
-       return ret;
-}
-
-PRECYCLE_BIN
-IntReferenceRecycleBin(
-       IN WCHAR driveLetter)
-{
-       PLIST_ENTRY ListEntry;
-       PRECYCLE_BIN bin = NULL, ret = NULL;
-       WCHAR RootPath[4];
-       DWORD FileSystemFlags;
-       LPCWSTR RecycleBinDirectory;
-       HANDLE tokenHandle = INVALID_HANDLE_VALUE;
-       PTOKEN_USER TokenUserInfo = NULL;
-       LPWSTR StringSid = NULL;
-       SIZE_T Needed, DirectoryLength;
-       INFO2_HEADER Header;
-       BOOL AlreadyCreated = FALSE;
-       DWORD bytesRead;
-
-       static LIST_ENTRY ListHead;
-       static BOOL ListInitialized = FALSE;
-
-       if (!ListInitialized)
-       {
-               InitializeListHead(&ListHead);
-               ListInitialized = TRUE;
-       }
-
-       /* Search if the recycle bin has already been opened */
-       driveLetter = (WCHAR)toupper(driveLetter);
-       ListEntry = ListHead.Flink;
-       while (ListEntry != &ListHead)
-       {
-               bin = CONTAINING_RECORD(ListEntry, RECYCLE_BIN, ListEntry);
-               if (bin->Folder[0] == driveLetter)
-               {
-                       ReferenceHandle(&bin->refCount);
-                       return bin;
-               }
-               ListEntry = ListEntry->Flink;
-       }
-       bin = NULL;
-
-       /* We need to create a new recycle bin */
-
-       /* Get information about file system */
-       wsprintfW(RootPath, L"%c:\\", driveLetter);
-       if (!GetVolumeInformationW(
-               RootPath,
-               NULL,
-               0,
-               NULL,
-               NULL,
-               &FileSystemFlags,
-               NULL,
-               0))
-       {
-               goto cleanup;
-       }
-       if (!(FileSystemFlags & FILE_PERSISTENT_ACLS))
-               RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL;
-       else
-       {
-               RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL;
-
-               /* Get user SID */
-               if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle))
-                       goto cleanup;
-               if (GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &Needed))
-               {
-                       SetLastError(ERROR_GEN_FAILURE);
-                       goto cleanup;
-               }
-               if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-                       goto cleanup;
-               TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed);
-               if (!TokenUserInfo)
-               {
-                       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                       goto cleanup;
-               }
-               if (!GetTokenInformation(tokenHandle, TokenUser, TokenUserInfo, (DWORD)Needed, &Needed))
-                       goto cleanup;
-               if (!ConvertSidToStringSidW(TokenUserInfo->User.Sid, &StringSid))
-                       goto cleanup;
-       }
-
-       /* Create RECYCLEBIN structure */
-openfile:
-       DirectoryLength = 3 + wcslen(RecycleBinDirectory) + 1;
-       if (StringSid)
-               DirectoryLength += wcslen(StringSid) + 1;
-       Needed = FIELD_OFFSET(RECYCLE_BIN, Folder) + (2 * DirectoryLength + 2 + wcslen(RECYCLE_BIN_FILE_NAME))* sizeof(WCHAR);
-       bin = HeapAlloc(GetProcessHeap(), 0, Needed);
-       if (!bin)
-       {
-               SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-               goto cleanup;
-       }
-       memset(bin, 0, Needed);
-       InitializeHandle(&bin->refCount, IntCloseRecycleBinHandle);
-       bin->magic = RECYCLEBIN_MAGIC;
-       bin->hInfo = INVALID_HANDLE_VALUE;
-       bin->InfoFile = &bin->Folder[DirectoryLength];
-       bin->Folder[0] = driveLetter;
-       bin->Folder[1] = '\0';
-       wcscat(bin->Folder, L":\\");
-       wcscat(bin->Folder, RecycleBinDirectory);
-       if (StringSid)
-       {
-               wcscat(bin->Folder, L"\\");
-               wcscat(bin->Folder, StringSid);
-       }
-       wcscpy(bin->InfoFile, bin->Folder);
-       wcscat(bin->InfoFile, L"\\");
-       wcscat(bin->InfoFile, RECYCLE_BIN_FILE_NAME);
-       InsertTailList(&ListHead, &bin->ListEntry);
-
-       /* Open info file */
-       bin->hInfo = CreateFileW(bin->InfoFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
-       if (bin->hInfo == INVALID_HANDLE_VALUE)
-       {
-               if (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND)
-               {
-                       if (!IntCreateEmptyRecycleBin(bin, TokenUserInfo ? TokenUserInfo->User.Sid : NULL))
-                               goto cleanup;
-                       AlreadyCreated = TRUE;
-               }
-       }
-       if (bin->hInfo == INVALID_HANDLE_VALUE)
-               goto cleanup;
-
-       if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
-               goto cleanup;
-       if (!ReadFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesRead, NULL))
-               goto cleanup;
-       if (bytesRead != sizeof(INFO2_HEADER) && !AlreadyCreated)
-       {
-               /* Create a new file */
-               if (!DereferenceHandle(&bin->refCount))
-                       goto cleanup;
-               if (!DeleteFileW(bin->InfoFile))
-                       goto cleanup;
-               goto openfile;
-       }
-       switch (Header.dwVersion)
-       {
-               case 5:
-                       InitializeCallbacks5(&bin->Callbacks);
-                       break;
-               default:
-                       /* Unknown recycle bin version */
-                       SetLastError(ERROR_NOT_SUPPORTED);
-                       goto cleanup;
-       }
-
-       ret = bin;
-
-cleanup:
-       if (tokenHandle != INVALID_HANDLE_VALUE)
-               CloseHandle(tokenHandle);
-       HeapFree(GetProcessHeap(), 0, TokenUserInfo);
-       if (StringSid)
-               LocalFree(StringSid);
-       if (!ret)
-       {
-               if (bin && bin->hInfo != INVALID_HANDLE_VALUE)
-                       DereferenceHandle(&bin->refCount);
-               HeapFree(GetProcessHeap(), 0, bin);
-       }
-       return ret;
-}
index 5e7668f..9cbc6ed 100644 (file)
@@ -1,7 +1,6 @@
 This library deals with Recycle bin.
 It is aimed to be compatible with Windows 2000/XP/2003 (at least) on FAT or NTFS volumes.
 
-
 TODO
 - Empty a recycle bin containing directories (v5)
 - Set security on recycle bin folder
@@ -9,7 +8,6 @@ TODO
 - Make the library thread-safe
 
 3 levels
-- 1:  recyclebin.c:   Public interface
-- 2a: openclose.c:    Open/close recycle bins
-- 2b: refcount.c:     Do reference counting on objects
-- 3: recyclebin_v5.c: Deals with recycle bins of Windows 2000/XP/2003
\ No newline at end of file
+- 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
\ No newline at end of file
index 51bf5e1..ebc2717 100644 (file)
@@ -1,35 +1,30 @@
 /*
  * PROJECT:     Recycle bin management
  * LICENSE:     GPL v2 - See COPYING in the top level directory
- * FILE:        lib/recyclebin/openclose.c
+ * FILE:        lib/recyclebin/recyclebin.c
  * PURPOSE:     Public interface
- * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
  */
 
+#define COBJMACROS
 #include "recyclebin_private.h"
-
-typedef struct _ENUMERATE_RECYCLE_BIN_CONTEXT
-{
-       PRECYCLE_BIN bin;
-       PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback;
-       PVOID Context;
-} ENUMERATE_RECYCLE_BIN_CONTEXT, *PENUMERATE_RECYCLE_BIN_CONTEXT;
+#include <stdio.h>
 
 BOOL WINAPI
 CloseRecycleBinHandle(
        IN HANDLE hDeletedFile)
 {
-       BOOL ret = FALSE;
-
-       if (!IntCheckDeletedFileHandle(hDeletedFile))
-               SetLastError(ERROR_INVALID_HANDLE);
+       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
-       {
-               PDELETED_FILE_HANDLE file = (PDELETED_FILE_HANDLE)hDeletedFile;
-               ret = DereferenceHandle(&file->refCount);
-       }
-
-       return ret;
+               SetLastError(ERROR_GEN_FAILURE);
+       return FALSE;
 }
 
 BOOL WINAPI
@@ -70,89 +65,78 @@ BOOL WINAPI
 DeleteFileToRecycleBinW(
        IN LPCWSTR FileName)
 {
-       LPWSTR FullFileName = NULL;
-       DWORD dwBufferLength = 0;
-       LPWSTR lpFilePart;
-       DWORD len;
-       PRECYCLE_BIN bin = NULL;
-       BOOL ret = FALSE;
+       IRecycleBin *prb;
+       HRESULT hr;
 
-       /* Check parameters */
-       if (FileName == NULL)
-       {
-               SetLastError(ERROR_INVALID_PARAMETER);
+       hr = GetDefaultRecycleBin(NULL, &prb);
+       if (!SUCCEEDED(hr))
                goto cleanup;
-       }
 
-       /* Get full file name */
-       while (TRUE)
+       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;
+
+       if (pszRoot)
        {
-               len = GetFullPathNameW(FileName, dwBufferLength, FullFileName, &lpFilePart);
+               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 (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
+                       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);
+       ret = EmptyRecycleBinW(szRootW);
 
 cleanup:
-       HeapFree(GetProcessHeap(), 0, FullFileName);
-       if (bin)
-               DereferenceHandle(&bin->refCount);
+       HeapFree(GetProcessHeap(), 0, szRootW);
        return ret;
 }
 
-BOOL WINAPI
-EmptyRecycleBinA(
-       IN CHAR driveLetter)
-{
-       return EmptyRecycleBinW((WCHAR)driveLetter);
-}
-
 BOOL WINAPI
 EmptyRecycleBinW(
-       IN WCHAR driveLetter)
+       IN LPCWSTR pszRoot OPTIONAL)
 {
-       PRECYCLE_BIN bin = NULL;
-       BOOL ret = FALSE;
+       IRecycleBin *prb;
+       HRESULT hr;
 
-       /* Open recycle bin */
-       bin = IntReferenceRecycleBin(driveLetter);
-       if (!bin)
+       hr = GetDefaultRecycleBin(pszRoot, &prb);
+       if (!SUCCEEDED(hr))
                goto cleanup;
 
-       if (bin->Callbacks.EmptyRecycleBin)
-               ret = bin->Callbacks.EmptyRecycleBin(&bin);
-       else
-               SetLastError(ERROR_NOT_SUPPORTED);
+       hr = IRecycleBin_EmptyRecycleBin(prb);
+       IRecycleBin_Release(prb);
 
 cleanup:
-       if (bin)
-               DereferenceHandle(&bin->refCount);
-       return ret;
+       if (SUCCEEDED(hr))
+               return TRUE;
+       if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
+               SetLastError(HRESULT_CODE(hr));
+       else
+               SetLastError(ERROR_GEN_FAILURE);
+       return FALSE;
 }
 
 BOOL WINAPI
@@ -164,92 +148,54 @@ EnumerateRecycleBinA(
        return EnumerateRecycleBinW((WCHAR)driveLetter, pFnCallback, Context);
 }
 
-static BOOL
-IntCloseDeletedFileHandle(
-       IN PREFCOUNT_DATA pData)
-{
-       PDELETED_FILE_HANDLE file;
-
-       file = CONTAINING_RECORD(pData, DELETED_FILE_HANDLE, refCount);
-       if (!DereferenceHandle(&file->bin->refCount))
-               return FALSE;
-
-       file->magic = 0;
-       HeapFree(GetProcessHeap(), 0, file);
-       return TRUE;
-}
-
-static BOOL
-IntEnumerateRecycleBinCallback(
-       IN PVOID Context,
-       IN HANDLE hDeletedFile)
-{
-       PENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext = (PENUMERATE_RECYCLE_BIN_CONTEXT)Context;
-       PDELETED_FILE_HANDLE DeletedFileHandle = NULL;
-       BOOL ret = FALSE;
-
-       DeletedFileHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(DELETED_FILE_HANDLE));
-       if (!DeletedFileHandle)
-       {
-               SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-               goto cleanup;
-       }
-
-       ReferenceHandle(&CallbackContext->bin->refCount);
-       InitializeHandle(&DeletedFileHandle->refCount, IntCloseDeletedFileHandle);
-       DeletedFileHandle->magic = DELETEDFILE_MAGIC;
-       DeletedFileHandle->bin = CallbackContext->bin;
-       DeletedFileHandle->hDeletedFile = hDeletedFile;
-
-       ret = CallbackContext->pFnCallback(CallbackContext->Context, DeletedFileHandle);
-
-cleanup:
-       if (!ret)
-       {
-               if (DeletedFileHandle)
-                       DereferenceHandle(&DeletedFileHandle->refCount);
-       }
-       return ret;
-}
-
 BOOL WINAPI
 EnumerateRecycleBinW(
        IN WCHAR driveLetter,
        IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
        IN PVOID Context OPTIONAL)
 {
-       PRECYCLE_BIN bin = NULL;
-       BOOL ret = FALSE;
+       IRecycleBin *prb = NULL;
+       IRecycleBinEnumList *prbel = NULL;
+       IRecycleBinFile *prbf;
+       HRESULT hr;
 
-       /* Check parameters */
-       if (pFnCallback == NULL)
-       {
-               SetLastError(ERROR_INVALID_PARAMETER);
+       hr = GetDefaultRecycleBin(NULL, &prb);
+       if (!SUCCEEDED(hr))
                goto cleanup;
-       }
 
-       /* Open recycle bin */
-       bin = IntReferenceRecycleBin(driveLetter);
-       if (!bin)
+       hr = IRecycleBin_EnumObjects(prb, &prbel);
+       if (!SUCCEEDED(hr))
                goto cleanup;
-
-       if (bin->Callbacks.EnumerateFiles)
+       while (TRUE)
        {
-               ENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext;
-
-               CallbackContext.bin = bin;
-               CallbackContext.pFnCallback = pFnCallback;
-               CallbackContext.Context = Context;
-
-               ret = bin->Callbacks.EnumerateFiles(bin, IntEnumerateRecycleBinCallback, &CallbackContext);
+               hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
+               if (hr == S_FALSE)
+               {
+                       hr = S_OK;
+                       goto cleanup;
+               }
+               else if (!SUCCEEDED(hr))
+                       goto cleanup;
+               if (!pFnCallback(Context, (HANDLE)prbf))
+               {
+                       hr = HRESULT_FROM_WIN32(GetLastError());
+                       goto cleanup;
+               }
+               IRecycleBinFile_Release(prbf);
        }
-       else
-               SetLastError(ERROR_NOT_SUPPORTED);
 
 cleanup:
-       if (bin)
-               DereferenceHandle(&bin->refCount);
-       return ret;
+       if (prb)
+               IRecycleBin_Release(prb);
+       if (prbel)
+               IRecycleBinEnumList_Release(prb);
+       if (SUCCEEDED(hr))
+               return TRUE;
+       if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
+               SetLastError(HRESULT_CODE(hr));
+       else
+               SetLastError(ERROR_GEN_FAILURE);
+       return FALSE;
 }
 
 BOOL WINAPI
@@ -284,7 +230,7 @@ GetDeletedFileDetailsA(
 
        if (FileDetails)
        {
-               memcpy(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
+               CopyMemory(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
                if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL))
                        goto cleanup;
        }
@@ -302,38 +248,92 @@ GetDeletedFileDetailsW(
        IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
        OUT LPDWORD RequiredSize OPTIONAL)
 {
-       BOOL ret = FALSE;
+       IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
+       HRESULT hr;
+       SIZE_T NameSize, Needed;
 
-       if (!IntCheckDeletedFileHandle(hDeletedFile))
-               SetLastError(ERROR_INVALID_HANDLE);
-       else
+       hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
+       if (!SUCCEEDED(hr))
+               goto cleanup;
+       Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + NameSize;
+       if (RequiredSize)
+               *RequiredSize = (DWORD)Needed;
+       if (Needed > BufferSize)
        {
-               PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile;
-               if (DeletedFile->bin->Callbacks.GetDetails)
-                       ret = DeletedFile->bin->Callbacks.GetDetails(DeletedFile->bin, DeletedFile->hDeletedFile, BufferSize, FileDetails, RequiredSize);
-               else
-                       SetLastError(ERROR_NOT_SUPPORTED);
+               hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+               goto cleanup;
        }
+       hr = IRecycleBinFile_GetFileName(rbf, NameSize, FileDetails->FileName, NULL);
+       if (!SUCCEEDED(hr))
+               goto cleanup;
+       hr = IRecycleBinFile_GetLastModificationTime(rbf, &FileDetails->LastModification);
+       if (!SUCCEEDED(hr))
+               goto cleanup;
+       hr = IRecycleBinFile_GetDeletionTime(rbf, &FileDetails->DeletionTime);
+       if (!SUCCEEDED(hr))
+               goto cleanup;
+       hr = IRecycleBinFile_GetFileSize(rbf, &FileDetails->FileSize);
+       if (!SUCCEEDED(hr))
+               goto cleanup;
+       hr = IRecycleBinFile_GetPhysicalFileSize(rbf, &FileDetails->PhysicalFileSize);
+       if (!SUCCEEDED(hr))
+               goto cleanup;
+       hr = IRecycleBinFile_GetAttributes(rbf, &FileDetails->Attributes);
+       if (!SUCCEEDED(hr))
+               goto cleanup;
 
-       return ret;
+cleanup:
+       if (SUCCEEDED(hr))
+               return TRUE;
+       if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
+               SetLastError(HRESULT_CODE(hr));
+       else
+               SetLastError(ERROR_GEN_FAILURE);
+       return FALSE;
 }
 
 BOOL WINAPI
 RestoreFile(
        IN HANDLE hDeletedFile)
 {
-       BOOL ret = FALSE;
+       IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
+       HRESULT hr;
+
+       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;
+}
 
-       if (!IntCheckDeletedFileHandle(hDeletedFile))
-               SetLastError(ERROR_INVALID_HANDLE);
+HRESULT WINAPI
+GetDefaultRecycleBin(
+       IN LPCWSTR pszVolume OPTIONAL,
+       OUT IRecycleBin **pprb)
+{
+       IUnknown *pUnk;
+       HRESULT hr;
+
+       if (!pprb)
+               return E_POINTER;
+
+       if (!pszVolume)
+               hr = RecycleBinGeneric_Constructor(&pUnk);
        else
        {
-               PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile;
-               if (DeletedFile->bin->Callbacks.RestoreFile)
-                       ret = DeletedFile->bin->Callbacks.RestoreFile(DeletedFile->bin, DeletedFile->hDeletedFile);
-               else
-                       SetLastError(ERROR_NOT_SUPPORTED);
-       }
+               /* FIXME: do a better validation! */
+               if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
+                       return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
 
-       return ret;
+               /* For now, only support this type of recycle bins... */
+               hr = RecycleBin5_Constructor(pszVolume, &pUnk);
+       }
+       if (!SUCCEEDED(hr))
+               return hr;
+       hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBin, (void **)pprb);
+       IUnknown_Release(pUnk);
+       return hr;
 }
index a6ba9a9..0c55cce 100644 (file)
@@ -54,10 +54,10 @@ DeleteFileToRecycleBinW(
 
 BOOL WINAPI
 EmptyRecycleBinA(
-       IN CHAR driveLetter);
+       IN LPCSTR pszRoot);
 BOOL WINAPI
 EmptyRecycleBinW(
-       IN WCHAR driveLetter);
+       IN LPCWSTR pszRoot);
 #ifdef UNICODE
 #define EmptyRecycleBin EmptyRecycleBinW
 #else
@@ -102,6 +102,190 @@ BOOL WINAPI
 RestoreFile(
        IN HANDLE hDeletedFile);
 
+/* COM interface */
+
+typedef interface IRecycleBinFile IRecycleBinFile;
+EXTERN_C const IID IID_IRecycleBinFile;
+
+typedef struct IRecycleBinFileVtbl
+{
+       HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+               IN IRecycleBinFile *This,
+               IN REFIID riid,
+               OUT void **ppvObject);
+
+       ULONG (STDMETHODCALLTYPE *AddRef)(
+               IN IRecycleBinFile *This);
+
+       ULONG (STDMETHODCALLTYPE *Release)(
+               IN IRecycleBinFile *This);
+
+       HRESULT (STDMETHODCALLTYPE *GetLastModificationTime)(
+               IN IRecycleBinFile *This,
+               OUT FILETIME *pLastModificationTime);
+
+       HRESULT (STDMETHODCALLTYPE *GetDeletionTime)(
+               IN IRecycleBinFile *This,
+               OUT FILETIME *pDeletionTime);
+
+       HRESULT (STDMETHODCALLTYPE *GetFileSize)(
+               IN IRecycleBinFile *This,
+               OUT ULARGE_INTEGER *pFileSize);
+
+       HRESULT (STDMETHODCALLTYPE *GetPhysicalFileSize)(
+               IN IRecycleBinFile *This,
+               OUT ULARGE_INTEGER *pPhysicalFileSize);
+
+       HRESULT (STDMETHODCALLTYPE *GetAttributes)(
+               IN IRecycleBinFile *This,
+               OUT DWORD *pAttributes);
+
+       HRESULT (STDMETHODCALLTYPE *GetFileName)(
+               IN IRecycleBinFile *This,
+               IN SIZE_T BufferSize,
+               IN OUT LPWSTR Buffer,
+               OUT SIZE_T *RequiredSize);
+
+       HRESULT (STDMETHODCALLTYPE *Delete)(
+               IN IRecycleBinFile *This);
+
+       HRESULT (STDMETHODCALLTYPE *Restore)(
+               IN IRecycleBinFile *This);
+} IRecycleBinFileVtbl;
+
+interface IRecycleBinFile
+{
+       CONST_VTBL struct IRecycleBinFileVtbl *lpVtbl;
+};
+
+#ifdef COBJMACROS
+#define IRecycleBinFile_QueryInterface(This, riid, ppvObject) \
+       (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
+#define IRecycleBinFile_AddRef(This) \
+       (This)->lpVtbl->AddRef(This)
+#define IRecycleBinFile_Release(This) \
+       (This)->lpVtbl->Release(This)
+#define IRecycleBinFile_GetLastModificationTime(This, pLastModificationTime) \
+       (This)->lpVtbl->GetLastModificationTime(This, pLastModificationTime)
+#define IRecycleBinFile_GetDeletionTime(This, pDeletionTime) \
+       (This)->lpVtbl->GetDeletionTime(This, pDeletionTime)
+#define IRecycleBinFile_GetFileSize(This, pFileSize) \
+       (This)->lpVtbl->GetFileSize(This, pFileSize)
+#define IRecycleBinFile_GetPhysicalFileSize(This, pPhysicalFileSize) \
+       (This)->lpVtbl->GetPhysicalFileSize(This, pPhysicalFileSize)
+#define IRecycleBinFile_GetAttributes(This, pAttributes) \
+       (This)->lpVtbl->GetAttributes(This, pAttributes)
+#define IRecycleBinFile_GetFileName(This, BufferSize, Buffer, RequiredSize) \
+       (This)->lpVtbl->GetFileName(This, BufferSize, Buffer, RequiredSize)
+#define IRecycleBinFile_Delete(This) \
+       (This)->lpVtbl->Delete(This)
+#define IRecycleBinFile_Restore(This) \
+       (This)->lpVtbl->Restore(This)
+#endif
+
+typedef interface IRecycleBinEnumList IRecycleBinEnumList;
+EXTERN_C const IID IID_IRecycleBinEnumList;
+
+typedef struct IRecycleBinEnumListVtbl
+{
+       HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+               IN IRecycleBinEnumList *This,
+               IN REFIID riid,
+               OUT void **ppvObject);
+
+       ULONG (STDMETHODCALLTYPE *AddRef)(
+               IN IRecycleBinEnumList *This);
+
+       ULONG (STDMETHODCALLTYPE *Release)(
+               IN IRecycleBinEnumList *This);
+
+       HRESULT (STDMETHODCALLTYPE *Next)(
+               IN IRecycleBinEnumList *This,
+               IN DWORD celt,
+               IN OUT IRecycleBinFile **rgelt,
+               OUT DWORD *pceltFetched);
+
+       HRESULT (STDMETHODCALLTYPE *Skip)(
+               IN IRecycleBinEnumList *This,
+               IN DWORD celt);
+
+       HRESULT (STDMETHODCALLTYPE *Reset)(
+               IN IRecycleBinEnumList *This);
+} IRecycleBinEnumListVtbl;
+
+interface IRecycleBinEnumList
+{
+       CONST_VTBL struct IRecycleBinEnumListVtbl *lpVtbl;
+};
+
+#ifdef COBJMACROS
+#define IRecycleBinEnumList_QueryInterface(This, riid, ppvObject) \
+       (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
+#define IRecycleBinEnumList_AddRef(This) \
+       (This)->lpVtbl->AddRef(This)
+#define IRecycleBinEnumList_Release(This) \
+       (This)->lpVtbl->Release(This)
+#define IRecycleBinEnumList_Next(This, celt, rgelt, pceltFetched) \
+       (This)->lpVtbl->Next(This, celt, rgelt, pceltFetched)
+#define IRecycleBinEnumList_Skip(This, celt) \
+       (This)->lpVtbl->Skip(This, celt)
+#define IRecycleBinEnumList_Reset(This) \
+       (This)->lpVtbl->Reset(This)
+#endif
+
+typedef interface IRecycleBin IRecycleBin;
+EXTERN_C const IID IID_IRecycleBin;
+
+typedef struct IRecycleBinVtbl
+{
+       HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+               IN IRecycleBin *This,
+               IN REFIID riid,
+               OUT void **ppvObject);
+
+       ULONG (STDMETHODCALLTYPE *AddRef)(
+               IN IRecycleBin *This);
+
+       ULONG (STDMETHODCALLTYPE *Release)(
+               IN IRecycleBin *This);
+
+       HRESULT (STDMETHODCALLTYPE *DeleteFile)(
+               IN IRecycleBin *This,
+               IN LPCWSTR szFileName);
+
+       HRESULT (STDMETHODCALLTYPE *EmptyRecycleBin)(
+               IN IRecycleBin *This);
+
+       HRESULT (STDMETHODCALLTYPE *EnumObjects)(
+               IN IRecycleBin *This,
+               OUT IRecycleBinEnumList **ppEnumList);
+} IRecycleBinVtbl;
+
+interface IRecycleBin
+{
+       CONST_VTBL struct IRecycleBinVtbl *lpVtbl;
+};
+
+#ifdef COBJMACROS
+#define IRecycleBin_QueryInterface(This, riid, ppvObject) \
+       (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
+#define IRecycleBin_AddRef(This) \
+       (This)->lpVtbl->AddRef(This)
+#define IRecycleBin_Release(This) \
+       (This)->lpVtbl->Release(This)
+#define IRecycleBin_DeleteFile(This, szFileName) \
+       (This)->lpVtbl->DeleteFile(This, szFileName)
+#define IRecycleBin_EmptyRecycleBin(This) \
+       (This)->lpVtbl->EmptyRecycleBin(This)
+#define IRecycleBin_EnumObjects(This, ppEnumList) \
+       (This)->lpVtbl->EnumObjects(This, ppEnumList)
+#endif
+
+HRESULT WINAPI
+GetDefaultRecycleBin(
+       IN LPCWSTR pszVolume OPTIONAL,
+       OUT IRecycleBin **pprb);
+
 #ifdef __cplusplus
 }
 #endif
index 158d6e6..3127c8b 100644 (file)
@@ -1,9 +1,10 @@
 <?xml version="1.0"?>
 <!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
 <module name="recyclebin" type="staticlibrary">
-       <define name="__USE_W32API" />
-       <file>openclose.c</file>
+       <file>guid.c</file>
        <file>recyclebin.c</file>
+       <file>recyclebin_generic.c</file>
+       <file>recyclebin_generic_enumerator.c</file>
        <file>recyclebin_v5.c</file>
-       <file>refcount.c</file>
+       <file>recyclebin_v5_enumerator.c</file>
 </module>
diff --git a/reactos/lib/recyclebin/recyclebin_generic.c b/reactos/lib/recyclebin/recyclebin_generic.c
new file mode 100644 (file)
index 0000000..8f8bc00
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * PROJECT:     Recycle bin management
+ * LICENSE:     GPL v2 - See COPYING in the top level directory
+ * FILE:        lib/recyclebin/recyclebin_generic.c
+ * PURPOSE:     Deals with a system-wide recycle bin
+ * PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+#define COBJMACROS
+#include "recyclebin_private.h"
+#include <stdio.h>
+
+struct RecycleBinGeneric
+{
+       ULONG ref;
+       IRecycleBin recycleBinImpl;
+};
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBinGenericVtbl_RecycleBin_QueryInterface( 
+       IRecycleBin *This,
+       REFIID riid,
+       void **ppvObject)
+{
+       struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
+
+       if (!ppvObject)
+               return E_POINTER;
+
+       if (IsEqualIID(riid, &IID_IUnknown))
+               *ppvObject = &s->recycleBinImpl;
+       else if (IsEqualIID(riid, &IID_IRecycleBin))
+               *ppvObject = &s->recycleBinImpl;
+       else
+       {
+               *ppvObject = NULL;
+               return E_NOINTERFACE;
+       }
+
+       IUnknown_AddRef(This);
+       return S_OK;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBinGenericVtbl_RecycleBin_AddRef(
+       IRecycleBin *This)
+{
+       struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
+       ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
+       return refCount;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBinGenericVtbl_RecycleBin_Release(
+       IRecycleBin *This)
+{
+       struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
+       ULONG refCount;
+
+       if (!This)
+               return E_POINTER;
+
+       refCount = InterlockedDecrement((PLONG)&s->ref);
+
+       if (refCount == 0)
+               CoTaskMemFree(s);
+
+       return refCount;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBinGenericVtbl_RecycleBin_DeleteFile(
+       IN IRecycleBin *This,
+       IN LPCWSTR szFileName)
+{
+       IRecycleBin *prb;
+       LPWSTR szFullName = NULL;
+       DWORD dwBufferLength = 0;
+       DWORD len;
+       WCHAR szVolume[MAX_PATH];
+       HRESULT hr;
+
+       /* Get full file name */
+       while (TRUE)
+       {
+               len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, NULL);
+               if (len == 0)
+               {
+                       if (szFullName)
+                               CoTaskMemFree(szFullName);
+                       return HRESULT_FROM_WIN32(GetLastError());
+               }
+               else if (len < dwBufferLength)
+                       break;
+               if (szFullName)
+                       CoTaskMemFree(szFullName);
+               dwBufferLength = len;
+               szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
+               if (!szFullName)
+                       return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+       }
+
+       /* Get associated volume path */
+#ifndef __REACTOS__
+       if (!GetVolumePathNameW(szFullName, szVolume, MAX_PATH))
+       {
+               CoTaskMemFree(szFullName);
+               return HRESULT_FROM_WIN32(GetLastError());
+       }
+#else
+       swprintf(szVolume, L"%c:\\", szFullName[0]);
+#endif
+
+       /* Skip namespace (if any) */
+       if (szVolume[0] == '\\'
+        && szVolume[1] == '\\'
+        && (szVolume[2] == '.' || szVolume[2] == '?')
+        && szVolume[3] == '\\')
+       {
+               MoveMemory(szVolume, &szVolume[4], (MAX_PATH - 4) * sizeof(WCHAR));
+       }
+
+       hr = GetDefaultRecycleBin(szVolume, &prb);
+       if (!SUCCEEDED(hr))
+       {
+               CoTaskMemFree(szFullName);
+               return hr;
+       }
+
+       hr = IRecycleBin_DeleteFile(prb, szFullName);
+       CoTaskMemFree(szFullName);
+       IRecycleBin_Release(prb);
+       return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin(
+       IN IRecycleBin *This)
+{
+       WCHAR szVolumeName[MAX_PATH];
+       DWORD dwLogicalDrives, i;
+       IRecycleBin *prb;
+       HRESULT hr;
+
+       dwLogicalDrives = GetLogicalDrives();
+       if (dwLogicalDrives == 0)
+               return HRESULT_FROM_WIN32(GetLastError());
+
+       for (i = 0; i < 26; i++)
+       {
+               if (!(dwLogicalDrives & (1 << i)))
+                       continue;
+               swprintf(szVolumeName, L"%c:\\", 'A' + i);
+               if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
+                       continue;
+               
+               hr = GetDefaultRecycleBin(szVolumeName, &prb);
+               if (!SUCCEEDED(hr))
+                       return hr;
+
+               hr = IRecycleBin_EmptyRecycleBin(prb);
+               IRecycleBin_Release(prb);
+       }
+
+       return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBinGenericVtbl_RecycleBin_EnumObjects(
+       IN IRecycleBin *This,
+       OUT IRecycleBinEnumList **ppEnumList)
+{
+       return RecycleBinGeneric_Enumerator_Constructor(ppEnumList);
+}
+
+CONST_VTBL struct IRecycleBinVtbl RecycleBinGenericVtbl =
+{
+       RecycleBinGenericVtbl_RecycleBin_QueryInterface,
+       RecycleBinGenericVtbl_RecycleBin_AddRef,
+       RecycleBinGenericVtbl_RecycleBin_Release,
+       RecycleBinGenericVtbl_RecycleBin_DeleteFile,
+       RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin,
+       RecycleBinGenericVtbl_RecycleBin_EnumObjects,
+};
+
+HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown)
+{
+       /* This RecycleBin implementation was introduced to be able to manage all
+        * drives at once, and instanciate the 'real' implementations when needed */
+       struct RecycleBinGeneric *s;
+
+       s = CoTaskMemAlloc(sizeof(struct RecycleBinGeneric));
+       if (!s)
+               return E_OUTOFMEMORY;
+       s->ref = 1;
+       s->recycleBinImpl.lpVtbl = &RecycleBinGenericVtbl;
+
+       *ppUnknown = (IUnknown *)&s->recycleBinImpl;
+       return S_OK;
+}
diff --git a/reactos/lib/recyclebin/recyclebin_generic_enumerator.c b/reactos/lib/recyclebin/recyclebin_generic_enumerator.c
new file mode 100644 (file)
index 0000000..f7b2a40
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * PROJECT:     Recycle bin management
+ * LICENSE:     GPL v2 - See COPYING in the top level directory
+ * FILE:        lib/recyclebin/recyclebin_generic_enumerator.c
+ * PURPOSE:     Enumerates contents of all recycle bins
+ * PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+#define COBJMACROS
+#include "recyclebin.h"
+#include <stdio.h>
+
+struct RecycleBinGenericEnum
+{
+       ULONG ref;
+       IRecycleBinEnumList recycleBinEnumImpl;
+       IRecycleBinEnumList *current;
+       DWORD dwLogicalDrives;
+       SIZE_T skip;
+};
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBinGenericEnum_RecycleBinEnumList_QueryInterface(
+       IN IRecycleBinEnumList *This,
+       IN REFIID riid,
+       OUT void **ppvObject)
+{
+       struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
+
+       if (!ppvObject)
+               return E_POINTER;
+
+       if (IsEqualIID(riid, &IID_IUnknown))
+               *ppvObject = &s->recycleBinEnumImpl;
+       else if (IsEqualIID(riid, &IID_IRecycleBinEnumList))
+               *ppvObject = &s->recycleBinEnumImpl;
+       else
+       {
+               *ppvObject = NULL;
+               return E_NOINTERFACE;
+       }
+
+       IUnknown_AddRef(This);
+       return S_OK;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBinGenericEnum_RecycleBinEnumList_AddRef(
+       IN IRecycleBinEnumList *This)
+{
+       struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
+       ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
+       return refCount;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBinGenericEnum_RecycleBinEnumList_Release(
+       IN IRecycleBinEnumList *This)
+{
+       struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
+       ULONG refCount;
+
+       if (!This)
+               return E_POINTER;
+
+       refCount = InterlockedDecrement((PLONG)&s->ref);
+
+       if (refCount == 0)
+       {
+               if (s->current)
+                       IRecycleBinEnumList_Release(s->current);
+               CoTaskMemFree(s);
+       }
+
+       return refCount;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBinGenericEnum_RecycleBinEnumList_Next(
+       IN IRecycleBinEnumList *This,
+       IN DWORD celt,
+       IN OUT IRecycleBinFile **rgelt,
+       OUT DWORD *pceltFetched)
+{
+       struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
+       IRecycleBin *prb;
+       DWORD i;
+       DWORD fetched = 0, newFetched;
+       HRESULT hr;
+
+       if (!rgelt)
+               return E_POINTER;
+       if (!pceltFetched && celt > 1)
+               return E_INVALIDARG;
+
+       while (TRUE)
+       {
+               /* Get enumerator implementation */
+               if (!s->current && s->dwLogicalDrives)
+               {
+                       for (i = 0; i < 26; i++)
+                               if (s->dwLogicalDrives & (1 << i))
+                               {
+                                       WCHAR szVolumeName[4];
+                                       szVolumeName[0] = (WCHAR)('A' + i);
+                                       szVolumeName[1] = ':';
+                                       szVolumeName[2] = '\\';
+                                       szVolumeName[3] = UNICODE_NULL;
+                                       if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
+                                       {
+                                               s->dwLogicalDrives &= ~(1 << i);
+                                               continue;
+                                       }
+                                       hr = GetDefaultRecycleBin(szVolumeName, &prb);
+                                       if (!SUCCEEDED(hr))
+                                               return hr;
+                                       hr = IRecycleBin_EnumObjects(prb, &s->current);
+                                       IRecycleBin_Release(prb);
+                                       if (!SUCCEEDED(hr))
+                                               return hr;
+                                       s->dwLogicalDrives &= ~(1 << i);
+                                       break;
+                               }
+               }
+               if (!s->current)
+               {
+                       /* Nothing more to enumerate */
+                       if (pceltFetched)
+                               *pceltFetched = fetched;
+                       return S_FALSE;
+               }
+
+               /* Skip some elements */
+               while (s->skip > 0)
+               {
+                       IRecycleBinFile *rbf;
+                       hr = IRecycleBinEnumList_Next(s->current, 1, &rbf, NULL);
+                       if (hr == S_OK)
+                               hr = IRecycleBinFile_Release(rbf);
+                       else if (hr == S_FALSE)
+                               break;
+                       else if (!SUCCEEDED(hr))
+                               return hr;
+               }
+               if (s->skip > 0)
+                       continue;
+
+               /* Fill area */
+               hr = IRecycleBinEnumList_Next(s->current, celt - fetched, &rgelt[fetched], &newFetched);
+               if (SUCCEEDED(hr))
+                       fetched += newFetched;
+               if (hr == S_FALSE || newFetched == 0)
+               {
+                       hr = IRecycleBinEnumList_Release(s->current);
+                       s->current = NULL;
+               }
+               else if (!SUCCEEDED(hr))
+                       return hr;
+               if (fetched == celt)
+               {
+                       if (pceltFetched)
+                               *pceltFetched = fetched;
+                       return S_OK;
+               }
+       }
+
+       /* Never go here */
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBinGenericEnum_RecycleBinEnumList_Skip(
+       IN IRecycleBinEnumList *This,
+       IN DWORD celt)
+{
+       struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
+       s->skip += celt;
+       return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBinGenericEnum_RecycleBinEnumList_Reset(
+       IN IRecycleBinEnumList *This)
+{
+       struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
+
+       if (s->current)
+       {
+               IRecycleBinEnumList_Release(s->current);
+               s->current = NULL;
+               s->skip = 0;
+       }
+       s->dwLogicalDrives = GetLogicalDrives();
+       return S_OK;
+}
+
+CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBinGenericEnumVtbl =
+{
+       RecycleBinGenericEnum_RecycleBinEnumList_QueryInterface,
+       RecycleBinGenericEnum_RecycleBinEnumList_AddRef,
+       RecycleBinGenericEnum_RecycleBinEnumList_Release,
+       RecycleBinGenericEnum_RecycleBinEnumList_Next,
+       RecycleBinGenericEnum_RecycleBinEnumList_Skip,
+       RecycleBinGenericEnum_RecycleBinEnumList_Reset,
+};
+
+HRESULT
+RecycleBinGeneric_Enumerator_Constructor(
+       OUT IRecycleBinEnumList **pprbel)
+{
+       struct RecycleBinGenericEnum *s;
+
+       s = CoTaskMemAlloc(sizeof(struct RecycleBinGenericEnum));
+       if (!s)
+               return E_OUTOFMEMORY;
+       ZeroMemory(s, sizeof(struct RecycleBinGenericEnum));
+       s->ref = 1;
+       s->recycleBinEnumImpl.lpVtbl = &RecycleBinGenericEnumVtbl;
+
+       *pprbel = &s->recycleBinEnumImpl;
+       return IRecycleBinEnumList_Reset(*pprbel);
+}
index 004733f..fea57a7 100644 (file)
 #define RemoveEntryList(Entry)  { PLIST_ENTRY _EX_Blink, _EX_Flink; _EX_Flink = (Entry)->Flink; _EX_Blink = (Entry)->Blink; _EX_Blink->Flink = _EX_Flink; _EX_Flink->Blink = _EX_Blink; }
 
 /* Typedefs */
-struct _RECYCLE_BIN;
-typedef struct _RECYCLE_BIN *PRECYCLE_BIN;
-struct _REFCOUNT_DATA;
-typedef struct _REFCOUNT_DATA *PREFCOUNT_DATA;
-
-typedef BOOL (*PINT_ENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context OPTIONAL, IN HANDLE hDeletedFile);
-typedef BOOL (*PDESTROY_DATA)    (IN PREFCOUNT_DATA pData);
-
-typedef BOOL (*PCLOSE_HANDLE)    (IN HANDLE hHandle);
-typedef BOOL (*PDELETE_FILE)     (IN PRECYCLE_BIN bin, IN LPCWSTR FullPath, IN LPCWSTR FileName);
-typedef BOOL (*PEMPTY_RECYCLEBIN)(IN PRECYCLE_BIN* bin);
-typedef BOOL (*PENUMERATE_FILES) (IN PRECYCLE_BIN bin, IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, IN PVOID Context OPTIONAL);
-typedef BOOL (*PGET_DETAILS)     (IN PRECYCLE_BIN bin, IN HANDLE hDeletedFile, IN DWORD BufferSize, IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL, OUT LPDWORD RequiredSize OPTIONAL);
-typedef BOOL (*PRESTORE_FILE)    (IN PRECYCLE_BIN bin, IN HANDLE hDeletedFile);
-
-typedef struct _RECYCLEBIN_CALLBACKS
-{
-       PCLOSE_HANDLE     CloseHandle;
-       PDELETE_FILE      DeleteFile;
-       PEMPTY_RECYCLEBIN EmptyRecycleBin;
-       PENUMERATE_FILES  EnumerateFiles;
-       PGET_DETAILS      GetDetails;
-       PRESTORE_FILE     RestoreFile;
-} RECYCLEBIN_CALLBACKS, *PRECYCLEBIN_CALLBACKS;
-
-typedef struct _REFCOUNT_DATA
-{
-       DWORD ReferenceCount;
-       PDESTROY_DATA Close;
-} REFCOUNT_DATA;
-
-typedef struct _RECYCLE_BIN
-{
-       DWORD magic; /* RECYCLEBIN_MAGIC */
-       LIST_ENTRY ListEntry;
-       REFCOUNT_DATA refCount;
-       HANDLE hInfo;
-       RECYCLEBIN_CALLBACKS Callbacks;
-       LPWSTR InfoFile;
-       WCHAR Folder[ANY_SIZE]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */
-} RECYCLE_BIN;
-
-typedef struct _DELETED_FILE_HANDLE
-{
-       DWORD magic; /* DELETEDFILE_MAGIC */
-       REFCOUNT_DATA refCount;
-       PRECYCLE_BIN bin;
-       HANDLE hDeletedFile; /* specific to recycle bin format */
-} DELETED_FILE_HANDLE, *PDELETED_FILE_HANDLE;
 
 /* Structures on disk */
 
@@ -84,33 +35,14 @@ typedef struct _INFO2_HEADER
 
 /* Prototypes */
 
-/* openclose.c */
+/* recyclebin_generic.c */
 
-BOOL
-IntCheckDeletedFileHandle(
-       IN HANDLE hDeletedFile);
+HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown);
 
-PRECYCLE_BIN
-IntReferenceRecycleBin(
-       IN WCHAR driveLetter);
+/* recyclebin_generic_enumerator.c */
 
-/* recyclebin_v5.c */
-
-VOID
-InitializeCallbacks5(
-       IN OUT PRECYCLEBIN_CALLBACKS Callbacks);
-
-/* refcount.c */
+HRESULT RecycleBinGeneric_Enumerator_Constructor(OUT IRecycleBinEnumList **pprbel);
 
-BOOL
-InitializeHandle(
-       IN PREFCOUNT_DATA pData,
-       IN PDESTROY_DATA pFnClose OPTIONAL);
-
-BOOL
-ReferenceHandle(
-       IN PREFCOUNT_DATA pData);
+/* recyclebin_v5.c */
 
-BOOL
-DereferenceHandle(
-       IN PREFCOUNT_DATA pData);
+HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown);
index 87a8c41..f293243 100644 (file)
 /*
  * 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@reactos.org)
+ * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
  */
 
+#define COBJMACROS
 #include "recyclebin_v5.h"
+#include <stdio.h>
 
-VOID
-InitializeCallbacks5(
-       IN OUT PRECYCLEBIN_CALLBACKS Callbacks)
+static BOOL
+IntDeleteRecursive(
+       IN LPCWSTR FullName)
 {
-       Callbacks->CloseHandle     = CloseHandle5;
-       Callbacks->DeleteFile      = DeleteFile5;
-       Callbacks->EmptyRecycleBin = EmptyRecycleBin5;
-       Callbacks->EnumerateFiles  = EnumerateFiles5;
-       Callbacks->GetDetails      = GetDetails5;
-       Callbacks->RestoreFile     = RestoreFile5;
+       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
-CloseHandle5(
-       IN HANDLE hDeletedFile)
+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)
 {
-       UNREFERENCED_PARAMETER(hDeletedFile);
-       /* Nothing to do, as hDeletedFile is simply a DWORD... */
-       return TRUE;
+       struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+       ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
+       return refCount;
 }
 
-static BOOL
-DeleteFile5(
-       IN PRECYCLE_BIN bin,
-       IN LPCWSTR FullPath,
-       IN LPCWSTR FileName)
+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;
+       HRESULT hr;
 
-       if (wcslen(FullPath) >= MAX_PATH)
+       if (s->EnumeratorCount != 0)
+               return E_FAIL;
+
+       /* Get full file name */
+       while (TRUE)
        {
-               /* Unable to store a too long path in recycle bin */
-               SetLastError(ERROR_INVALID_NAME);
-               goto cleanup;
+               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);
        }
 
-       hFile = CreateFileW(FullPath, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+       /* 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)
+       {
+               hr = HRESULT_FROM_WIN32(GetLastError());
                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)
+       /* 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)
        {
-               SetLastError(ERROR_GEN_FAILURE);
+               hr = HRESULT_FROM_WIN32(GetLastError());
                goto cleanup;
        }
 
-       if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD))
+       /* Open INFO2 file */
+       pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
+       if (!pHeader)
        {
-               SetLastError(ERROR_GEN_FAILURE);
+               hr = HRESULT_FROM_WIN32(GetLastError());
                goto cleanup;
        }
+       pDeletedFile = ((PDELETED_FILE_RECORD)(pHeader + 1)) + pHeader->dwNumberOfEntries;
 
        /* Get file size */
 #if 0
-       if (!GetFileSizeEx(hFile, &fileSize))
+       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)
+       {
+               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);
+               hr = E_NOTIMPL;
                goto cleanup;
        }
-       Header.dwTotalLogicalSize += fileSize.u.LowPart;
+       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))
+       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))
        {
-               SetLastError(ERROR_INVALID_NAME);
+               hr = HRESULT_FROM_WIN32(GetLastError());
                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);
+       pDeletedFile->dwPhysicalFileSize = ROUND_UP(fileSize.u.LowPart, ClusterSize);
 
-       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))
+       /* Set name */
+       wcscpy(pDeletedFile->FileNameW, szFullName);
+       if (WideCharToMultiByte(CP_ACP, 0, pDeletedFile->FileNameW, -1, pDeletedFile->FileNameA, MAX_PATH, NULL, NULL) == 0)
        {
-               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);
+               hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
+               SetLastError(ERROR_INVALID_NAME);
                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;
+       CoTaskMemFree(szFullName);
+       return hr;
 }
 
-static BOOL
-EmptyRecycleBin5(
-       IN PRECYCLE_BIN* bin)
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_EmptyRecycleBin(
+       IN IRecycleBin5 *This)
 {
-       LPWSTR InfoFile = NULL;
-       BOOL ret = FALSE;
+       IRecycleBinEnumList *prbel;
+       IRecycleBinFile *prbf;
+       HRESULT hr;
 
-       InfoFile = HeapAlloc(GetProcessHeap(), 0, wcslen((*bin)->InfoFile) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
-       if (!InfoFile)
+       while (TRUE)
        {
-               SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-               goto cleanup;
+               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;
        }
-       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;
-
-cleanup:
-       HeapFree(GetProcessHeap(), 0, InfoFile);
-       return ret;
 }
 
-static BOOL
-EnumerateFiles5(
-       IN PRECYCLE_BIN bin,
-       IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
-       IN PVOID Context OPTIONAL)
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_EnumObjects(
+       IN IRecycleBin5 *This,
+       OUT IRecycleBinEnumList **ppEnumList)
 {
-       INFO2_HEADER Header;
-       DELETED_FILE_RECORD DeletedFile;
-       DWORD bytesRead, dwEntries;
-       BOOL ret = FALSE;
+       struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+       IRecycleBinEnumList *prbel;
+       HRESULT hr;
+       IUnknown *pUnk;
 
-       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)
+       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))
        {
-               SetLastError(ERROR_GEN_FAILURE);
-               goto cleanup;
+               s->EnumeratorCount++;
+               *ppEnumList = prbel;
        }
+       IUnknown_Release(pUnk);
+       return hr;
+}
 
-       if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD))
+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)
        {
-               SetLastError(ERROR_GEN_FAILURE);
-               goto cleanup;
+               UnmapViewOfFile(pHeader);
+               return HRESULT_FROM_WIN32(GetLastError());
        }
+       dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
 
-       SetLastError(ERROR_SUCCESS);
-       for (dwEntries = 0; dwEntries < Header.dwNumberOfEntries; dwEntries++)
+       pRecord = (DELETED_FILE_RECORD *)(pHeader + 1);
+       for (i = 0; i < dwEntries; i++)
        {
-               if (!ReadFile(bin->hInfo, &DeletedFile, Header.dwRecordSize, &bytesRead, NULL))
-                       goto cleanup;
-               if (bytesRead != Header.dwRecordSize)
+               if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId)
                {
-                       SetLastError(ERROR_GEN_FAILURE);
-                       goto cleanup;
+                       /* 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;
                }
-               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;
+               pRecord++;
        }
-
-       ret = TRUE;
-
-cleanup:
-       return ret;
+       UnmapViewOfFile(pHeader);
+       return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
 }
 
-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)
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_Restore(
+       IN IRecycleBin5 *This,
+       IN LPCWSTR pDeletedFileName,
+       IN DELETED_FILE_RECORD *pDeletedFile)
 {
-       DELETED_FILE_RECORD DeletedFile;
-       SIZE_T Needed;
-       LPWSTR FullName = NULL;
-       HANDLE hFile = INVALID_HANDLE_VALUE;
-       BOOL ret = FALSE;
+       struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+       ULARGE_INTEGER FileSize;
+       PINFO2_HEADER pHeader;
+       DELETED_FILE_RECORD *pRecord, *pLast;
+       DWORD dwEntries, i;
 
-       /* Check parameters */
-       if (BufferSize > 0 && FileDetails == NULL)
+       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)
        {
-               SetLastError(ERROR_INVALID_PARAMETER);
-               goto cleanup;
+               UnmapViewOfFile(pHeader);
+               return HRESULT_FROM_WIN32(GetLastError());
        }
+       dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
 
-       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)
+       pRecord = (DELETED_FILE_RECORD *)(pHeader + 1);
+       for (i = 0; i < dwEntries; i++)
        {
-               SetLastError(ERROR_INSUFFICIENT_BUFFER);
-               goto cleanup;
+               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++;
        }
 
-       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);
-       if (hFile != INVALID_HANDLE_VALUE)
-               CloseHandle(hFile);
-       return ret;
+       UnmapViewOfFile(pHeader);
+       return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
 }
 
-static BOOL
-RestoreFile5(
-       IN PRECYCLE_BIN bin,
-       IN HANDLE hDeletedFile)
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5_RecycleBin5_OnClosing(
+       IN IRecycleBin5 *This,
+       IN IRecycleBinEnumList *prb5el)
 {
-       INFO2_HEADER Header;
-       DWORD bytesRead, bytesWritten;
-       LARGE_INTEGER Position;
-       DELETED_FILE_RECORD DeletedFile, LastFile;
-       LPWSTR FullName = NULL;
-       BOOL ret = FALSE;
+       struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
+       s->EnumeratorCount--;
+       return S_OK;
+}
 
-       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;
-       }
+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;
 
-       if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD))
+       Needed = (wcslen(Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR);
+       BufferName = HeapAlloc(GetProcessHeap(), 0, Needed);
+       if (!BufferName)
        {
-               SetLastError(ERROR_GEN_FAILURE);
+               hr = ERROR_NOT_ENOUGH_MEMORY;
                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))
+       wcscpy(BufferName, Folder);
+       Separator = wcsstr(&BufferName[3], L"\\");
+       if (Separator)
+               *Separator = UNICODE_NULL;
+       if (!CreateDirectoryW(BufferName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
        {
-               SetLastError(ERROR_GEN_FAILURE);
+               hr = HRESULT_FROM_WIN32(GetLastError());
                goto cleanup;
        }
-       if (LastFile.dwRecordUniqueId != DeletedFile.dwRecordUniqueId)
+       SetFileAttributesW(BufferName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
+       if (Separator)
        {
-               /* 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))
+               *Separator = L'\\';
+               if (!CreateDirectoryW(BufferName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
                {
-                       SetLastError(ERROR_GEN_FAILURE);
+                       hr = HRESULT_FROM_WIN32(GetLastError());
                        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))
+
+       if (OwnerSid)
        {
-               SetLastError(ERROR_GEN_FAILURE);
-               goto cleanup;
+               //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;
+               }
+               */
        }
-       /* 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;
 
-cleanup:
-       HeapFree(GetProcessHeap(), 0, FullName);
-       return ret;
-}
-
-static BOOL
-IntDeleteRecursive(
-       IN LPCWSTR FullName)
-{
-       DWORD RemovableAttributes = FILE_ATTRIBUTE_READONLY;
-       DWORD FileAttributes;
-       BOOL ret = FALSE;
+       wcscat(BufferName, L"\\");
+       FileName = &BufferName[wcslen(BufferName)];
 
-       FileAttributes = GetFileAttributesW(FullName);
-       if (FileAttributes == INVALID_FILE_ATTRIBUTES)
+       /* 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)
        {
-               if (GetLastError() == ERROR_FILE_NOT_FOUND)
-                       ret = TRUE;
+               hr = HRESULT_FROM_WIN32(GetLastError());
                goto cleanup;
        }
-       if (FileAttributes & RemovableAttributes)
+       BytesToWrite = strlen(DesktopIniContents);
+       if (!WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten, NULL))
        {
-               if (!SetFileAttributesW(FullName, FileAttributes & ~RemovableAttributes))
-                       goto cleanup;
-       }
-       if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-       {
-               /* Recursive deletion */
-               /* FIXME: recursive deletion */
-               SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+               hr = HRESULT_FROM_WIN32(GetLastError());
                goto cleanup;
-
-               if (!RemoveDirectoryW(FullName))
-                       goto cleanup;
        }
-       else
+       if (BytesWritten != BytesToWrite)
        {
-               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))
+               hr = E_FAIL;
                goto cleanup;
+       }
+       CloseHandle(hFile);
+       hFile = INVALID_HANDLE_VALUE;
 
-       if (!IntDeleteRecursive(FullName))
+       /* 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;
-       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);
+       }
+       BytesToWrite = sizeof(Info2Contents);
+       if (!WriteFile(hFile, Info2Contents, (DWORD)BytesToWrite, &BytesWritten, NULL))
+       {
+               hr = HRESULT_FROM_WIN32(GetLastError());
                goto cleanup;
        }
-       wsprintfW(FullName, L"%s\\D%c%lu%s", bin->Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension);
-       *pFullName = FullName;
-       ret = TRUE;
+       if (BytesWritten == BytesToWrite)
+               hr = S_OK;
+       else
+               hr = E_FAIL;
 
 cleanup:
-       if (!ret)
-               HeapFree(GetProcessHeap(), 0, FullName);
-       return ret;
+       HeapFree(GetProcessHeap(), 0, BufferName);
+       if (hFile != INVALID_HANDLE_VALUE)
+               CloseHandle(hFile);
+       return hr;
 }
 
-static BOOL
-IntSearchRecord(
-       IN PRECYCLE_BIN bin,
-       IN HANDLE hDeletedFile,
-       OUT PDELETED_FILE_RECORD pDeletedFile,
-       OUT PLARGE_INTEGER Position OPTIONAL)
+HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown)
 {
-       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)
+       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))
        {
-               SetLastError(ERROR_GEN_FAILURE);
+               hr = HRESULT_FROM_WIN32(GetLastError());
                goto cleanup;
        }
-
-       if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD))
+       if (!(FileSystemFlags & FILE_PERSISTENT_ACLS))
+               RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL;
+       else
        {
-               SetLastError(ERROR_GEN_FAILURE);
-               goto cleanup;
-       }
+               RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL;
 
-       SetLastError(ERROR_SUCCESS);
-       for (dwEntries = 0; dwEntries < Header.dwNumberOfEntries; dwEntries++)
-       {
-               if (Position)
+               /* Get user SID */
+               if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle))
                {
-                       LARGE_INTEGER Zero;
-                       Zero.QuadPart = 0;
-                       if (!SetFilePointerEx(bin->hInfo, Zero, Position, FILE_CURRENT))
-                               goto cleanup;
+                       hr = HRESULT_FROM_WIN32(GetLastError());
+                       goto cleanup;
                }
-               if (!ReadFile(bin->hInfo, &DeletedFile, Header.dwRecordSize, &bytesRead, NULL))
+               if (GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &Needed))
+               {
+                       hr = E_FAIL;
                        goto cleanup;
-               if (bytesRead != Header.dwRecordSize)
+               }
+               if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
                {
-                       SetLastError(ERROR_GEN_FAILURE);
+                       hr = HRESULT_FROM_WIN32(GetLastError());
                        goto cleanup;
                }
-               if (DeletedFile.dwRecordUniqueId == (DWORD)(ULONG_PTR)hDeletedFile)
+               TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed);
+               if (!TokenUserInfo)
                {
-                       memcpy(pDeletedFile, &DeletedFile, Header.dwRecordSize);
-                       ret = TRUE;
+                       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);
 
-       /* Entry not found */
-       SetLastError(ERROR_INVALID_HANDLE);
+       *ppUnknown = (IUnknown *)&s->recycleBinImpl;
+
+       hr = S_OK;
 
 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;
 }
index 8222fd5..6f6b328 100644 (file)
@@ -5,6 +5,10 @@
 
 #include "recyclebin_private.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <pshpack1.h>
 
 /* MS Windows 2000/XP/2003 */
@@ -20,57 +24,86 @@ typedef struct _DELETED_FILE_RECORD
 
 #include <poppack.h>
 
-static BOOL
-CloseHandle5(
-       IN HANDLE hDeletedFile);
-
-static BOOL
-DeleteFile5(
-       IN PRECYCLE_BIN bin,
-       IN LPCWSTR FullPath,
-       IN LPCWSTR FileName);
-
-static BOOL
-EmptyRecycleBin5(
-       IN PRECYCLE_BIN* bin);
-
-static BOOL
-EnumerateFiles5(
-       IN PRECYCLE_BIN bin,
-       IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
-       IN PVOID Context OPTIONAL);
-
-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);
-
-static BOOL
-RestoreFile5(
-       IN PRECYCLE_BIN bin,
-       IN HANDLE hDeletedFile);
-
-static BOOL
-IntDeleteRecursive(
-       IN LPCWSTR FullName);
-
-static BOOL
-IntEmptyRecycleBinCallback(
-       IN PVOID Context,
-       IN HANDLE hDeletedFile);
-
-static BOOL
-IntGetFullName(
-       IN PRECYCLE_BIN bin,
-       IN PDELETED_FILE_RECORD pDeletedFile,
-       OUT LPWSTR* pFullName);
-
-static BOOL
-IntSearchRecord(
-       IN PRECYCLE_BIN bin,
-       IN HANDLE hDeletedFile,
-       OUT PDELETED_FILE_RECORD DeletedFile,
-       OUT PLARGE_INTEGER Position OPTIONAL);
+/* COM interface */
+
+typedef interface IRecycleBin5 IRecycleBin5;
+EXTERN_C const IID IID_IRecycleBin5;
+
+typedef struct IRecycleBin5Vtbl
+{
+       /* IRecycleBin interface */
+       HRESULT (STDMETHODCALLTYPE *QueryInterface)(
+               IN IRecycleBin5 *This,
+               IN REFIID riid,
+               OUT void **ppvObject);
+
+       ULONG (STDMETHODCALLTYPE *AddRef)(
+               IN IRecycleBin5 *This);
+
+       ULONG (STDMETHODCALLTYPE *Release)(
+               IN IRecycleBin5 *This);
+
+       HRESULT (STDMETHODCALLTYPE *DeleteFile)(
+               IN IRecycleBin5 *This,
+               IN LPCWSTR szFileName);
+
+       HRESULT (STDMETHODCALLTYPE *EmptyRecycleBin)(
+               IN IRecycleBin5 *This);
+
+       HRESULT (STDMETHODCALLTYPE *EnumObjects)(
+               IN IRecycleBin5 *This,
+               OUT IRecycleBinEnumList **ppEnumList);
+
+       /* IRecycleBin5 interface */
+       HRESULT (STDMETHODCALLTYPE *Delete)(
+               IN IRecycleBin5 *This,
+               IN LPCWSTR pDeletedFileName,
+               IN DELETED_FILE_RECORD *pDeletedFile);
+
+       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
diff --git a/reactos/lib/recyclebin/recyclebin_v5_enumerator.c b/reactos/lib/recyclebin/recyclebin_v5_enumerator.c
new file mode 100644 (file)
index 0000000..e3f1abe
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * PROJECT:     Recycle bin management
+ * LICENSE:     GPL v2 - See COPYING in the top level directory
+ * FILE:        lib/recyclebin/recyclebin_v5_enumerator.c
+ * PURPOSE:     Enumerates contents of a MS Windows 2000/XP/2003 recyclebin
+ * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+#define COBJMACROS
+#include "recyclebin_v5.h"
+
+struct RecycleBin5File
+{
+       ULONG ref;
+       IRecycleBin5 *recycleBin;
+       DELETED_FILE_RECORD deletedFile;
+       IRecycleBinFile recycleBinFileImpl;
+       WCHAR FullName[ANY_SIZE];
+};
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_QueryInterface(
+       IN IRecycleBinFile *This,
+       IN REFIID riid,
+       OUT void **ppvObject)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+
+       if (!ppvObject)
+               return E_POINTER;
+
+       if (IsEqualIID(riid, &IID_IUnknown))
+               *ppvObject = &s->recycleBinFileImpl;
+       else if (IsEqualIID(riid, &IID_IRecycleBinFile))
+               *ppvObject = &s->recycleBinFileImpl;
+       else
+       {
+               *ppvObject = NULL;
+               return E_NOINTERFACE;
+       }
+
+       IUnknown_AddRef(This);
+       return S_OK;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_AddRef(
+       IN IRecycleBinFile *This)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
+       return refCount;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_Release(
+       IN IRecycleBinFile *This)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       ULONG refCount;
+
+       if (!This)
+               return E_POINTER;
+
+       refCount = InterlockedDecrement((PLONG)&s->ref);
+
+       if (refCount == 0)
+       {
+               IRecycleBin5_Release(s->recycleBin);
+               CoTaskMemFree(s);
+       }
+
+       return refCount;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_GetLastModificationTime(
+       IN IRecycleBinFile *This,
+       OUT FILETIME *pLastModificationTime)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       HRESULT hr;
+       DWORD dwAttributes;
+       HANDLE hFile;
+
+       dwAttributes = GetFileAttributesW(s->FullName);
+       if (dwAttributes == INVALID_FILE_ATTRIBUTES)
+               return HRESULT_FROM_WIN32(GetLastError());
+       if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
+               hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+       else
+               hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+       if (hFile == INVALID_HANDLE_VALUE)
+               return HRESULT_FROM_WIN32(GetLastError());
+
+       if (GetFileTime(hFile, NULL, NULL, pLastModificationTime))
+               hr = S_OK;
+       else
+               hr = HRESULT_FROM_WIN32(GetLastError());
+       CloseHandle(hFile);
+       return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_GetDeletionTime(
+       IN IRecycleBinFile *This,
+       OUT FILETIME *pDeletionTime)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       *pDeletionTime = s->deletedFile.DeletionTime;
+       return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_GetFileSize(
+       IN IRecycleBinFile *This,
+       OUT ULARGE_INTEGER *pFileSize)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       HRESULT hr;
+       DWORD dwAttributes;
+       HANDLE hFile;
+
+       dwAttributes = GetFileAttributesW(s->FullName);
+       if (dwAttributes == INVALID_FILE_ATTRIBUTES)
+               return HRESULT_FROM_WIN32(GetLastError());
+       if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
+       {
+               pFileSize->QuadPart = 0;
+               return S_OK;
+       }
+
+       hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+       if (hFile == INVALID_HANDLE_VALUE)
+               return HRESULT_FROM_WIN32(GetLastError());
+       pFileSize->u.LowPart = GetFileSize(hFile, &pFileSize->u.HighPart);
+       if (pFileSize->u.LowPart != INVALID_FILE_SIZE)
+               hr = S_OK;
+       else
+               hr = HRESULT_FROM_WIN32(GetLastError());
+       CloseHandle(hFile);
+       return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_GetPhysicalFileSize(
+       IN IRecycleBinFile *This,
+       OUT ULARGE_INTEGER *pPhysicalFileSize)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       pPhysicalFileSize->u.HighPart = 0;
+       pPhysicalFileSize->u.LowPart = s->deletedFile.dwPhysicalFileSize;
+       return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_GetAttributes(
+       IN IRecycleBinFile *This,
+       OUT DWORD *pAttributes)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       DWORD dwAttributes;
+
+       dwAttributes = GetFileAttributesW(s->FullName);
+       if (dwAttributes == INVALID_FILE_ATTRIBUTES)
+               return HRESULT_FROM_WIN32(GetLastError());
+
+       *pAttributes = dwAttributes;
+       return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_GetFileName(
+       IN IRecycleBinFile *This,
+       IN DWORD BufferSize,
+       IN OUT LPWSTR Buffer,
+       OUT DWORD *RequiredSize)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       DWORD dwRequired;
+
+       dwRequired = (DWORD)(wcslen(s->deletedFile.FileNameW) + 1) * sizeof(WCHAR);
+       if (RequiredSize)
+               *RequiredSize = dwRequired;
+
+       if (BufferSize == 0 && !Buffer)
+               return S_OK;
+
+       if (BufferSize < dwRequired)
+               return E_OUTOFMEMORY;
+       CopyMemory(Buffer, s->deletedFile.FileNameW, dwRequired);
+       return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_Delete(
+       IN IRecycleBinFile *This)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       return IRecycleBin5_Delete(s->recycleBin, s->FullName, &s->deletedFile);
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5File_RecycleBinFile_Restore(
+       IN IRecycleBinFile *This)
+{
+       struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
+       return IRecycleBin5_Restore(s->recycleBin, s->FullName, &s->deletedFile);
+}
+
+CONST_VTBL struct IRecycleBinFileVtbl RecycleBin5FileVtbl =
+{
+       RecycleBin5File_RecycleBinFile_QueryInterface,
+       RecycleBin5File_RecycleBinFile_AddRef,
+       RecycleBin5File_RecycleBinFile_Release,
+       RecycleBin5File_RecycleBinFile_GetLastModificationTime,
+       RecycleBin5File_RecycleBinFile_GetDeletionTime,
+       RecycleBin5File_RecycleBinFile_GetFileSize,
+       RecycleBin5File_RecycleBinFile_GetPhysicalFileSize,
+       RecycleBin5File_RecycleBinFile_GetAttributes,
+       RecycleBin5File_RecycleBinFile_GetFileName,
+       RecycleBin5File_RecycleBinFile_Delete,
+       RecycleBin5File_RecycleBinFile_Restore,
+};
+
+static HRESULT
+RecycleBin5_File_Constructor(
+       IN IRecycleBin5 *prb,
+       IN LPCWSTR Folder,
+       IN PDELETED_FILE_RECORD pDeletedFile,
+       OUT IRecycleBinFile **ppFile)
+{
+       struct RecycleBin5File *s = NULL;
+       LPCWSTR Extension;
+       SIZE_T Needed;
+
+       if (!ppFile)
+               return E_POINTER;
+
+       Extension = wcsrchr(pDeletedFile->FileNameW, '.');
+       if (Extension < wcsrchr(pDeletedFile->FileNameW, '\\'))
+               Extension = NULL;
+       Needed = wcslen(Folder) + 13;
+       if (Extension)
+               Needed += wcslen(Extension);
+       Needed *= sizeof(WCHAR);
+
+       s = CoTaskMemAlloc(sizeof(struct RecycleBin5File) + Needed);
+       if (!s)
+               return E_OUTOFMEMORY;
+       ZeroMemory(s, sizeof(struct RecycleBin5File) + Needed);
+       s->recycleBinFileImpl.lpVtbl = &RecycleBin5FileVtbl;
+       s->ref = 1;
+       s->deletedFile = *pDeletedFile;
+       s->recycleBin = prb;
+       IRecycleBin5_AddRef(s->recycleBin);
+       *ppFile = &s->recycleBinFileImpl;
+       wsprintfW(s->FullName, L"%s\\D%c%lu%s", Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension);
+
+       return S_OK;
+}
+
+struct RecycleBin5Enum
+{
+       ULONG ref;
+       IRecycleBin5 *recycleBin;
+       HANDLE hInfo;
+       INFO2_HEADER *pInfo;
+       DWORD dwCurrent;
+       IRecycleBinEnumList recycleBinEnumImpl;
+       WCHAR szPrefix[ANY_SIZE];
+};
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5Enum_RecycleBinEnumList_QueryInterface(
+       IN IRecycleBinEnumList *This,
+       IN REFIID riid,
+       OUT void **ppvObject)
+{
+       struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
+
+       if (!ppvObject)
+               return E_POINTER;
+
+       if (IsEqualIID(riid, &IID_IUnknown))
+               *ppvObject = &s->recycleBinEnumImpl;
+       else if (IsEqualIID(riid, &IID_IRecycleBinEnumList))
+               *ppvObject = &s->recycleBinEnumImpl;
+       else
+       {
+               *ppvObject = NULL;
+               return E_NOINTERFACE;
+       }
+
+       IUnknown_AddRef(This);
+       return S_OK;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBin5Enum_RecycleBinEnumList_AddRef(
+       IN IRecycleBinEnumList *This)
+{
+       struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
+       ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
+       return refCount;
+}
+
+static ULONG STDMETHODCALLTYPE
+RecycleBin5Enum_RecycleBinEnumList_Release(
+       IN IRecycleBinEnumList *This)
+{
+       struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
+       ULONG refCount;
+
+       if (!This)
+               return E_POINTER;
+
+       refCount = InterlockedDecrement((PLONG)&s->ref);
+
+       if (refCount == 0)
+       {
+               IRecycleBin5_OnClosing(s->recycleBin, This);
+               UnmapViewOfFile(s->pInfo);
+               IRecycleBin5_Release(s->recycleBin);
+               CoTaskMemFree(s);
+       }
+
+       return refCount;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5Enum_RecycleBinEnumList_Next(
+       IRecycleBinEnumList *This,
+       IN DWORD celt,
+       IN OUT IRecycleBinFile **rgelt,
+       OUT DWORD *pceltFetched)
+{
+       struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
+       ULARGE_INTEGER FileSize;
+       INFO2_HEADER *pHeader = s->pInfo;
+       DELETED_FILE_RECORD *pDeletedFile;
+       DWORD fetched = 0, i;
+       DWORD dwEntries;
+       HRESULT hr;
+
+       if (!rgelt)
+               return E_POINTER;
+       if (!pceltFetched && celt > 1)
+               return E_INVALIDARG;
+
+       FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
+       if (FileSize.u.LowPart == 0)
+               return HRESULT_FROM_WIN32(GetLastError());
+       dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
+
+       i = s->dwCurrent;
+       pDeletedFile = (DELETED_FILE_RECORD *)(pHeader + 1) + i;
+       for (; i < dwEntries && fetched < celt; i++)
+       {
+               hr = RecycleBin5_File_Constructor(s->recycleBin, s->szPrefix, pDeletedFile, &rgelt[fetched]);
+               if (!SUCCEEDED(hr))
+               {
+                       for (i = 0; i < fetched; i++)
+                               IRecycleBinFile_Release(rgelt[i]);
+                       return hr;
+               }
+               pDeletedFile++;
+               fetched++;
+       }
+
+       s->dwCurrent = i;
+       if (pceltFetched)
+               *pceltFetched = fetched;
+       if (fetched == celt)
+               return S_OK;
+       else
+               return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5Enum_RecycleBinEnumList_Skip(
+       IN IRecycleBinEnumList *This,
+       IN DWORD celt)
+{
+       struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
+       s->dwCurrent += celt;
+       return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+RecycleBin5Enum_RecycleBinEnumList_Reset(
+       IN IRecycleBinEnumList *This)
+{
+       struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
+       s->dwCurrent = 0;
+       return S_OK;
+}
+
+CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBin5EnumVtbl =
+{
+       RecycleBin5Enum_RecycleBinEnumList_QueryInterface,
+       RecycleBin5Enum_RecycleBinEnumList_AddRef,
+       RecycleBin5Enum_RecycleBinEnumList_Release,
+       RecycleBin5Enum_RecycleBinEnumList_Next,
+       RecycleBin5Enum_RecycleBinEnumList_Skip,
+       RecycleBin5Enum_RecycleBinEnumList_Reset,
+};
+
+HRESULT
+RecycleBin5_Enumerator_Constructor(
+       IN IRecycleBin5 *prb,
+       IN HANDLE hInfo,
+       IN HANDLE hInfoMapped,
+       IN LPCWSTR szPrefix,
+       OUT IUnknown **ppUnknown)
+{
+       struct RecycleBin5Enum *s = NULL;
+       SIZE_T Needed;
+
+       if (!ppUnknown)
+               return E_POINTER;
+
+       Needed = (wcslen(szPrefix) + 1) * sizeof(WCHAR);
+
+       s = CoTaskMemAlloc(sizeof(struct RecycleBin5Enum) + Needed);
+       if (!s)
+               return E_OUTOFMEMORY;
+       ZeroMemory(s, sizeof(struct RecycleBin5Enum) + Needed);
+       s->recycleBinEnumImpl.lpVtbl = &RecycleBin5EnumVtbl;
+       s->ref = 1;
+       s->recycleBin = prb;
+       wcscpy(s->szPrefix, szPrefix);
+       s->hInfo = hInfo;
+       s->pInfo = MapViewOfFile(hInfoMapped, FILE_MAP_READ, 0, 0, 0);
+       if (!s->pInfo)
+       {
+               CoTaskMemFree(s);
+               return HRESULT_FROM_WIN32(GetLastError());
+       }
+       if (s->pInfo->dwVersion != 5 || s->pInfo->dwRecordSize != sizeof(DELETED_FILE_RECORD))
+       {
+               UnmapViewOfFile(s->pInfo);
+               CoTaskMemFree(s);
+               return E_FAIL;
+       }
+       IRecycleBin5_AddRef(s->recycleBin);
+       *ppUnknown = (IUnknown *)&s->recycleBinEnumImpl;
+
+       return S_OK;
+}
diff --git a/reactos/lib/recyclebin/refcount.c b/reactos/lib/recyclebin/refcount.c
deleted file mode 100644 (file)
index 24e83b8..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * PROJECT:     Recycle bin management
- * LICENSE:     GPL v2 - See COPYING in the top level directory
- * FILE:        lib/recyclebin/openclose.c
- * PURPOSE:     Do reference counting on objects
- * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
- */
-
-#include "recyclebin_private.h"
-
-BOOL
-InitializeHandle(
-       IN PREFCOUNT_DATA pData,
-       IN PDESTROY_DATA pFnClose OPTIONAL)
-{
-       pData->ReferenceCount = 1;
-       pData->Close = pFnClose;
-       return TRUE;
-}
-
-BOOL
-ReferenceHandle(
-       IN PREFCOUNT_DATA pData)
-{
-       pData->ReferenceCount++;
-       return TRUE;
-}
-
-BOOL
-DereferenceHandle(
-       IN PREFCOUNT_DATA pData)
-{
-       pData->ReferenceCount--;
-       if (pData->ReferenceCount == 0)
-       {
-               if (pData->Close)
-                       return pData->Close(pData);
-               else
-                       return TRUE;
-       }
-       return TRUE;
-}