mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 23:05:41 +00:00
Create a branch for cmake bringup.
svn path=/branches/cmake-bringup/; revision=48236
This commit is contained in:
parent
a28e798006
commit
c424146e2c
20602 changed files with 0 additions and 1140137 deletions
14
lib/recyclebin/guid.c
Normal file
14
lib/recyclebin/guid.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* PROJECT: Recycle bin management
|
||||
* LICENSE: GPL v2 - See COPYING in the top level directory
|
||||
* FILE: lib/recyclebin/guid.c
|
||||
* PURPOSE: Define GUID values
|
||||
* PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
|
||||
*/
|
||||
|
||||
#define INITGUID
|
||||
#include <initguid.h>
|
||||
DEFINE_GUID(IID_IRecycleBin, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x80);
|
||||
DEFINE_GUID(IID_IRecycleBinEnumList, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x81);
|
||||
DEFINE_GUID(IID_IRecycleBinFile, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x82);
|
||||
DEFINE_GUID(IID_IRecycleBin5, 0x392ec73a, 0x45e9, 0x43de, 0xa8, 0x41, 0x4f, 0x32, 0x1a, 0xea, 0xa5, 0x83);
|
11
lib/recyclebin/readme.txt
Normal file
11
lib/recyclebin/readme.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
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
|
||||
- Set security on recycle bin folder
|
||||
- Make the library thread-safe
|
||||
|
||||
3 levels
|
||||
- 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
|
417
lib/recyclebin/recyclebin.c
Normal file
417
lib/recyclebin/recyclebin.c
Normal file
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
* PROJECT: Recycle bin management
|
||||
* LICENSE: GPL v2 - See COPYING in the top level directory
|
||||
* FILE: lib/recyclebin/recyclebin.c
|
||||
* PURPOSE: Public interface
|
||||
* PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
|
||||
*/
|
||||
|
||||
#define COBJMACROS
|
||||
#include "recyclebin_private.h"
|
||||
#include <stdio.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
|
||||
|
||||
BOOL WINAPI
|
||||
CloseRecycleBinHandle(
|
||||
IN HANDLE hDeletedFile)
|
||||
{
|
||||
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", hDeletedFile);
|
||||
|
||||
hr = IRecycleBinFile_Release(rbf);
|
||||
if (SUCCEEDED(hr))
|
||||
return TRUE;
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
DeleteFileToRecycleBinA(
|
||||
IN LPCSTR FileName)
|
||||
{
|
||||
int len;
|
||||
LPWSTR FileNameW = NULL;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
TRACE("(%s)\n", debugstr_a(FileName));
|
||||
|
||||
/* Check parameters */
|
||||
if (FileName == NULL)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
len = MultiByteToWideChar(CP_ACP, 0, FileName, -1, NULL, 0);
|
||||
if (len == 0)
|
||||
goto cleanup;
|
||||
FileNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
||||
if (!FileNameW)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto cleanup;
|
||||
}
|
||||
if (MultiByteToWideChar(CP_ACP, 0, FileName, -1, FileNameW, len) == 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = DeleteFileToRecycleBinW(FileNameW);
|
||||
|
||||
cleanup:
|
||||
HeapFree(GetProcessHeap(), 0, FileNameW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
DeleteFileToRecycleBinW(
|
||||
IN LPCWSTR FileName)
|
||||
{
|
||||
IRecycleBin *prb;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%s)\n", debugstr_w(FileName));
|
||||
|
||||
hr = GetDefaultRecycleBin(NULL, &prb);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
|
||||
hr = IRecycleBin_DeleteFile(prb, FileName);
|
||||
IRecycleBin_Release(prb);
|
||||
|
||||
cleanup:
|
||||
if (SUCCEEDED(hr))
|
||||
return TRUE;
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
DeleteFileHandleToRecycleBin(
|
||||
IN HANDLE hDeletedFile)
|
||||
{
|
||||
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", hDeletedFile);
|
||||
|
||||
hr = IRecycleBinFile_Delete(rbf);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
return TRUE;
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
EmptyRecycleBinA(
|
||||
IN LPCSTR pszRoot OPTIONAL)
|
||||
{
|
||||
int len;
|
||||
LPWSTR szRootW = NULL;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
TRACE("(%s)\n", debugstr_a(pszRoot));
|
||||
|
||||
if (pszRoot)
|
||||
{
|
||||
len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
|
||||
if (len == 0)
|
||||
goto cleanup;
|
||||
szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
||||
if (!szRootW)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto cleanup;
|
||||
}
|
||||
if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = EmptyRecycleBinW(szRootW);
|
||||
|
||||
cleanup:
|
||||
HeapFree(GetProcessHeap(), 0, szRootW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
EmptyRecycleBinW(
|
||||
IN LPCWSTR pszRoot OPTIONAL)
|
||||
{
|
||||
IRecycleBin *prb;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%s)\n", debugstr_w(pszRoot));
|
||||
|
||||
hr = GetDefaultRecycleBin(pszRoot, &prb);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
|
||||
hr = IRecycleBin_EmptyRecycleBin(prb);
|
||||
IRecycleBin_Release(prb);
|
||||
|
||||
cleanup:
|
||||
if (SUCCEEDED(hr))
|
||||
return TRUE;
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
EnumerateRecycleBinA(
|
||||
IN LPCSTR pszRoot OPTIONAL,
|
||||
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
|
||||
IN PVOID Context OPTIONAL)
|
||||
{
|
||||
int len;
|
||||
LPWSTR szRootW = NULL;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
TRACE("(%s, %p, %p)\n", debugstr_a(pszRoot), pFnCallback, Context);
|
||||
|
||||
if (pszRoot)
|
||||
{
|
||||
len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
|
||||
if (len == 0)
|
||||
goto cleanup;
|
||||
szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
||||
if (!szRootW)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto cleanup;
|
||||
}
|
||||
if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = EnumerateRecycleBinW(szRootW, pFnCallback, Context);
|
||||
|
||||
cleanup:
|
||||
HeapFree(GetProcessHeap(), 0, szRootW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
EnumerateRecycleBinW(
|
||||
IN LPCWSTR pszRoot OPTIONAL,
|
||||
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
|
||||
IN PVOID Context OPTIONAL)
|
||||
{
|
||||
IRecycleBin *prb = NULL;
|
||||
IRecycleBinEnumList *prbel = NULL;
|
||||
IRecycleBinFile *prbf;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%s, %p, %p)\n", debugstr_w(pszRoot), pFnCallback, Context);
|
||||
|
||||
hr = GetDefaultRecycleBin(NULL, &prb);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
|
||||
hr = IRecycleBin_EnumObjects(prb, &prbel);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
while (TRUE)
|
||||
{
|
||||
hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
|
||||
if (hr == S_FALSE)
|
||||
{
|
||||
hr = S_OK;
|
||||
goto cleanup;
|
||||
}
|
||||
else if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
if (!pFnCallback(Context, (HANDLE)prbf))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (prb)
|
||||
IRecycleBin_Release(prb);
|
||||
if (prbel)
|
||||
IRecycleBinEnumList_Release(prbel);
|
||||
if (SUCCEEDED(hr))
|
||||
return TRUE;
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
GetDeletedFileDetailsA(
|
||||
IN HANDLE hDeletedFile,
|
||||
IN DWORD BufferSize,
|
||||
IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL,
|
||||
OUT LPDWORD RequiredSize OPTIONAL)
|
||||
{
|
||||
PDELETED_FILE_DETAILS_W FileDetailsW = NULL;
|
||||
DWORD BufferSizeW = 0;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
|
||||
|
||||
if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName))
|
||||
{
|
||||
BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName)
|
||||
+ (BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) * sizeof(WCHAR);
|
||||
}
|
||||
if (FileDetails && BufferSizeW)
|
||||
{
|
||||
FileDetailsW = HeapAlloc(GetProcessHeap(), 0, BufferSizeW);
|
||||
if (!FileDetailsW)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = GetDeletedFileDetailsW(hDeletedFile, BufferSizeW, FileDetailsW, RequiredSize);
|
||||
if (!ret)
|
||||
goto cleanup;
|
||||
|
||||
if (FileDetails)
|
||||
{
|
||||
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;
|
||||
}
|
||||
ret = TRUE;
|
||||
|
||||
cleanup:
|
||||
HeapFree(GetProcessHeap(), 0, FileDetailsW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
GetDeletedFileDetailsW(
|
||||
IN HANDLE hDeletedFile,
|
||||
IN DWORD BufferSize,
|
||||
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
|
||||
OUT LPDWORD RequiredSize OPTIONAL)
|
||||
{
|
||||
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||
HRESULT hr;
|
||||
SIZE_T NameSize, Needed;
|
||||
|
||||
TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
|
||||
|
||||
hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + NameSize;
|
||||
if (RequiredSize)
|
||||
*RequiredSize = (DWORD)Needed;
|
||||
if (Needed > BufferSize)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
goto cleanup;
|
||||
}
|
||||
hr = IRecycleBinFile_GetFileName(rbf, NameSize, FileDetails->FileName, NULL);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetLastModificationTime(rbf, &FileDetails->LastModification);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetDeletionTime(rbf, &FileDetails->DeletionTime);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetFileSize(rbf, &FileDetails->FileSize);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetPhysicalFileSize(rbf, &FileDetails->PhysicalFileSize);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
hr = IRecycleBinFile_GetAttributes(rbf, &FileDetails->Attributes);
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
if (SUCCEEDED(hr))
|
||||
return TRUE;
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
GetRecycleBinDetails(
|
||||
IN LPCWSTR pszVolume OPTIONAL,
|
||||
OUT ULARGE_INTEGER *pulTotalItems,
|
||||
OUT ULARGE_INTEGER *pulTotalSize)
|
||||
{
|
||||
pulTotalItems->QuadPart = 0;
|
||||
pulTotalSize->QuadPart = 0;
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
RestoreFile(
|
||||
IN HANDLE hDeletedFile)
|
||||
{
|
||||
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", hDeletedFile);
|
||||
|
||||
hr = IRecycleBinFile_Restore(rbf);
|
||||
if (SUCCEEDED(hr))
|
||||
return TRUE;
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
SetLastError(HRESULT_CODE(hr));
|
||||
else
|
||||
SetLastError(ERROR_GEN_FAILURE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HRESULT WINAPI
|
||||
GetDefaultRecycleBin(
|
||||
IN LPCWSTR pszVolume OPTIONAL,
|
||||
OUT IRecycleBin **pprb)
|
||||
{
|
||||
IUnknown *pUnk;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%s, %p)\n", debugstr_w(pszVolume), pprb);
|
||||
|
||||
if (!pprb)
|
||||
return E_POINTER;
|
||||
|
||||
if (!pszVolume)
|
||||
hr = RecycleBinGeneric_Constructor(&pUnk);
|
||||
else
|
||||
{
|
||||
/* FIXME: do a better validation! */
|
||||
if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
|
||||
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
|
||||
|
||||
/* For now, only support this type of recycle bins... */
|
||||
hr = RecycleBin5_Constructor(pszVolume, &pUnk);
|
||||
}
|
||||
if (!SUCCEEDED(hr))
|
||||
return hr;
|
||||
hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBin, (void **)pprb);
|
||||
IUnknown_Release(pUnk);
|
||||
return hr;
|
||||
}
|
298
lib/recyclebin/recyclebin.h
Normal file
298
lib/recyclebin/recyclebin.h
Normal file
|
@ -0,0 +1,298 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <objbase.h>
|
||||
#define ANY_SIZE 1
|
||||
|
||||
/* Structures used by the API Interface */
|
||||
|
||||
typedef struct _DELETED_FILE_DETAILS_A
|
||||
{
|
||||
FILETIME LastModification;
|
||||
FILETIME DeletionTime;
|
||||
ULARGE_INTEGER FileSize;
|
||||
ULARGE_INTEGER PhysicalFileSize;
|
||||
DWORD Attributes;
|
||||
CHAR FileName[ANY_SIZE];
|
||||
} DELETED_FILE_DETAILS_A, *PDELETED_FILE_DETAILS_A;
|
||||
typedef struct _DELETED_FILE_DETAILS_W
|
||||
{
|
||||
FILETIME LastModification;
|
||||
FILETIME DeletionTime;
|
||||
ULARGE_INTEGER FileSize;
|
||||
ULARGE_INTEGER PhysicalFileSize;
|
||||
DWORD Attributes;
|
||||
WCHAR FileName[ANY_SIZE];
|
||||
} DELETED_FILE_DETAILS_W, *PDELETED_FILE_DETAILS_W;
|
||||
#ifdef UNICODE
|
||||
#define DELETED_FILE_DETAILS DELETED_FILE_DETAILS_W
|
||||
#define PDELETED_FILE_DETAILS PDELETED_FILE_DETAILS_W
|
||||
#else
|
||||
#define DELETED_FILE_DETAILS DELETED_FILE_DETAILS_A
|
||||
#define PDELETED_FILE_DETAILS PDELETED_FILE_DETAILS_A
|
||||
#endif
|
||||
|
||||
/* API Interface */
|
||||
|
||||
/* Function called for each deleted file in the recycle bin
|
||||
* Context: value given by the caller of the EnumerateRecycleBin function
|
||||
* hDeletedFile: a handle to the deleted file
|
||||
* Returning FALSE stops the enumeration.
|
||||
* Remarks: the handle must be closed with the CloseRecycleBinHandle function
|
||||
*/
|
||||
typedef BOOL (WINAPI *PENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context, IN HANDLE hDeletedFile);
|
||||
|
||||
/* Closes a file deleted handle.
|
||||
* hDeletedFile: the handle to close
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
* Remark: The handle is obtained in the PENUMERATE_RECYCLEBIN_CALLBACK callback
|
||||
*/
|
||||
BOOL WINAPI
|
||||
CloseRecycleBinHandle(
|
||||
IN HANDLE hDeletedFile);
|
||||
|
||||
/* Moves a file to the recycle bin.
|
||||
* FileName: the name of the file to move the recycle bin
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
*/
|
||||
BOOL WINAPI
|
||||
DeleteFileToRecycleBinA(
|
||||
IN LPCSTR FileName);
|
||||
BOOL WINAPI
|
||||
DeleteFileToRecycleBinW(
|
||||
IN LPCWSTR FileName);
|
||||
#ifdef UNICODE
|
||||
#define DeleteFileToRecycleBin DeleteFileToRecycleBinW
|
||||
#else
|
||||
#define DeleteFileToRecycleBin DeleteFileToRecycleBinA
|
||||
#endif
|
||||
|
||||
/* Moves a file to the recycle bin.
|
||||
* hDeletedFile: handle of the deleted file to delete
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
* Remark: The handle is obtained in the PENUMERATE_RECYCLEBIN_CALLBACK callback
|
||||
*/
|
||||
BOOL WINAPI
|
||||
DeleteFileHandleToRecycleBin(
|
||||
IN HANDLE hDeletedFile);
|
||||
|
||||
/* Removes all elements contained in a recycle bin
|
||||
* pszRoot: the name of the drive containing the recycle bin
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
* Remarks: 'pszRoot' can be NULL to mean 'all recycle bins'.
|
||||
*/
|
||||
BOOL WINAPI
|
||||
EmptyRecycleBinA(
|
||||
IN LPCSTR pszRoot OPTIONAL);
|
||||
BOOL WINAPI
|
||||
EmptyRecycleBinW(
|
||||
IN LPCWSTR pszRoot OPTIONAL);
|
||||
#ifdef UNICODE
|
||||
#define EmptyRecycleBin EmptyRecycleBinW
|
||||
#else
|
||||
#define EmptyRecycleBin EmptyRecycleBinA
|
||||
#endif
|
||||
|
||||
/* Enumerate contents of a recycle bin.
|
||||
* pszRoot: the name of the drive containing the recycle bin
|
||||
* pFnCallback: callback function to be called for each deleted item found
|
||||
* Context: some value which will be given back in the callback function
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
* Remarks: 'pszRoot' can be NULL to mean 'all recycle bins'.
|
||||
*/
|
||||
BOOL WINAPI
|
||||
EnumerateRecycleBinA(
|
||||
IN LPCSTR pszRoot OPTIONAL,
|
||||
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
|
||||
IN PVOID Context OPTIONAL);
|
||||
BOOL WINAPI
|
||||
EnumerateRecycleBinW(
|
||||
IN LPCWSTR pszRoot OPTIONAL,
|
||||
IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
|
||||
IN PVOID Context OPTIONAL);
|
||||
#ifdef UNICODE
|
||||
#define EnumerateRecycleBin EnumerateRecycleBinW
|
||||
#else
|
||||
#define EnumerateRecycleBin EnumerateRecycleBinA
|
||||
#endif
|
||||
|
||||
/* Gets details about a deleted file
|
||||
* hDeletedFile: handle of the deleted file to get details about
|
||||
* BufferSize: size of the 'FileDetails' buffer, in bytes
|
||||
* FileDetails: if the function succeeded, contains details about the deleted file
|
||||
* RequiredSize: contains the minimal buffer size required to get file information details
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
* Remark: The handle is obtained in the PENUMERATE_RECYCLEBIN_CALLBACK callback
|
||||
*/
|
||||
BOOL WINAPI
|
||||
GetDeletedFileDetailsA(
|
||||
IN HANDLE hDeletedFile,
|
||||
IN DWORD BufferSize,
|
||||
IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL,
|
||||
OUT LPDWORD RequiredSize OPTIONAL);
|
||||
BOOL WINAPI
|
||||
GetDeletedFileDetailsW(
|
||||
IN HANDLE hDeletedFile,
|
||||
IN DWORD BufferSize,
|
||||
IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
|
||||
OUT LPDWORD RequiredSize OPTIONAL);
|
||||
#ifdef UNICODE
|
||||
#define GetDeletedFileDetails GetDeletedFileDetailsW
|
||||
#else
|
||||
#define GetDeletedFileDetails GetDeletedFileDetailsA
|
||||
#endif
|
||||
|
||||
/* Get details about a whole recycle bin
|
||||
* pszVolume:
|
||||
* pulTotalItems:
|
||||
* pulTotalSize
|
||||
*/
|
||||
BOOL WINAPI
|
||||
GetRecycleBinDetails(
|
||||
IN LPCWSTR pszVolume OPTIONAL,
|
||||
OUT ULARGE_INTEGER *pulTotalItems,
|
||||
OUT ULARGE_INTEGER *pulTotalSize);
|
||||
|
||||
/* Restores a deleted file
|
||||
* hDeletedFile: handle of the deleted file to restore
|
||||
* Returns TRUE if operation succeeded, FALSE otherwise.
|
||||
* Remarks: if the function succeeds, the handle is not valid anymore.
|
||||
*/
|
||||
BOOL WINAPI
|
||||
RestoreFile(
|
||||
IN HANDLE hDeletedFile);
|
||||
|
||||
/* COM interface */
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IRecycleBinFile
|
||||
|
||||
DECLARE_INTERFACE_(IRecycleBinFile, IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IRecycleBinFile methods */
|
||||
STDMETHOD(GetLastModificationTime)(THIS_ FILETIME *pLastModificationTime) PURE;
|
||||
STDMETHOD(GetDeletionTime)(THIS_ FILETIME *pDeletionTime) PURE;
|
||||
STDMETHOD(GetFileSize)(THIS_ ULARGE_INTEGER *pFileSize) PURE;
|
||||
STDMETHOD(GetPhysicalFileSize)(THIS_ ULARGE_INTEGER *pPhysicalFileSize) PURE;
|
||||
STDMETHOD(GetAttributes)(THIS_ DWORD *pAttributes) PURE;
|
||||
STDMETHOD(GetFileName)(THIS_ SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) PURE;
|
||||
STDMETHOD(Delete)(THIS) PURE;
|
||||
STDMETHOD(Restore)(THIS) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IRecycleBinEnumList
|
||||
|
||||
DECLARE_INTERFACE_(IRecycleBinEnumList, IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IRecycleBinEnumList methods */
|
||||
STDMETHOD(Next)(THIS_ DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched);
|
||||
STDMETHOD(Skip)(THIS_ DWORD celt) PURE;
|
||||
STDMETHOD(Reset)(THIS) PURE;
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IRecycleBin
|
||||
|
||||
DECLARE_INTERFACE_(IRecycleBin, IUnknown)
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
/* IUnknown methods */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IRecycleBin methods */
|
||||
STDMETHOD(DeleteFile)(THIS_ LPCWSTR szFileName);
|
||||
STDMETHOD(EmptyRecycleBin)(THIS);
|
||||
STDMETHOD(EnumObjects)(THIS_ IRecycleBinEnumList **ppEnumList);
|
||||
|
||||
END_INTERFACE
|
||||
};
|
||||
|
||||
EXTERN_C const IID IID_IRecycleBinFile;
|
||||
EXTERN_C const IID IID_IRecycleBinEnumList;
|
||||
EXTERN_C const IID IID_IRecycleBin;
|
||||
|
||||
#if (!defined(__cplusplus) || defined(CINTERFACE)) && defined(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)
|
||||
|
||||
#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)
|
||||
|
||||
#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
|
10
lib/recyclebin/recyclebin.rbuild
Normal file
10
lib/recyclebin/recyclebin.rbuild
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
|
||||
<module name="recyclebin" type="staticlibrary">
|
||||
<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>recyclebin_v5_enumerator.c</file>
|
||||
</module>
|
218
lib/recyclebin/recyclebin_generic.c
Normal file
218
lib/recyclebin/recyclebin_generic.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
|
||||
|
||||
struct RecycleBinGeneric
|
||||
{
|
||||
ULONG ref;
|
||||
IRecycleBin recycleBinImpl;
|
||||
};
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBinGeneric_RecycleBin_QueryInterface(
|
||||
IRecycleBin *This,
|
||||
REFIID riid,
|
||||
void **ppvObject)
|
||||
{
|
||||
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
|
||||
|
||||
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
|
||||
|
||||
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
|
||||
RecycleBinGeneric_RecycleBin_AddRef(
|
||||
IRecycleBin *This)
|
||||
{
|
||||
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
|
||||
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
|
||||
TRACE("(%p)\n", This);
|
||||
return refCount;
|
||||
}
|
||||
|
||||
static VOID
|
||||
RecycleBinGeneric_Destructor(
|
||||
struct RecycleBinGeneric *s)
|
||||
{
|
||||
TRACE("(%p)\n", s);
|
||||
|
||||
CoTaskMemFree(s);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
RecycleBinGeneric_RecycleBin_Release(
|
||||
IRecycleBin *This)
|
||||
{
|
||||
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
|
||||
ULONG refCount;
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
refCount = InterlockedDecrement((PLONG)&s->ref);
|
||||
|
||||
if (refCount == 0)
|
||||
RecycleBinGeneric_Destructor(s);
|
||||
|
||||
return refCount;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBinGeneric_RecycleBin_DeleteFile(
|
||||
IN IRecycleBin *This,
|
||||
IN LPCWSTR szFileName)
|
||||
{
|
||||
IRecycleBin *prb;
|
||||
LPWSTR szFullName = NULL;
|
||||
DWORD dwBufferLength = 0;
|
||||
DWORD len;
|
||||
WCHAR szVolume[MAX_PATH];
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p, %s)\n", This, debugstr_w(szFileName));
|
||||
|
||||
/* 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
|
||||
RecycleBinGeneric_RecycleBin_EmptyRecycleBin(
|
||||
IN IRecycleBin *This)
|
||||
{
|
||||
WCHAR szVolumeName[MAX_PATH];
|
||||
DWORD dwLogicalDrives, i;
|
||||
IRecycleBin *prb;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
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
|
||||
RecycleBinGeneric_RecycleBin_EnumObjects(
|
||||
IN IRecycleBin *This,
|
||||
OUT IRecycleBinEnumList **ppEnumList)
|
||||
{
|
||||
TRACE("(%p, %p)\n", This, ppEnumList);
|
||||
return RecycleBinGenericEnum_Constructor(ppEnumList);
|
||||
}
|
||||
|
||||
CONST_VTBL struct IRecycleBinVtbl RecycleBinGenericVtbl =
|
||||
{
|
||||
RecycleBinGeneric_RecycleBin_QueryInterface,
|
||||
RecycleBinGeneric_RecycleBin_AddRef,
|
||||
RecycleBinGeneric_RecycleBin_Release,
|
||||
RecycleBinGeneric_RecycleBin_DeleteFile,
|
||||
RecycleBinGeneric_RecycleBin_EmptyRecycleBin,
|
||||
RecycleBinGeneric_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;
|
||||
}
|
237
lib/recyclebin/recyclebin_generic_enumerator.c
Normal file
237
lib/recyclebin/recyclebin_generic_enumerator.c
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* 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_private.h"
|
||||
#include <stdio.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
|
||||
|
||||
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);
|
||||
|
||||
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
|
||||
|
||||
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);
|
||||
TRACE("(%p)\n", This);
|
||||
return refCount;
|
||||
}
|
||||
|
||||
static VOID
|
||||
RecycleBinGenericEnum_Destructor(
|
||||
struct RecycleBinGenericEnum *s)
|
||||
{
|
||||
TRACE("(%p)\n", s);
|
||||
|
||||
if (s->current)
|
||||
IRecycleBinEnumList_Release(s->current);
|
||||
CoTaskMemFree(s);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
RecycleBinGenericEnum_RecycleBinEnumList_Release(
|
||||
IN IRecycleBinEnumList *This)
|
||||
{
|
||||
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
|
||||
ULONG refCount;
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
refCount = InterlockedDecrement((PLONG)&s->ref);
|
||||
|
||||
if (refCount == 0)
|
||||
RecycleBinGenericEnum_Destructor(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;
|
||||
|
||||
TRACE("(%p, %u, %p, %p)\n", This, celt, rgelt, pceltFetched);
|
||||
|
||||
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);
|
||||
TRACE("(%p, %u)\n", This, celt);
|
||||
s->skip += celt;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBinGenericEnum_RecycleBinEnumList_Reset(
|
||||
IN IRecycleBinEnumList *This)
|
||||
{
|
||||
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
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
|
||||
RecycleBinGenericEnum_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);
|
||||
}
|
40
lib/recyclebin/recyclebin_private.h
Normal file
40
lib/recyclebin/recyclebin_private.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "recyclebin.h"
|
||||
#include "sddl.h"
|
||||
#include <wine/debug.h>
|
||||
|
||||
/* Defines */
|
||||
|
||||
#define RECYCLE_BIN_DIRECTORY_WITH_ACL L"RECYCLER"
|
||||
#define RECYCLE_BIN_DIRECTORY_WITHOUT_ACL L"RECYCLED"
|
||||
#define RECYCLE_BIN_FILE_NAME L"INFO2"
|
||||
|
||||
#define ROUND_UP(N, S) ((( (N) + (S) - 1) / (S) ) * (S) )
|
||||
|
||||
/* Structures on disk */
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
typedef struct _INFO2_HEADER
|
||||
{
|
||||
DWORD dwVersion;
|
||||
DWORD dwNumberOfEntries; /* unused */
|
||||
DWORD dwHighestRecordUniqueId; /* unused */
|
||||
DWORD dwRecordSize;
|
||||
DWORD dwTotalLogicalSize;
|
||||
} INFO2_HEADER, *PINFO2_HEADER;
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
/* recyclebin_generic.c */
|
||||
|
||||
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown);
|
||||
|
||||
/* recyclebin_generic_enumerator.c */
|
||||
|
||||
HRESULT RecycleBinGenericEnum_Constructor(OUT IRecycleBinEnumList **pprbel);
|
||||
|
||||
/* recyclebin_v5.c */
|
||||
|
||||
HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown);
|
803
lib/recyclebin/recyclebin_v5.c
Normal file
803
lib/recyclebin/recyclebin_v5.c
Normal file
|
@ -0,0 +1,803 @@
|
|||
/*
|
||||
* PROJECT: Recycle bin management
|
||||
* LICENSE: GPL v2 - See COPYING in the top level directory
|
||||
* FILE: lib/recyclebin/recyclebin_v5.c
|
||||
* PURPOSE: Deals with recycle bins of Windows 2000/XP/2003
|
||||
* PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
|
||||
*/
|
||||
|
||||
#define COBJMACROS
|
||||
#include "recyclebin_v5.h"
|
||||
#include <stdio.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
|
||||
|
||||
static BOOL
|
||||
IntDeleteRecursive(
|
||||
IN LPCWSTR FullName)
|
||||
{
|
||||
DWORD RemovableAttributes = FILE_ATTRIBUTE_READONLY;
|
||||
WIN32_FIND_DATAW FindData;
|
||||
HANDLE hSearch = INVALID_HANDLE_VALUE;
|
||||
LPWSTR FullPath = NULL, pFilePart;
|
||||
DWORD FileAttributes;
|
||||
SIZE_T dwLength;
|
||||
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)
|
||||
{
|
||||
/* Prepare file specification */
|
||||
dwLength = wcslen(FullName);
|
||||
FullPath = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1 + MAX_PATH + 1) * sizeof(WCHAR));
|
||||
if (!FullPath)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto cleanup;
|
||||
}
|
||||
wcscpy(FullPath, FullName);
|
||||
if (FullPath[dwLength - 1] != '\\')
|
||||
{
|
||||
FullPath[dwLength] = '\\';
|
||||
dwLength++;
|
||||
}
|
||||
pFilePart = &FullPath[dwLength];
|
||||
wcscpy(pFilePart, L"*");
|
||||
|
||||
/* Enumerate contents, and delete it */
|
||||
hSearch = FindFirstFileW(FullPath, &FindData);
|
||||
if (hSearch == INVALID_HANDLE_VALUE)
|
||||
goto cleanup;
|
||||
do
|
||||
{
|
||||
if (!(FindData.cFileName[0] == '.' &&
|
||||
(FindData.cFileName[1] == '\0' || (FindData.cFileName[1] == '.' && FindData.cFileName[2] == '\0'))))
|
||||
{
|
||||
wcscpy(pFilePart, FindData.cFileName);
|
||||
if (!IntDeleteRecursive(FullPath))
|
||||
{
|
||||
FindClose(hSearch);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (FindNextFileW(hSearch, &FindData));
|
||||
FindClose(hSearch);
|
||||
if (GetLastError() != ERROR_NO_MORE_FILES)
|
||||
goto cleanup;
|
||||
|
||||
/* Remove (now empty) directory */
|
||||
if (!RemoveDirectoryW(FullName))
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!DeleteFileW(FullName))
|
||||
goto cleanup;
|
||||
}
|
||||
ret = TRUE;
|
||||
|
||||
cleanup:
|
||||
HeapFree(GetProcessHeap(), 0, FullPath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct RecycleBin5
|
||||
{
|
||||
ULONG ref;
|
||||
IRecycleBin5 recycleBinImpl;
|
||||
HANDLE hInfo;
|
||||
HANDLE hInfoMapped;
|
||||
|
||||
DWORD EnumeratorCount;
|
||||
|
||||
LPWSTR VolumePath;
|
||||
WCHAR Folder[ANY_SIZE]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */
|
||||
};
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBin5_RecycleBin5_QueryInterface(
|
||||
IRecycleBin5 *This,
|
||||
REFIID riid,
|
||||
void **ppvObject)
|
||||
{
|
||||
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
|
||||
|
||||
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
|
||||
|
||||
if (!ppvObject)
|
||||
return E_POINTER;
|
||||
|
||||
if (IsEqualIID(riid, &IID_IUnknown))
|
||||
*ppvObject = &s->recycleBinImpl;
|
||||
else if (IsEqualIID(riid, &IID_IRecycleBin))
|
||||
*ppvObject = &s->recycleBinImpl;
|
||||
else if (IsEqualIID(riid, &IID_IRecycleBin5))
|
||||
*ppvObject = &s->recycleBinImpl;
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
IUnknown_AddRef(This);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
RecycleBin5_RecycleBin5_AddRef(
|
||||
IRecycleBin5 *This)
|
||||
{
|
||||
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
|
||||
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
|
||||
TRACE("(%p)\n", This);
|
||||
return refCount;
|
||||
}
|
||||
|
||||
static VOID
|
||||
RecycleBin5_Destructor(
|
||||
struct RecycleBin5 *s)
|
||||
{
|
||||
TRACE("(%p)\n", s);
|
||||
|
||||
if (s->hInfo && s->hInfo != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(s->hInfo);
|
||||
if (s->hInfoMapped)
|
||||
CloseHandle(s->hInfoMapped);
|
||||
CoTaskMemFree(s);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
RecycleBin5_RecycleBin5_Release(
|
||||
IRecycleBin5 *This)
|
||||
{
|
||||
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
|
||||
ULONG refCount;
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
refCount = InterlockedDecrement((PLONG)&s->ref);
|
||||
|
||||
if (refCount == 0)
|
||||
RecycleBin5_Destructor(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;
|
||||
PINFO2_HEADER pHeader = NULL;
|
||||
PDELETED_FILE_RECORD pDeletedFile;
|
||||
ULARGE_INTEGER FileSize;
|
||||
DWORD dwAttributes, dwEntries;
|
||||
SYSTEMTIME SystemTime;
|
||||
DWORD ClusterSize, BytesPerSector, SectorsPerCluster;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p, %s)\n", This, debugstr_w(szFileName));
|
||||
|
||||
if (s->EnumeratorCount != 0)
|
||||
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
|
||||
|
||||
/* Get full file name */
|
||||
while (TRUE)
|
||||
{
|
||||
len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, &lpFilePart);
|
||||
if (len == 0)
|
||||
{
|
||||
if (szFullName)
|
||||
CoTaskMemFree(szFullName);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
else if (len < dwBufferLength)
|
||||
break;
|
||||
if (szFullName)
|
||||
CoTaskMemFree(szFullName);
|
||||
dwBufferLength = len;
|
||||
szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
|
||||
if (!szFullName)
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
|
||||
/* Check if file exists */
|
||||
dwAttributes = GetFileAttributesW(szFullName);
|
||||
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
if (dwBufferLength < 2 || szFullName[1] != ':')
|
||||
{
|
||||
/* Not a local file */
|
||||
CoTaskMemFree(szFullName);
|
||||
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
|
||||
}
|
||||
|
||||
hFile = CreateFileW(szFullName, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Increase INFO2 file size */
|
||||
CloseHandle(s->hInfoMapped);
|
||||
SetFilePointer(s->hInfo, sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
|
||||
SetEndOfFile(s->hInfo);
|
||||
s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
|
||||
if (!s->hInfoMapped)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Open INFO2 file */
|
||||
pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
|
||||
if (!pHeader)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Get number of entries */
|
||||
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
|
||||
if (FileSize.u.LowPart < sizeof(INFO2_HEADER))
|
||||
{
|
||||
UnmapViewOfFile(pHeader);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)) - 1;
|
||||
pDeletedFile = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries;
|
||||
|
||||
/* Get file size */
|
||||
#if 0
|
||||
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)
|
||||
{
|
||||
/* Yes, this recyclebin can't support this file */
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
goto cleanup;
|
||||
}
|
||||
pHeader->dwTotalLogicalSize += FileSize.u.LowPart;
|
||||
|
||||
/* Generate new name */
|
||||
Extension = wcsrchr(szFullName, '.');
|
||||
ZeroMemory(pDeletedFile, sizeof(DELETED_FILE_RECORD));
|
||||
if (dwEntries == 0)
|
||||
pDeletedFile->dwRecordUniqueId = 0;
|
||||
else
|
||||
{
|
||||
PDELETED_FILE_RECORD pLastDeleted = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries - 1;
|
||||
pDeletedFile->dwRecordUniqueId = pLastDeleted->dwRecordUniqueId + 1;
|
||||
}
|
||||
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 */
|
||||
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, &pDeletedFile->DeletionTime))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
pDeletedFile->dwPhysicalFileSize = ROUND_UP(FileSize.u.LowPart, ClusterSize);
|
||||
|
||||
/* Set name */
|
||||
wcscpy(pDeletedFile->FileNameW, szFullName);
|
||||
if (WideCharToMultiByte(CP_ACP, 0, pDeletedFile->FileNameW, -1, pDeletedFile->FileNameA, MAX_PATH, NULL, NULL) == 0)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Move file */
|
||||
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);
|
||||
CoTaskMemFree(szFullName);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBin5_RecycleBin5_EmptyRecycleBin(
|
||||
IN IRecycleBin5 *This)
|
||||
{
|
||||
IRecycleBinEnumList *prbel;
|
||||
IRecycleBinFile *prbf;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
hr = IRecycleBin5_EnumObjects(This, &prbel);
|
||||
if (!SUCCEEDED(hr))
|
||||
return hr;
|
||||
hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
|
||||
IRecycleBinEnumList_Release(prbel);
|
||||
if (hr == S_FALSE)
|
||||
return S_OK;
|
||||
hr = IRecycleBinFile_Delete(prbf);
|
||||
IRecycleBinFile_Release(prbf);
|
||||
if (!SUCCEEDED(hr))
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBin5_RecycleBin5_EnumObjects(
|
||||
IN IRecycleBin5 *This,
|
||||
OUT IRecycleBinEnumList **ppEnumList)
|
||||
{
|
||||
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
|
||||
IRecycleBinEnumList *prbel;
|
||||
HRESULT hr;
|
||||
IUnknown *pUnk;
|
||||
|
||||
TRACE("(%p, %p)\n", This, ppEnumList);
|
||||
|
||||
hr = RecycleBin5Enum_Constructor(This, s->hInfo, s->hInfoMapped, s->Folder, &pUnk);
|
||||
if (!SUCCEEDED(hr))
|
||||
return hr;
|
||||
|
||||
hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBinEnumList, (void **)&prbel);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
s->EnumeratorCount++;
|
||||
*ppEnumList = prbel;
|
||||
}
|
||||
IUnknown_Release(pUnk);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBin5_RecycleBin5_Delete(
|
||||
IN IRecycleBin5 *This,
|
||||
IN LPCWSTR pDeletedFileName,
|
||||
IN DELETED_FILE_RECORD *pDeletedFile)
|
||||
{
|
||||
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
|
||||
ULARGE_INTEGER FileSize;
|
||||
PINFO2_HEADER pHeader;
|
||||
DELETED_FILE_RECORD *pRecord, *pLast;
|
||||
DWORD dwEntries, i;
|
||||
|
||||
TRACE("(%p, %s, %p)\n", This, debugstr_w(pDeletedFileName), pDeletedFile);
|
||||
|
||||
if (s->EnumeratorCount != 0)
|
||||
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
|
||||
|
||||
pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
|
||||
if (!pHeader)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
|
||||
if (FileSize.u.LowPart == 0)
|
||||
{
|
||||
UnmapViewOfFile(pHeader);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
|
||||
|
||||
pRecord = (DELETED_FILE_RECORD *)(pHeader + 1);
|
||||
for (i = 0; i < dwEntries; i++)
|
||||
{
|
||||
if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId)
|
||||
{
|
||||
/* Delete file */
|
||||
if (!IntDeleteRecursive(pDeletedFileName))
|
||||
{
|
||||
UnmapViewOfFile(pHeader);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
/* Clear last entry in the file */
|
||||
MoveMemory(pRecord, pRecord + 1, (dwEntries - i - 1) * sizeof(DELETED_FILE_RECORD));
|
||||
pLast = pRecord + (dwEntries - i - 1);
|
||||
ZeroMemory(pLast, sizeof(DELETED_FILE_RECORD));
|
||||
UnmapViewOfFile(pHeader);
|
||||
|
||||
/* Resize file */
|
||||
CloseHandle(s->hInfoMapped);
|
||||
SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
|
||||
SetEndOfFile(s->hInfo);
|
||||
s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
|
||||
if (!s->hInfoMapped)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return S_OK;
|
||||
}
|
||||
pRecord++;
|
||||
}
|
||||
UnmapViewOfFile(pHeader);
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBin5_RecycleBin5_Restore(
|
||||
IN IRecycleBin5 *This,
|
||||
IN LPCWSTR pDeletedFileName,
|
||||
IN DELETED_FILE_RECORD *pDeletedFile)
|
||||
{
|
||||
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
|
||||
ULARGE_INTEGER FileSize;
|
||||
PINFO2_HEADER pHeader;
|
||||
DELETED_FILE_RECORD *pRecord, *pLast;
|
||||
DWORD dwEntries, i;
|
||||
SHFILEOPSTRUCTW op;
|
||||
|
||||
TRACE("(%p, %s, %p)\n", This, debugstr_w(pDeletedFileName), pDeletedFile);
|
||||
|
||||
if (s->EnumeratorCount != 0)
|
||||
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
|
||||
|
||||
pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
|
||||
if (!pHeader)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
|
||||
if (FileSize.u.LowPart == 0)
|
||||
{
|
||||
UnmapViewOfFile(pHeader);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
|
||||
|
||||
pRecord = (DELETED_FILE_RECORD *)(pHeader + 1);
|
||||
for (i = 0; i < dwEntries; i++)
|
||||
{
|
||||
if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId)
|
||||
{
|
||||
/* Restore file */
|
||||
ZeroMemory(&op, sizeof(op));
|
||||
op.wFunc = FO_COPY;
|
||||
op.pFrom = pDeletedFileName;
|
||||
op.pTo = pDeletedFile->FileNameW;
|
||||
|
||||
if (!SHFileOperationW(&op))
|
||||
{
|
||||
UnmapViewOfFile(pHeader);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
/* Clear last entry in the file */
|
||||
MoveMemory(pRecord, pRecord + 1, (dwEntries - i - 1) * sizeof(DELETED_FILE_RECORD));
|
||||
pLast = pRecord + (dwEntries - i - 1);
|
||||
ZeroMemory(pLast, sizeof(DELETED_FILE_RECORD));
|
||||
UnmapViewOfFile(pHeader);
|
||||
|
||||
/* Resize file */
|
||||
CloseHandle(s->hInfoMapped);
|
||||
SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
|
||||
SetEndOfFile(s->hInfo);
|
||||
s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
|
||||
if (!s->hInfoMapped)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
return S_OK;
|
||||
}
|
||||
pRecord++;
|
||||
}
|
||||
|
||||
UnmapViewOfFile(pHeader);
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBin5_RecycleBin5_OnClosing(
|
||||
IN IRecycleBin5 *This,
|
||||
IN IRecycleBinEnumList *prbel)
|
||||
{
|
||||
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
|
||||
TRACE("(%p, %p)\n", This, prbel);
|
||||
s->EnumeratorCount--;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CONST_VTBL struct IRecycleBin5Vtbl RecycleBin5Vtbl =
|
||||
{
|
||||
RecycleBin5_RecycleBin5_QueryInterface,
|
||||
RecycleBin5_RecycleBin5_AddRef,
|
||||
RecycleBin5_RecycleBin5_Release,
|
||||
RecycleBin5_RecycleBin5_DeleteFile,
|
||||
RecycleBin5_RecycleBin5_EmptyRecycleBin,
|
||||
RecycleBin5_RecycleBin5_EnumObjects,
|
||||
RecycleBin5_RecycleBin5_Delete,
|
||||
RecycleBin5_RecycleBin5_Restore,
|
||||
RecycleBin5_RecycleBin5_OnClosing,
|
||||
};
|
||||
|
||||
static HRESULT
|
||||
RecycleBin5_Create(
|
||||
IN LPCWSTR Folder,
|
||||
IN PSID OwnerSid OPTIONAL)
|
||||
{
|
||||
LPWSTR BufferName = NULL;
|
||||
LPWSTR Separator; /* Pointer into BufferName buffer */
|
||||
LPWSTR FileName; /* Pointer into BufferName buffer */
|
||||
LPCSTR DesktopIniContents = "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
|
||||
INFO2_HEADER Info2Contents[] = { { 5, 0, 0, 0x320, 0 } };
|
||||
DWORD BytesToWrite, BytesWritten, Needed;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
HRESULT hr;
|
||||
|
||||
Needed = (wcslen(Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR);
|
||||
BufferName = HeapAlloc(GetProcessHeap(), 0, Needed);
|
||||
if (!BufferName)
|
||||
{
|
||||
hr = ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
wcscpy(BufferName, Folder);
|
||||
Separator = wcsstr(&BufferName[3], L"\\");
|
||||
if (Separator)
|
||||
*Separator = UNICODE_NULL;
|
||||
if (!CreateDirectoryW(BufferName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
SetFileAttributesW(BufferName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
|
||||
if (Separator)
|
||||
{
|
||||
*Separator = L'\\';
|
||||
if (!CreateDirectoryW(BufferName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (OwnerSid)
|
||||
{
|
||||
//DWORD rc;
|
||||
|
||||
/* Add ACL to allow only user/SYSTEM to open it */
|
||||
/* FIXME: rc = SetNamedSecurityInfo(
|
||||
BufferName,
|
||||
SE_FILE_OBJECT,
|
||||
???,
|
||||
OwnerSid,
|
||||
NULL,
|
||||
???,
|
||||
???);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(rc);
|
||||
goto cleanup;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
wcscat(BufferName, L"\\");
|
||||
FileName = &BufferName[wcslen(BufferName)];
|
||||
|
||||
/* Create desktop.ini */
|
||||
wcscpy(FileName, L"desktop.ini");
|
||||
hFile = CreateFileW(BufferName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
BytesToWrite = strlen(DesktopIniContents);
|
||||
if (!WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten, NULL))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
if (BytesWritten != BytesToWrite)
|
||||
{
|
||||
hr = E_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* Create empty INFO2 file */
|
||||
wcscpy(FileName, RECYCLE_BIN_FILE_NAME);
|
||||
hFile = CreateFileW(BufferName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
BytesToWrite = sizeof(Info2Contents);
|
||||
if (!WriteFile(hFile, Info2Contents, (DWORD)BytesToWrite, &BytesWritten, NULL))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
if (BytesWritten == BytesToWrite)
|
||||
hr = S_OK;
|
||||
else
|
||||
hr = E_FAIL;
|
||||
|
||||
cleanup:
|
||||
HeapFree(GetProcessHeap(), 0, BufferName);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hFile);
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown)
|
||||
{
|
||||
struct RecycleBin5 *s = NULL;
|
||||
DWORD FileSystemFlags;
|
||||
LPCWSTR RecycleBinDirectory;
|
||||
HANDLE tokenHandle = INVALID_HANDLE_VALUE;
|
||||
PTOKEN_USER TokenUserInfo = NULL;
|
||||
LPWSTR StringSid = NULL, p;
|
||||
DWORD Needed, DirectoryLength;
|
||||
INT len;
|
||||
HRESULT hr;
|
||||
|
||||
if (!ppUnknown)
|
||||
return E_POINTER;
|
||||
|
||||
/* Get information about file system */
|
||||
if (!GetVolumeInformationW(
|
||||
VolumePath,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&FileSystemFlags,
|
||||
NULL,
|
||||
0))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
if (!(FileSystemFlags & FILE_PERSISTENT_ACLS))
|
||||
RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL;
|
||||
else
|
||||
{
|
||||
RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL;
|
||||
|
||||
/* Get user SID */
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
if (GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &Needed))
|
||||
{
|
||||
hr = E_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed);
|
||||
if (!TokenUserInfo)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
if (!GetTokenInformation(tokenHandle, TokenUser, TokenUserInfo, (DWORD)Needed, &Needed))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
if (!ConvertSidToStringSidW(TokenUserInfo->User.Sid, &StringSid))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
DirectoryLength = wcslen(VolumePath) + wcslen(RecycleBinDirectory) + 1;
|
||||
if (StringSid)
|
||||
DirectoryLength += wcslen(StringSid) + 1;
|
||||
DirectoryLength += 1 + wcslen(RECYCLE_BIN_FILE_NAME);
|
||||
DirectoryLength += wcslen(VolumePath) + 1;
|
||||
Needed = (DirectoryLength + 1) * sizeof(WCHAR);
|
||||
|
||||
s = CoTaskMemAlloc(sizeof(struct RecycleBin5) + Needed);
|
||||
if (!s)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
ZeroMemory(s, sizeof(struct RecycleBin5));
|
||||
s->recycleBinImpl.lpVtbl = &RecycleBin5Vtbl;
|
||||
s->ref = 1;
|
||||
if (StringSid)
|
||||
len = swprintf(s->Folder, L"%s%s\\%s", VolumePath, RecycleBinDirectory, StringSid);
|
||||
else
|
||||
len = swprintf(s->Folder, L"%s%s", VolumePath, RecycleBinDirectory);
|
||||
p = &s->Folder[len];
|
||||
wcscpy(p, L"\\" RECYCLE_BIN_FILE_NAME);
|
||||
s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (s->hInfo == INVALID_HANDLE_VALUE && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND))
|
||||
{
|
||||
*p = UNICODE_NULL;
|
||||
hr = RecycleBin5_Create(s->Folder, TokenUserInfo ? TokenUserInfo->User.Sid : NULL);
|
||||
*p = L'\\';
|
||||
if (!SUCCEEDED(hr))
|
||||
goto cleanup;
|
||||
s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
}
|
||||
if (s->hInfo == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
|
||||
if (!s->hInfoMapped)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
*p = UNICODE_NULL;
|
||||
s->VolumePath = p + 1;
|
||||
wcscpy(s->VolumePath, VolumePath);
|
||||
|
||||
*ppUnknown = (IUnknown *)&s->recycleBinImpl;
|
||||
|
||||
hr = S_OK;
|
||||
|
||||
cleanup:
|
||||
if (tokenHandle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(tokenHandle);
|
||||
HeapFree(GetProcessHeap(), 0, TokenUserInfo);
|
||||
if (StringSid)
|
||||
LocalFree(StringSid);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
if (s)
|
||||
RecycleBin5_Destructor(s);
|
||||
}
|
||||
return hr;
|
||||
}
|
109
lib/recyclebin/recyclebin_v5.h
Normal file
109
lib/recyclebin/recyclebin_v5.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
/* Recycle bin management
|
||||
* This file is under the GPLv2 licence
|
||||
* Copyright (C) 2006 Hervé Poussineau <hpoussin@reactos.org>
|
||||
*/
|
||||
|
||||
#include "recyclebin_private.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
/* MS Windows 2000/XP/2003 */
|
||||
typedef struct _DELETED_FILE_RECORD
|
||||
{
|
||||
CHAR FileNameA[MAX_PATH];
|
||||
DWORD dwRecordUniqueId;
|
||||
DWORD dwDriveNumber;
|
||||
FILETIME DeletionTime;
|
||||
DWORD dwPhysicalFileSize;
|
||||
WCHAR FileNameW[MAX_PATH];
|
||||
} DELETED_FILE_RECORD, *PDELETED_FILE_RECORD;
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
/* 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 *prbel);
|
||||
} 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
|
||||
RecycleBin5Enum_Constructor(
|
||||
IN IRecycleBin5 *prb,
|
||||
IN HANDLE hInfo,
|
||||
IN HANDLE hInfoMapped,
|
||||
IN LPCWSTR szPrefix,
|
||||
OUT IUnknown **ppUnknown);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
486
lib/recyclebin/recyclebin_v5_enumerator.c
Normal file
486
lib/recyclebin/recyclebin_v5_enumerator.c
Normal file
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
|
||||
|
||||
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);
|
||||
|
||||
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
|
||||
|
||||
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);
|
||||
TRACE("(%p)\n", This);
|
||||
return refCount;
|
||||
}
|
||||
|
||||
static VOID
|
||||
RecycleBin5File_Destructor(
|
||||
struct RecycleBin5File *s)
|
||||
{
|
||||
TRACE("(%p)\n", s);
|
||||
|
||||
IRecycleBin5_Release(s->recycleBin);
|
||||
CoTaskMemFree(s);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
RecycleBin5File_RecycleBinFile_Release(
|
||||
IN IRecycleBinFile *This)
|
||||
{
|
||||
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
|
||||
ULONG refCount;
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
refCount = InterlockedDecrement((PLONG)&s->ref);
|
||||
|
||||
if (refCount == 0)
|
||||
RecycleBin5File_Destructor(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;
|
||||
|
||||
TRACE("(%p, %p)\n", This, pLastModificationTime);
|
||||
|
||||
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);
|
||||
TRACE("(%p, %p)\n", This, pDeletionTime);
|
||||
*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;
|
||||
|
||||
TRACE("(%p, %p)\n", This, pFileSize);
|
||||
|
||||
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);
|
||||
TRACE("(%p, %p)\n", This, pPhysicalFileSize);
|
||||
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;
|
||||
|
||||
TRACE("(%p, %p)\n", This, pAttributes);
|
||||
|
||||
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 SIZE_T BufferSize,
|
||||
IN OUT LPWSTR Buffer,
|
||||
OUT SIZE_T *RequiredSize)
|
||||
{
|
||||
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
|
||||
DWORD dwRequired;
|
||||
|
||||
TRACE("(%p, %u, %p, %p)\n", This, BufferSize, Buffer, RequiredSize);
|
||||
|
||||
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);
|
||||
TRACE("(%p)\n", This);
|
||||
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);
|
||||
TRACE("(%p)\n", This);
|
||||
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
|
||||
RecycleBin5File_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);
|
||||
if (GetFileAttributesW(s->FullName) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
RecycleBin5File_Destructor(s);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
|
||||
|
||||
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);
|
||||
TRACE("(%p)\n", This);
|
||||
return refCount;
|
||||
}
|
||||
|
||||
static VOID
|
||||
RecycleBin5Enum_Destructor(
|
||||
struct RecycleBin5Enum *s)
|
||||
{
|
||||
TRACE("(%p)\n", s);
|
||||
|
||||
IRecycleBin5_OnClosing(s->recycleBin, &s->recycleBinEnumImpl);
|
||||
UnmapViewOfFile(s->pInfo);
|
||||
IRecycleBin5_Release(s->recycleBin);
|
||||
CoTaskMemFree(s);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
RecycleBin5Enum_RecycleBinEnumList_Release(
|
||||
IN IRecycleBinEnumList *This)
|
||||
{
|
||||
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
|
||||
ULONG refCount;
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
refCount = InterlockedDecrement((PLONG)&s->ref);
|
||||
|
||||
if (refCount == 0)
|
||||
RecycleBin5Enum_Destructor(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;
|
||||
|
||||
TRACE("(%p, %u, %p, %p)\n", This, celt, rgelt, pceltFetched);
|
||||
|
||||
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 = RecycleBin5File_Constructor(s->recycleBin, s->szPrefix, pDeletedFile, &rgelt[fetched]);
|
||||
if (SUCCEEDED(hr))
|
||||
fetched++;
|
||||
pDeletedFile++;
|
||||
}
|
||||
|
||||
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);
|
||||
TRACE("(%p, %u)\n", This, celt);
|
||||
s->dwCurrent += celt;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
RecycleBin5Enum_RecycleBinEnumList_Reset(
|
||||
IN IRecycleBinEnumList *This)
|
||||
{
|
||||
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
|
||||
TRACE("(%p)\n", This);
|
||||
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
|
||||
RecycleBin5Enum_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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue