[SHELL32] RecycleBin5: Make it C++ (#7174)

Modernize code.
JIRA issue: CORE-19595
Rewrite RecycleBin5 in C++.
This commit is contained in:
Katayama Hirofumi MZ 2024-07-29 09:20:36 +09:00 committed by GitHub
parent 22b913928f
commit 90a5b9a83f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 193 additions and 210 deletions

View file

@ -8,11 +8,12 @@ list(APPEND SOURCE
recyclebin.c recyclebin.c
recyclebin_generic.cpp recyclebin_generic.cpp
recyclebin_generic_enumerator.cpp recyclebin_generic_enumerator.cpp
recyclebin_v5.c recyclebin_v5.cpp
recyclebin_v5_enumerator.cpp recyclebin_v5_enumerator.cpp
recyclebin_private.h) recyclebin_private.h)
add_library(recyclebin ${SOURCE} guid.c) add_library(recyclebin ${SOURCE} guid.c)
target_link_libraries(recyclebin PRIVATE atl_classes)
add_pch(recyclebin recyclebin_private.h SOURCE) add_pch(recyclebin recyclebin_private.h SOURCE)
add_dependencies(recyclebin psdk) add_dependencies(recyclebin psdk)
target_link_libraries(recyclebin PRIVATE atl_classes) target_link_libraries(recyclebin PRIVATE atl_classes)

View file

@ -50,6 +50,7 @@ HRESULT RecycleBinGenericEnum_Constructor(OUT IRecycleBinEnumList **pprbel);
/* recyclebin_v5.c */ /* recyclebin_v5.c */
HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown); EXTERN_C
HRESULT RecycleBin5_Constructor(_In_ LPCWSTR VolumePath, _Out_ IUnknown **ppUnknown);
#endif /* _RECYCLEBIN_PRIVATE_H_ */ #endif /* _RECYCLEBIN_PRIVATE_H_ */

View file

@ -1,13 +1,14 @@
/* /*
* PROJECT: Recycle bin management * PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* FILE: lib/recyclebin/recyclebin_v5.c
* PURPOSE: Deals with recycle bins of Windows 2000/XP/2003 * PURPOSE: Deals with recycle bins of Windows 2000/XP/2003
* PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org) * COPYRIGHT: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
* Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/ */
#include "recyclebin_private.h" #include "recyclebin_private.h"
#include <atlstr.h>
#include <shlwapi.h>
#include "sddl.h" #include "sddl.h"
static BOOL static BOOL
@ -38,7 +39,7 @@ IntDeleteRecursive(
{ {
/* Prepare file specification */ /* Prepare file specification */
dwLength = wcslen(FullName); dwLength = wcslen(FullName);
FullPath = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1 + MAX_PATH + 1) * sizeof(WCHAR)); FullPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (dwLength + 1 + MAX_PATH + 1) * sizeof(WCHAR));
if (!FullPath) if (!FullPath)
{ {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
@ -91,99 +92,97 @@ cleanup:
return ret; return ret;
} }
struct RecycleBin5 class RecycleBin5 : public IRecycleBin5
{ {
ULONG ref; public:
IRecycleBin5 recycleBinImpl; RecycleBin5();
HANDLE hInfo; virtual ~RecycleBin5();
HANDLE hInfoMapped;
DWORD EnumeratorCount; HRESULT Init(_In_ LPCWSTR VolumePath);
LPWSTR VolumePath; /* IUnknown interface */
WCHAR Folder[ANY_SIZE]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */ STDMETHODIMP QueryInterface(_In_ REFIID riid, _Out_ void **ppvObject) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
/* IRecycleBin interface */
STDMETHODIMP DeleteFile(_In_ LPCWSTR szFileName) override;
STDMETHODIMP EmptyRecycleBin() override;
STDMETHODIMP EnumObjects(_Out_ IRecycleBinEnumList **ppEnumList) override;
/* IRecycleBin5 interface */
STDMETHODIMP Delete(
_In_ LPCWSTR pDeletedFileName,
_In_ DELETED_FILE_RECORD *pDeletedFile) override;
STDMETHODIMP Restore(
_In_ LPCWSTR pDeletedFileName,
_In_ DELETED_FILE_RECORD *pDeletedFile) override;
STDMETHODIMP OnClosing(_In_ IRecycleBinEnumList *prbel) override;
protected:
LONG m_ref;
HANDLE m_hInfo;
HANDLE m_hInfoMapped;
DWORD m_EnumeratorCount;
CStringW m_VolumePath;
CStringW m_Folder; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */
}; };
static HRESULT STDMETHODCALLTYPE STDMETHODIMP RecycleBin5::QueryInterface(_In_ REFIID riid, _Out_ void **ppvObject)
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);
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
if (!ppvObject) if (!ppvObject)
return E_POINTER; return E_POINTER;
if (IsEqualIID(riid, &IID_IUnknown)) if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRecycleBin))
*ppvObject = &s->recycleBinImpl; *ppvObject = static_cast<IRecycleBin5 *>(this);
else if (IsEqualIID(riid, &IID_IRecycleBin)) else if (IsEqualIID(riid, IID_IRecycleBin5))
*ppvObject = &s->recycleBinImpl; *ppvObject = static_cast<IRecycleBin5 *>(this);
else if (IsEqualIID(riid, &IID_IRecycleBin5))
*ppvObject = &s->recycleBinImpl;
else else
{ {
*ppvObject = NULL; *ppvObject = NULL;
return E_NOINTERFACE; return E_NOINTERFACE;
} }
IUnknown_AddRef(This); AddRef();
return S_OK; return S_OK;
} }
static ULONG STDMETHODCALLTYPE STDMETHODIMP_(ULONG) RecycleBin5::AddRef()
RecycleBin5_RecycleBin5_AddRef(
IRecycleBin5 *This)
{ {
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); TRACE("(%p)\n", this);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref); return InterlockedIncrement(&m_ref);
TRACE("(%p)\n", This);
return refCount;
} }
static VOID RecycleBin5::~RecycleBin5()
RecycleBin5_Destructor(
struct RecycleBin5 *s)
{ {
TRACE("(%p)\n", s); TRACE("(%p)\n", this);
if (s->hInfo && s->hInfo != INVALID_HANDLE_VALUE) if (m_hInfo && m_hInfo != INVALID_HANDLE_VALUE)
CloseHandle(s->hInfo); CloseHandle(m_hInfo);
if (s->hInfoMapped) if (m_hInfoMapped)
CloseHandle(s->hInfoMapped); CloseHandle(m_hInfoMapped);
CoTaskMemFree(s);
} }
static ULONG STDMETHODCALLTYPE STDMETHODIMP_(ULONG) RecycleBin5::Release()
RecycleBin5_RecycleBin5_Release(
IRecycleBin5 *This)
{ {
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); TRACE("(%p)\n", this);
ULONG refCount;
TRACE("(%p)\n", This);
refCount = InterlockedDecrement((PLONG)&s->ref);
ULONG refCount = InterlockedDecrement(&m_ref);
if (refCount == 0) if (refCount == 0)
RecycleBin5_Destructor(s); delete this;
return refCount; return refCount;
} }
static HRESULT STDMETHODCALLTYPE STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName)
RecycleBin5_RecycleBin5_DeleteFile(
IN IRecycleBin5 *This,
IN LPCWSTR szFileName)
{ {
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
LPWSTR szFullName = NULL; LPWSTR szFullName = NULL;
DWORD dwBufferLength = 0; DWORD dwBufferLength = 0;
LPWSTR lpFilePart; LPWSTR lpFilePart;
LPCWSTR Extension; LPCWSTR Extension;
WCHAR DeletedFileName[MAX_PATH]; CStringW DeletedFileName;
WCHAR szUniqueId[64];
DWORD len; DWORD len;
HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hFile = INVALID_HANDLE_VALUE;
PINFO2_HEADER pHeader = NULL; PINFO2_HEADER pHeader = NULL;
@ -194,9 +193,9 @@ RecycleBin5_RecycleBin5_DeleteFile(
DWORD ClusterSize, BytesPerSector, SectorsPerCluster; DWORD ClusterSize, BytesPerSector, SectorsPerCluster;
HRESULT hr; HRESULT hr;
TRACE("(%p, %s)\n", This, debugstr_w(szFileName)); TRACE("(%p, %s)\n", this, debugstr_w(szFileName));
if (s->EnumeratorCount != 0) if (m_EnumeratorCount != 0)
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION); return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
/* Get full file name */ /* Get full file name */
@ -214,7 +213,7 @@ RecycleBin5_RecycleBin5_DeleteFile(
if (szFullName) if (szFullName)
CoTaskMemFree(szFullName); CoTaskMemFree(szFullName);
dwBufferLength = len; dwBufferLength = len;
szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR)); szFullName = (LPWSTR)CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
if (!szFullName) if (!szFullName)
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
} }
@ -242,18 +241,18 @@ RecycleBin5_RecycleBin5_DeleteFile(
} }
/* Increase INFO2 file size */ /* Increase INFO2 file size */
CloseHandle(s->hInfoMapped); CloseHandle(m_hInfoMapped);
SetFilePointer(s->hInfo, sizeof(DELETED_FILE_RECORD), NULL, FILE_END); SetFilePointer(m_hInfo, sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
SetEndOfFile(s->hInfo); SetEndOfFile(m_hInfo);
s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
if (!s->hInfoMapped) if (!m_hInfoMapped)
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup; goto cleanup;
} }
/* Open INFO2 file */ /* Open INFO2 file */
pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); pHeader = (PINFO2_HEADER)MapViewOfFile(m_hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
if (!pHeader) if (!pHeader)
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
@ -261,7 +260,7 @@ RecycleBin5_RecycleBin5_DeleteFile(
} }
/* Get number of entries */ /* Get number of entries */
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart); FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart);
if (FileSize.u.LowPart < sizeof(INFO2_HEADER)) if (FileSize.u.LowPart < sizeof(INFO2_HEADER))
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
@ -295,7 +294,7 @@ RecycleBin5_RecycleBin5_DeleteFile(
pHeader->dwTotalLogicalSize += FileSize.u.LowPart; pHeader->dwTotalLogicalSize += FileSize.u.LowPart;
/* Generate new name */ /* Generate new name */
Extension = wcsrchr(szFullName, '.'); Extension = PathFindExtensionW(szFullName);
ZeroMemory(pDeletedFile, sizeof(DELETED_FILE_RECORD)); ZeroMemory(pDeletedFile, sizeof(DELETED_FILE_RECORD));
if (dwEntries == 0) if (dwEntries == 0)
pDeletedFile->dwRecordUniqueId = 0; pDeletedFile->dwRecordUniqueId = 0;
@ -304,11 +303,18 @@ RecycleBin5_RecycleBin5_DeleteFile(
PDELETED_FILE_RECORD pLastDeleted = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries - 1; PDELETED_FILE_RECORD pLastDeleted = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries - 1;
pDeletedFile->dwRecordUniqueId = pLastDeleted->dwRecordUniqueId + 1; pDeletedFile->dwRecordUniqueId = pLastDeleted->dwRecordUniqueId + 1;
} }
pDeletedFile->dwDriveNumber = tolower(szFullName[0]) - 'a'; pDeletedFile->dwDriveNumber = tolower(szFullName[0]) - 'a';
_snwprintf(DeletedFileName, MAX_PATH, L"%s\\D%c%lu%s", s->Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension); _ultow(pDeletedFile->dwRecordUniqueId, szUniqueId, 10);
DeletedFileName = m_Folder;
DeletedFileName += L"\\D";
DeletedFileName += (WCHAR)(L'a' + pDeletedFile->dwDriveNumber);
DeletedFileName += szUniqueId;
DeletedFileName += Extension;
/* Get cluster size */ /* Get cluster size */
if (!GetDiskFreeSpaceW(s->VolumePath, &SectorsPerCluster, &BytesPerSector, NULL, NULL)) if (!GetDiskFreeSpaceW(m_VolumePath, &SectorsPerCluster, &BytesPerSector, NULL, NULL))
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup; goto cleanup;
@ -348,80 +354,69 @@ cleanup:
return hr; return hr;
} }
static HRESULT STDMETHODCALLTYPE STDMETHODIMP RecycleBin5::EmptyRecycleBin()
RecycleBin5_RecycleBin5_EmptyRecycleBin(
IN IRecycleBin5 *This)
{ {
IRecycleBinEnumList *prbel; TRACE("(%p)\n", this);
IRecycleBinFile *prbf;
HRESULT hr;
TRACE("(%p)\n", This);
while (TRUE) while (TRUE)
{ {
hr = IRecycleBin5_EnumObjects(This, &prbel); IRecycleBinEnumList *prbel;
HRESULT hr = EnumObjects(&prbel);
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
return hr; return hr;
hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
IRecycleBinEnumList_Release(prbel); IRecycleBinFile *prbf;
hr = prbel->Next(1, &prbf, NULL);
prbel->Release();
if (hr == S_FALSE) if (hr == S_FALSE)
return S_OK; return S_OK;
hr = IRecycleBinFile_Delete(prbf); hr = prbf->Delete();
IRecycleBinFile_Release(prbf); prbf->Release();
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
return hr; return hr;
} }
} }
static HRESULT STDMETHODCALLTYPE STDMETHODIMP RecycleBin5::EnumObjects(_Out_ IRecycleBinEnumList **ppEnumList)
RecycleBin5_RecycleBin5_EnumObjects(
IN IRecycleBin5 *This,
OUT IRecycleBinEnumList **ppEnumList)
{ {
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); TRACE("(%p, %p)\n", this, ppEnumList);
IRecycleBinEnumList *prbel;
HRESULT hr;
IUnknown *pUnk; IUnknown *pUnk;
HRESULT hr = RecycleBin5Enum_Constructor(this, m_hInfo, m_hInfoMapped, m_Folder, &pUnk);
TRACE("(%p, %p)\n", This, ppEnumList);
hr = RecycleBin5Enum_Constructor(This, s->hInfo, s->hInfoMapped, s->Folder, &pUnk);
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
return hr; return hr;
hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBinEnumList, (void **)&prbel); IRecycleBinEnumList *prbel;
hr = pUnk->QueryInterface(IID_IRecycleBinEnumList, (void **)&prbel);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
s->EnumeratorCount++; m_EnumeratorCount++;
*ppEnumList = prbel; *ppEnumList = prbel;
} }
IUnknown_Release(pUnk);
pUnk->Release();
return hr; return hr;
} }
static HRESULT STDMETHODCALLTYPE STDMETHODIMP RecycleBin5::Delete(
RecycleBin5_RecycleBin5_Delete( _In_ LPCWSTR pDeletedFileName,
IN IRecycleBin5 *This, _In_ DELETED_FILE_RECORD *pDeletedFile)
IN LPCWSTR pDeletedFileName,
IN DELETED_FILE_RECORD *pDeletedFile)
{ {
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
ULARGE_INTEGER FileSize; ULARGE_INTEGER FileSize;
PINFO2_HEADER pHeader; PINFO2_HEADER pHeader;
DELETED_FILE_RECORD *pRecord, *pLast; DELETED_FILE_RECORD *pRecord, *pLast;
DWORD dwEntries, i; DWORD dwEntries, i;
TRACE("(%p, %s, %p)\n", This, debugstr_w(pDeletedFileName), pDeletedFile); TRACE("(%p, %s, %p)\n", this, debugstr_w(pDeletedFileName), pDeletedFile);
if (s->EnumeratorCount != 0) if (m_EnumeratorCount != 0)
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION); return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); pHeader = (PINFO2_HEADER)MapViewOfFile(m_hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
if (!pHeader) if (!pHeader)
return HRESULT_FROM_WIN32(GetLastError()); return HRESULT_FROM_WIN32(GetLastError());
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart); FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart);
if (FileSize.u.LowPart == 0) if (FileSize.u.LowPart == 0)
{ {
UnmapViewOfFile(pHeader); UnmapViewOfFile(pHeader);
@ -448,11 +443,11 @@ RecycleBin5_RecycleBin5_Delete(
UnmapViewOfFile(pHeader); UnmapViewOfFile(pHeader);
/* Resize file */ /* Resize file */
CloseHandle(s->hInfoMapped); CloseHandle(m_hInfoMapped);
SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END); SetFilePointer(m_hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
SetEndOfFile(s->hInfo); SetEndOfFile(m_hInfo);
s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
if (!s->hInfoMapped) if (!m_hInfoMapped)
return HRESULT_FROM_WIN32(GetLastError()); return HRESULT_FROM_WIN32(GetLastError());
return S_OK; return S_OK;
} }
@ -462,13 +457,10 @@ RecycleBin5_RecycleBin5_Delete(
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
} }
static HRESULT STDMETHODCALLTYPE STDMETHODIMP RecycleBin5::Restore(
RecycleBin5_RecycleBin5_Restore( _In_ LPCWSTR pDeletedFileName,
IN IRecycleBin5 *This, _In_ DELETED_FILE_RECORD *pDeletedFile)
IN LPCWSTR pDeletedFileName,
IN DELETED_FILE_RECORD *pDeletedFile)
{ {
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl);
ULARGE_INTEGER FileSize; ULARGE_INTEGER FileSize;
PINFO2_HEADER pHeader; PINFO2_HEADER pHeader;
DELETED_FILE_RECORD *pRecord, *pLast; DELETED_FILE_RECORD *pRecord, *pLast;
@ -476,16 +468,16 @@ RecycleBin5_RecycleBin5_Restore(
SHFILEOPSTRUCTW op; SHFILEOPSTRUCTW op;
int res; int res;
TRACE("(%p, %s, %p)\n", This, debugstr_w(pDeletedFileName), pDeletedFile); TRACE("(%p, %s, %p)\n", this, debugstr_w(pDeletedFileName), pDeletedFile);
if (s->EnumeratorCount != 0) if (m_EnumeratorCount != 0)
return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION); return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); pHeader = (PINFO2_HEADER)MapViewOfFile(m_hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
if (!pHeader) if (!pHeader)
return HRESULT_FROM_WIN32(GetLastError()); return HRESULT_FROM_WIN32(GetLastError());
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart); FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart);
if (FileSize.u.LowPart == 0) if (FileSize.u.LowPart == 0)
{ {
UnmapViewOfFile(pHeader); UnmapViewOfFile(pHeader);
@ -519,11 +511,11 @@ RecycleBin5_RecycleBin5_Restore(
UnmapViewOfFile(pHeader); UnmapViewOfFile(pHeader);
/* Resize file */ /* Resize file */
CloseHandle(s->hInfoMapped); CloseHandle(m_hInfoMapped);
SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END); SetFilePointer(m_hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END);
SetEndOfFile(s->hInfo); SetEndOfFile(m_hInfo);
s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
if (!s->hInfoMapped) if (!m_hInfoMapped)
return HRESULT_FROM_WIN32(GetLastError()); return HRESULT_FROM_WIN32(GetLastError());
return S_OK; return S_OK;
} }
@ -534,34 +526,17 @@ RecycleBin5_RecycleBin5_Restore(
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
} }
static HRESULT STDMETHODCALLTYPE STDMETHODIMP RecycleBin5::OnClosing(_In_ IRecycleBinEnumList *prbel)
RecycleBin5_RecycleBin5_OnClosing(
IN IRecycleBin5 *This,
IN IRecycleBinEnumList *prbel)
{ {
struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); TRACE("(%p, %p)\n", this, prbel);
TRACE("(%p, %p)\n", This, prbel); m_EnumeratorCount--;
s->EnumeratorCount--;
return S_OK; 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 static HRESULT
RecycleBin5_Create( RecycleBin5_Create(
IN LPCWSTR Folder, _In_ LPCWSTR Folder,
IN PSID OwnerSid OPTIONAL) _In_ PSID OwnerSid OPTIONAL)
{ {
LPWSTR BufferName = NULL; LPWSTR BufferName = NULL;
LPWSTR Separator; /* Pointer into BufferName buffer */ LPWSTR Separator; /* Pointer into BufferName buffer */
@ -573,7 +548,7 @@ RecycleBin5_Create(
HRESULT hr; HRESULT hr;
Needed = (wcslen(Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR); Needed = (wcslen(Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR);
BufferName = HeapAlloc(GetProcessHeap(), 0, Needed); BufferName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, Needed);
if (!BufferName) if (!BufferName)
{ {
hr = ERROR_NOT_ENOUGH_MEMORY; hr = ERROR_NOT_ENOUGH_MEMORY;
@ -672,37 +647,38 @@ cleanup:
return hr; return hr;
} }
HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown) RecycleBin5::RecycleBin5()
: m_ref(1)
, m_hInfo(NULL)
, m_hInfoMapped(NULL)
, m_EnumeratorCount(0)
{
}
HRESULT RecycleBin5::Init(_In_ LPCWSTR VolumePath)
{ {
struct RecycleBin5 *s = NULL;
DWORD FileSystemFlags; DWORD FileSystemFlags;
LPCWSTR RecycleBinDirectory; LPCWSTR RecycleBinDirectory;
HANDLE tokenHandle = INVALID_HANDLE_VALUE; HANDLE tokenHandle = INVALID_HANDLE_VALUE;
PTOKEN_USER TokenUserInfo = NULL; PTOKEN_USER TokenUserInfo = NULL;
LPWSTR StringSid = NULL, p; LPWSTR StringSid = NULL;
DWORD Needed, DirectoryLength; DWORD Needed;
INT len; INT len;
HRESULT hr; HRESULT hr;
if (!ppUnknown) m_VolumePath = VolumePath;
return E_POINTER;
/* Get information about file system */ /* Get information about file system */
if (!GetVolumeInformationW( if (!GetVolumeInformationW(VolumePath, NULL, 0, NULL, NULL, &FileSystemFlags, NULL, 0))
VolumePath,
NULL,
0,
NULL,
NULL,
&FileSystemFlags,
NULL,
0))
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup; goto cleanup;
} }
if (!(FileSystemFlags & FILE_PERSISTENT_ACLS)) if (!(FileSystemFlags & FILE_PERSISTENT_ACLS))
{
RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL; RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL;
}
else else
{ {
RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL; RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL;
@ -723,7 +699,7 @@ HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown)
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup; goto cleanup;
} }
TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed); TokenUserInfo = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, Needed);
if (!TokenUserInfo) if (!TokenUserInfo)
{ {
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
@ -741,55 +717,42 @@ HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown)
} }
} }
DirectoryLength = wcslen(VolumePath) + wcslen(RecycleBinDirectory) + 1; m_Folder = VolumePath;
m_Folder += RecycleBinDirectory;
if (StringSid) 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; m_Folder += L'\\';
goto cleanup; m_Folder += StringSid;
} }
ZeroMemory(s, sizeof(struct RecycleBin5)); len = m_Folder.GetLength();
s->recycleBinImpl.lpVtbl = &RecycleBin5Vtbl; m_Folder += L"\\" RECYCLE_BIN_FILE_NAME;
s->ref = 1;
if (StringSid) m_hInfo = CreateFileW(m_Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
len = swprintf(s->Folder, L"%s%s\\%s", VolumePath, RecycleBinDirectory, StringSid); if (m_hInfo == INVALID_HANDLE_VALUE &&
else (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND))
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; m_Folder = m_Folder.Left(len);
hr = RecycleBin5_Create(s->Folder, TokenUserInfo ? TokenUserInfo->User.Sid : NULL); hr = RecycleBin5_Create(m_Folder, TokenUserInfo ? TokenUserInfo->User.Sid : NULL);
*p = L'\\'; m_Folder += L"\\" RECYCLE_BIN_FILE_NAME;
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
goto cleanup; goto cleanup;
s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); m_hInfo = CreateFileW(m_Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
} }
if (s->hInfo == INVALID_HANDLE_VALUE)
if (m_hInfo == INVALID_HANDLE_VALUE)
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup; goto cleanup;
} }
s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
if (!s->hInfoMapped) m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL);
if (!m_hInfoMapped)
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup; goto cleanup;
} }
*p = UNICODE_NULL;
s->VolumePath = p + 1;
wcscpy(s->VolumePath, VolumePath);
*ppUnknown = (IUnknown *)&s->recycleBinImpl;
m_Folder = m_Folder.Left(len);
hr = S_OK; hr = S_OK;
cleanup: cleanup:
@ -798,10 +761,28 @@ cleanup:
HeapFree(GetProcessHeap(), 0, TokenUserInfo); HeapFree(GetProcessHeap(), 0, TokenUserInfo);
if (StringSid) if (StringSid)
LocalFree(StringSid); LocalFree(StringSid);
if (!SUCCEEDED(hr))
{
if (s)
RecycleBin5_Destructor(s);
}
return hr; return hr;
} }
EXTERN_C
HRESULT RecycleBin5_Constructor(_In_ LPCWSTR VolumePath, _Out_ IUnknown **ppUnknown)
{
if (!ppUnknown)
return E_POINTER;
*ppUnknown = NULL;
RecycleBin5 *pThis = new RecycleBin5();
if (!pThis)
return E_OUTOFMEMORY;
HRESULT hr = pThis->Init(VolumePath);
if (FAILED(hr))
{
delete pThis;
return hr;
}
*ppUnknown = static_cast<IRecycleBin5 *>(pThis);
return S_OK;
}