mirror of
https://github.com/reactos/reactos.git
synced 2025-05-06 18:31:26 +00:00
[SHELL32] RecycleBin5: Make it C++ (#7174)
Modernize code. JIRA issue: CORE-19595 Rewrite RecycleBin5 in C++.
This commit is contained in:
parent
22b913928f
commit
90a5b9a83f
3 changed files with 193 additions and 210 deletions
|
@ -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)
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in a new issue