Something went wrong. Try again.
Reactos
Something went wrong. Try again.
13 kB · 485 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486/* * PROJECT: Recycle bin management * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Enumerates contents of a MS Windows 2000/XP/2003 recyclebin * COPYRIGHT: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org) * Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */
#include "recyclebin_private.h"#include <atlstr.h>#include <shlwapi.h>#include <strsafe.h>
class RecycleBin5File : public IRecycleBinFile{public: RecycleBin5File(); virtual ~RecycleBin5File();
HRESULT Init( _In_ IRecycleBin5 *prb, _In_ LPCWSTR Folder, _In_ PDELETED_FILE_RECORD pDeletedFile);
/* IUnknown methods */ STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override; STDMETHODIMP_(ULONG) AddRef() override; STDMETHODIMP_(ULONG) Release() override;
/* IRecycleBinFile methods */ STDMETHODIMP IsEqualIdentity(const RECYCLEBINFILEIDENTITY *pFI) override { RECYCLEBINFILEIDENTITY self = { m_deletedFile.DeletionTime, m_FullName }; return RecycleBinGeneric_IsEqualFileIdentity(pFI, &self) ? S_OK : S_FALSE; } STDMETHODIMP GetInfo(PDELETED_FILE_INFO pInfo) override; STDMETHODIMP GetLastModificationTime(FILETIME *pLastModificationTime) override; STDMETHODIMP GetDeletionTime(FILETIME *pDeletionTime) override; STDMETHODIMP GetFileSize(ULARGE_INTEGER *pFileSize) override; STDMETHODIMP GetPhysicalFileSize(ULARGE_INTEGER *pPhysicalFileSize) override; STDMETHODIMP GetAttributes(DWORD *pAttributes) override; STDMETHODIMP GetFileName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) override; STDMETHODIMP Delete() override; STDMETHODIMP Restore() override; STDMETHODIMP RemoveFromDatabase() override;
protected: LONG m_ref; IRecycleBin5 *m_recycleBin; DELETED_FILE_RECORD m_deletedFile; LPWSTR m_FullName;};
STDMETHODIMP RecycleBin5File::QueryInterface(REFIID riid, void **ppvObject){ TRACE("(%p, %s, %p)\n", this, debugstr_guid(&riid), ppvObject);
if (!ppvObject) return E_POINTER;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRecycleBinFile)) { *ppvObject = static_cast<IRecycleBinFile *>(this); } else { *ppvObject = NULL; return E_NOINTERFACE; }
AddRef(); return S_OK;}
STDMETHODIMP_(ULONG) RecycleBin5File::AddRef(){ TRACE("(%p)\n", this); return InterlockedIncrement(&m_ref);}
RecycleBin5File::~RecycleBin5File(){ TRACE("(%p)\n", this); m_recycleBin->Release(); SHFree(m_FullName);}
STDMETHODIMP_(ULONG) RecycleBin5File::Release(){ TRACE("(%p)\n", this); ULONG refCount = InterlockedDecrement(&m_ref); if (refCount == 0) delete this; return refCount;}
STDMETHODIMP RecycleBin5File::GetInfo(PDELETED_FILE_INFO pInfo){ HRESULT hr = S_OK; ULARGE_INTEGER uli; if (FAILED(GetLastModificationTime(&pInfo->LastModification))) ZeroMemory(&pInfo->LastModification, sizeof(pInfo->LastModification)); pInfo->DeletionTime = m_deletedFile.DeletionTime; C_ASSERT(sizeof(pInfo->FileSize) <= sizeof(UINT)); pInfo->FileSize = FAILED(GetFileSize(&uli)) ? INVALID_FILE_SIZE : uli.LowPart; if (FAILED(hr = GetAttributes(&pInfo->Attributes))) pInfo->Attributes = 0; InitializeRecycleBinStringRef(&pInfo->OriginalFullPath, m_deletedFile.FileNameW); InitializeRecycleBinStringRef(&pInfo->RecycledFullPath, m_FullName); return hr;}
STDMETHODIMP RecycleBin5File::GetLastModificationTime(FILETIME *pLastModificationTime){ TRACE("(%p, %p)\n", this, pLastModificationTime);
DWORD dwAttributes = ::GetFileAttributesW(m_FullName); if (dwAttributes == INVALID_FILE_ATTRIBUTES) return HResultFromWin32(GetLastError());
HANDLE hFile; hFile = CreateFileW(m_FullName, GENERIC_READ, FILE_SHARE_READ | ((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (FILE_SHARE_WRITE | FILE_SHARE_DELETE) : 0), NULL, OPEN_EXISTING, (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS : 0, NULL); if (hFile == INVALID_HANDLE_VALUE) return HResultFromWin32(GetLastError());
HRESULT hr; if (GetFileTime(hFile, NULL, NULL, pLastModificationTime)) hr = S_OK; else hr = HResultFromWin32(GetLastError()); CloseHandle(hFile); return hr;}
STDMETHODIMP RecycleBin5File::GetDeletionTime(FILETIME *pDeletionTime){ TRACE("(%p, %p)\n", this, pDeletionTime); *pDeletionTime = m_deletedFile.DeletionTime; return S_OK;}
STDMETHODIMP RecycleBin5File::GetFileSize(ULARGE_INTEGER *pFileSize){ TRACE("(%p, %p)\n", this, pFileSize);
DWORD dwAttributes = GetFileAttributesW(m_FullName); if (dwAttributes == INVALID_FILE_ATTRIBUTES) return HRESULT_FROM_WIN32(GetLastError()); if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) { pFileSize->QuadPart = 0; return S_OK; }
HANDLE hFile = CreateFileW(m_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);
HRESULT hr; if (pFileSize->u.LowPart != INVALID_FILE_SIZE) hr = S_OK; else hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hFile); return hr;}
STDMETHODIMP RecycleBin5File::GetPhysicalFileSize(ULARGE_INTEGER *pPhysicalFileSize){ TRACE("(%p, %p)\n", this, pPhysicalFileSize); pPhysicalFileSize->u.HighPart = 0; pPhysicalFileSize->u.LowPart = m_deletedFile.dwPhysicalFileSize; return S_OK;}
STDMETHODIMP RecycleBin5File::GetAttributes(DWORD *pAttributes){ DWORD dwAttributes;
TRACE("(%p, %p)\n", this, pAttributes);
dwAttributes = GetFileAttributesW(m_FullName); if (dwAttributes == INVALID_FILE_ATTRIBUTES) return HResultFromWin32(GetLastError());
*pAttributes = dwAttributes; return S_OK;}
STDMETHODIMP RecycleBin5File::GetFileName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize){ DWORD dwRequired;
TRACE("(%p, %u, %p, %p)\n", this, BufferSize, Buffer, RequiredSize);
dwRequired = (DWORD)(wcslen(m_deletedFile.FileNameW) + 1) * sizeof(WCHAR); if (RequiredSize) *RequiredSize = dwRequired;
if (BufferSize == 0 && !Buffer) return S_OK;
if (BufferSize < dwRequired) return E_OUTOFMEMORY; CopyMemory(Buffer, m_deletedFile.FileNameW, dwRequired); return S_OK;}
STDMETHODIMP RecycleBin5File::Delete(){ TRACE("(%p)\n", this); return m_recycleBin->Delete(m_FullName, &m_deletedFile);}
STDMETHODIMP RecycleBin5File::Restore(){ TRACE("(%p)\n", this); return m_recycleBin->Restore(m_FullName, &m_deletedFile);}
STDMETHODIMP RecycleBin5File::RemoveFromDatabase(){ TRACE("(%p)\n", this); return m_recycleBin->RemoveFromDatabase(m_FullName, &m_deletedFile);}
RecycleBin5File::RecycleBin5File() : m_ref(1) , m_recycleBin(NULL) , m_FullName(NULL){ ZeroMemory(&m_deletedFile, sizeof(m_deletedFile));}
HRESULTRecycleBin5File::Init( _In_ IRecycleBin5 *prb, _In_ LPCWSTR Folder, _In_ PDELETED_FILE_RECORD pDeletedFile){ m_recycleBin = prb; m_recycleBin->AddRef(); m_deletedFile = *pDeletedFile;
WCHAR szUniqueId[32]; StringCchPrintfW(szUniqueId, _countof(szUniqueId), L"%lu", pDeletedFile->dwRecordUniqueId);
CStringW strFullName(Folder); strFullName += L"\\D"; strFullName += (WCHAR)(L'a' + pDeletedFile->dwDriveNumber); strFullName += szUniqueId; strFullName += PathFindExtensionW(pDeletedFile->FileNameW); if (GetFileAttributesW(strFullName) == INVALID_FILE_ATTRIBUTES) return E_FAIL;
return SHStrDup(strFullName, &m_FullName);}
static HRESULTRecycleBin5File_Constructor( _In_ IRecycleBin5 *prb, _In_ LPCWSTR Folder, _In_ PDELETED_FILE_RECORD pDeletedFile, _Out_ IRecycleBinFile **ppFile){ if (!ppFile) return E_POINTER;
*ppFile = NULL;
RecycleBin5File *pThis = new RecycleBin5File(); if (!pThis) return E_OUTOFMEMORY;
HRESULT hr = pThis->Init(prb, Folder, pDeletedFile); if (FAILED(hr)) { delete pThis; return hr; }
*ppFile = static_cast<IRecycleBinFile *>(pThis); return S_OK;}
class RecycleBin5Enum : public IRecycleBinEnumList{public: RecycleBin5Enum(); virtual ~RecycleBin5Enum();
HRESULT Init( _In_ IRecycleBin5 *prb, _In_ HANDLE hInfo, _In_ HANDLE hInfoMapped, _In_ LPCWSTR pszPrefix);
/* IUnknown methods */ STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override; STDMETHODIMP_(ULONG) AddRef() override; STDMETHODIMP_(ULONG) Release() override;
/* IRecycleBinEnumList methods */ STDMETHODIMP Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched) override; STDMETHODIMP Skip(DWORD celt) override; STDMETHODIMP Reset() override;
protected: LONG m_ref; IRecycleBin5 *m_recycleBin; HANDLE m_hInfo; INFO2_HEADER *m_pInfo; DWORD m_dwCurrent; LPWSTR m_pszPrefix;};
STDMETHODIMP RecycleBin5Enum::QueryInterface(REFIID riid, void **ppvObject){ TRACE("(%p, %s, %p)\n", this, debugstr_guid(&riid), ppvObject);
if (!ppvObject) return E_POINTER;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRecycleBinEnumList)) *ppvObject = static_cast<IRecycleBinEnumList *>(this); else { *ppvObject = NULL; return E_NOINTERFACE; }
AddRef(); return S_OK;}
STDMETHODIMP_(ULONG) RecycleBin5Enum::AddRef(){ TRACE("(%p)\n", this); return InterlockedIncrement(&m_ref);}
RecycleBin5Enum::~RecycleBin5Enum(){ TRACE("(%p)\n", this);
m_recycleBin->OnClosing(this); UnmapViewOfFile(m_pInfo); m_recycleBin->Release(); SHFree(m_pszPrefix);}
STDMETHODIMP_(ULONG) RecycleBin5Enum::Release(){ TRACE("(%p)\n", this);
ULONG refCount = InterlockedDecrement(&m_ref); if (refCount == 0) delete this; return refCount;}
STDMETHODIMP RecycleBin5Enum::Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched){ HRESULT hr;
TRACE("(%p, %u, %p, %p)\n", this, celt, rgelt, pceltFetched);
if (!rgelt) return E_POINTER; if (!pceltFetched && celt > 1) return E_INVALIDARG;
ULARGE_INTEGER FileSize; FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart); if (FileSize.u.LowPart == 0) return HResultFromWin32(GetLastError());
DWORD dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
DWORD iEntry = m_dwCurrent, fetched = 0; PDELETED_FILE_RECORD pDeletedFile = (PDELETED_FILE_RECORD)(m_pInfo + 1) + iEntry; for (; iEntry < dwEntries && fetched < celt; ++iEntry) { hr = RecycleBin5File_Constructor(m_recycleBin, m_pszPrefix, pDeletedFile, &rgelt[fetched]); if (SUCCEEDED(hr)) fetched++; pDeletedFile++; }
m_dwCurrent = iEntry; if (pceltFetched) *pceltFetched = fetched; if (fetched == celt) return S_OK; else return S_FALSE;}
STDMETHODIMP RecycleBin5Enum::Skip(DWORD celt){ TRACE("(%p, %u)\n", this, celt); m_dwCurrent += celt; return S_OK;}
STDMETHODIMP RecycleBin5Enum::Reset(){ TRACE("(%p)\n", this); m_dwCurrent = 0; return S_OK;}
RecycleBin5Enum::RecycleBin5Enum() : m_ref(1) , m_recycleBin(NULL) , m_hInfo(NULL) , m_pInfo(NULL) , m_dwCurrent(0) , m_pszPrefix(NULL){}
HRESULTRecycleBin5Enum::Init( _In_ IRecycleBin5 *prb, _In_ HANDLE hInfo, _In_ HANDLE hInfoMapped, _In_ LPCWSTR pszPrefix){ m_recycleBin = prb; m_recycleBin->AddRef();
HRESULT hr = SHStrDup(pszPrefix, &m_pszPrefix); if (FAILED(hr)) return hr;
m_hInfo = hInfo; m_pInfo = (PINFO2_HEADER)MapViewOfFile(hInfoMapped, FILE_MAP_READ, 0, 0, 0); if (!m_pInfo) return HResultFromWin32(GetLastError());
if (m_pInfo->dwVersion != 5 || m_pInfo->dwRecordSize != sizeof(DELETED_FILE_RECORD)) return E_FAIL;
return S_OK;}
EXTERN_CHRESULTRecycleBin5Enum_Constructor( _In_ IRecycleBin5 *prb, _In_ HANDLE hInfo, _In_ HANDLE hInfoMapped, _In_ LPCWSTR szPrefix, _Out_ IUnknown **ppUnknown){ if (!ppUnknown) return E_POINTER;
*ppUnknown = NULL;
RecycleBin5Enum *pThis = new RecycleBin5Enum(); if (!pThis) return E_OUTOFMEMORY;
HRESULT hr = pThis->Init(prb, hInfo, hInfoMapped, szPrefix); if (FAILED(hr)) { delete pThis; return hr; }
*ppUnknown = static_cast<IRecycleBinEnumList *>(pThis); return S_OK;}