Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806/* * PROJECT: Recycle bin management * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Deals with recycle bins of Windows 2000/XP/2003 * 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 "sddl.h"
EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void);
class CZZWStr{ LPWSTR m_sz;
public: ~CZZWStr() { SHFree(m_sz); } CZZWStr() : m_sz(NULL) {} CZZWStr(const CZZWStr&) = delete; CZZWStr& operator=(const CZZWStr&) = delete;
bool Initialize(LPCWSTR Str) { SIZE_T cch = wcslen(Str) + 1; m_sz = (LPWSTR)SHAlloc((cch + 1) * sizeof(*Str)); if (!m_sz) return false; CopyMemory(m_sz, Str, cch * sizeof(*Str)); m_sz[cch] = UNICODE_NULL; // Double-null terminate return true; } inline LPWSTR c_str() { return m_sz; }};
static int SHELL_SingleFileOperation(HWND hWnd, UINT Op, LPCWSTR pszFrom, LPCWSTR pszTo, FILEOP_FLAGS Flags){ CZZWStr szzFrom, szzTo; if (!szzFrom.Initialize(pszFrom) || !szzTo.Initialize(pszTo)) return ERROR_OUTOFMEMORY; // Note: Not one of the DE errors but also not in the DE range SHFILEOPSTRUCTW fos = { hWnd, Op, szzFrom.c_str(), szzTo.c_str(), Flags }; return SHFileOperationW(&fos);}
static BOOLIntDeleteRecursive( 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 = (LPWSTR)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;}
class RecycleBin5 : public IRecycleBin5{public: RecycleBin5(); virtual ~RecycleBin5();
HRESULT Init(_In_ LPCWSTR VolumePath);
/* IUnknown interface */ 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; STDMETHODIMP GetDirectory(LPWSTR szPath) override { if (!m_Folder[0]) return E_UNEXPECTED; lstrcpynW(szPath, m_Folder, MAX_PATH); return S_OK; }
/* 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 RemoveFromDatabase( _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} */};
STDMETHODIMP RecycleBin5::QueryInterface(_In_ REFIID riid, _Out_ 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_IRecycleBin)) *ppvObject = static_cast<IRecycleBin5 *>(this); else if (IsEqualIID(riid, IID_IRecycleBin5)) *ppvObject = static_cast<IRecycleBin5 *>(this); else { *ppvObject = NULL; return E_NOINTERFACE; }
AddRef(); return S_OK;}
STDMETHODIMP_(ULONG) RecycleBin5::AddRef(){ TRACE("(%p)\n", this); return InterlockedIncrement(&m_ref);}
RecycleBin5::~RecycleBin5(){ TRACE("(%p)\n", this);
if (m_hInfo && m_hInfo != INVALID_HANDLE_VALUE) CloseHandle(m_hInfo); if (m_hInfoMapped) CloseHandle(m_hInfoMapped);}
STDMETHODIMP_(ULONG) RecycleBin5::Release(){ TRACE("(%p)\n", this);
ULONG refCount = InterlockedDecrement(&m_ref); if (refCount == 0) delete this; return refCount;}
STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName){ LPWSTR szFullName = NULL; DWORD dwBufferLength = 0; LPWSTR lpFilePart; LPCWSTR Extension; CStringW DeletedFileName; WCHAR szUniqueId[64]; 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; WIN32_FIND_DATAW wfd = {};
TRACE("(%p, %s)\n", this, debugstr_w(szFileName));
if (m_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 HResultFromWin32(GetLastError()); } else if (len < dwBufferLength) break; if (szFullName) CoTaskMemFree(szFullName); dwBufferLength = len; szFullName = (LPWSTR)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) { CoTaskMemFree(szFullName); return HResultFromWin32(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, (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS : 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { hr = HResultFromWin32(GetLastError()); goto cleanup; }
/* Increase INFO2 file size */ CloseHandle(m_hInfoMapped); SetFilePointer(m_hInfo, sizeof(DELETED_FILE_RECORD), NULL, FILE_END); SetEndOfFile(m_hInfo); m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); if (!m_hInfoMapped) { hr = HResultFromWin32(GetLastError()); goto cleanup; }
/* Open INFO2 file */ pHeader = (PINFO2_HEADER)MapViewOfFile(m_hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); if (!pHeader) { hr = HResultFromWin32(GetLastError()); goto cleanup; }
/* Get number of entries */ FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart); if (FileSize.u.LowPart < sizeof(INFO2_HEADER)) { hr = HResultFromWin32(GetLastError()); goto cleanup; } 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 = HResultFromWin32(GetLastError()); goto cleanup; }#else FileSize.u.LowPart = GetFileSize(hFile, &FileSize.u.HighPart); if (FileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { hr = HResultFromWin32(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 = PathFindExtensionW(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'; _ultow(pDeletedFile->dwRecordUniqueId, szUniqueId, 10);
DeletedFileName = m_Folder; DeletedFileName += L"\\D"; DeletedFileName += (WCHAR)(L'a' + pDeletedFile->dwDriveNumber); DeletedFileName += szUniqueId; DeletedFileName += Extension;
/* Get cluster size */ if (!GetDiskFreeSpaceW(m_VolumePath, &SectorsPerCluster, &BytesPerSector, NULL, NULL)) { hr = HResultFromWin32(GetLastError()); goto cleanup; } ClusterSize = BytesPerSector * SectorsPerCluster;
/* Get current time */ GetSystemTime(&SystemTime); if (!SystemTimeToFileTime(&SystemTime, &pDeletedFile->DeletionTime)) { hr = HResultFromWin32(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; }
wfd.dwFileAttributes = dwAttributes; wfd.nFileSizeLow = FileSize.u.LowPart; GetFileTime(hFile, &wfd.ftCreationTime, &wfd.ftLastAccessTime, &wfd.ftLastWriteTime);
/* Move file */ if (MoveFileW(szFullName, DeletedFileName)) hr = S_OK; else hr = HResultFromWin32(GetLastError());
if (SUCCEEDED(hr)) { RECYCLEBINFILEIDENTITY ident = { pDeletedFile->DeletionTime, DeletedFileName }; CRecycleBin_NotifyRecycled(szFullName, &wfd, &ident); }
cleanup: if (pHeader) UnmapViewOfFile(pHeader); if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); CoTaskMemFree(szFullName); return hr;}
STDMETHODIMP RecycleBin5::EmptyRecycleBin(){ TRACE("(%p)\n", this);
while (TRUE) { IRecycleBinEnumList *prbel; HRESULT hr = EnumObjects(&prbel); if (!SUCCEEDED(hr)) return hr;
IRecycleBinFile *prbf; hr = prbel->Next(1, &prbf, NULL); prbel->Release(); if (hr == S_FALSE) return S_OK; hr = prbf->Delete(); prbf->Release(); if (!SUCCEEDED(hr)) return hr; }}
STDMETHODIMP RecycleBin5::EnumObjects(_Out_ IRecycleBinEnumList **ppEnumList){ TRACE("(%p, %p)\n", this, ppEnumList);
IUnknown *pUnk; HRESULT hr = RecycleBin5Enum_Constructor(this, m_hInfo, m_hInfoMapped, m_Folder, &pUnk); if (!SUCCEEDED(hr)) return hr;
IRecycleBinEnumList *prbel; hr = pUnk->QueryInterface(IID_IRecycleBinEnumList, (void **)&prbel); if (SUCCEEDED(hr)) { m_EnumeratorCount++; *ppEnumList = prbel; }
pUnk->Release(); return hr;}
STDMETHODIMP RecycleBin5::Delete( _In_ LPCWSTR pDeletedFileName, _In_ DELETED_FILE_RECORD *pDeletedFile){
TRACE("(%p, %s, %p)\n", this, debugstr_w(pDeletedFileName), pDeletedFile);
int res = IntDeleteRecursive(pDeletedFileName); if (!res) return HResultFromWin32(GetLastError()); res = RemoveFromDatabase(pDeletedFileName, pDeletedFile); if (res == 0) SHUpdateRecycleBinIcon(); // Full --> Empty return res;}
STDMETHODIMP RecycleBin5::Restore( _In_ LPCWSTR pDeletedFileName, _In_ DELETED_FILE_RECORD *pDeletedFile){
TRACE("(%p, %s, %p)\n", this, debugstr_w(pDeletedFileName), pDeletedFile);
int res = SHELL_SingleFileOperation(NULL, FO_MOVE, pDeletedFileName, pDeletedFile->FileNameW, 0); if (res) { ERR("SHFileOperationW failed with 0x%x\n", res); return E_FAIL; } res = RemoveFromDatabase(pDeletedFileName, pDeletedFile); if (res == 0) SHUpdateRecycleBinIcon(); // Full --> Empty return res;}
STDMETHODIMP RecycleBin5::RemoveFromDatabase( _In_ LPCWSTR pDeletedFileName, _In_ DELETED_FILE_RECORD *pDeletedFile){ 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 (m_EnumeratorCount != 0) return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION);
pHeader = (PINFO2_HEADER)MapViewOfFile(m_hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); if (!pHeader) return HRESULT_FROM_WIN32(GetLastError());
FileSize.u.LowPart = GetFileSize(m_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) { /* 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(m_hInfoMapped); SetFilePointer(m_hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END); SetEndOfFile(m_hInfo); m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); if (!m_hInfoMapped) return HResultFromWin32(GetLastError()); dwEntries--; return FAILED((int)dwEntries) ? INT_MAX : dwEntries; } pRecord++; }
UnmapViewOfFile(pHeader); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);}
STDMETHODIMP RecycleBin5::OnClosing(_In_ IRecycleBinEnumList *prbel){ TRACE("(%p, %p)\n", this, prbel); m_EnumeratorCount--; return S_OK;}
static HRESULTRecycleBin5_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; SIZE_T 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 = (LPWSTR)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 = (UINT)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;}
RecycleBin5::RecycleBin5() : m_ref(1) , m_hInfo(NULL) , m_hInfoMapped(NULL) , m_EnumeratorCount(0){}
HRESULT RecycleBin5::Init(_In_ LPCWSTR VolumePath){ DWORD FileSystemFlags; LPCWSTR RecycleBinDirectory; HANDLE tokenHandle = INVALID_HANDLE_VALUE; PTOKEN_USER TokenUserInfo = NULL; LPWSTR StringSid = NULL; DWORD Needed; INT len; HRESULT hr;
m_VolumePath = VolumePath;
/* 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 = (PTOKEN_USER)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; } }
m_Folder = VolumePath; m_Folder += RecycleBinDirectory; if (StringSid) { m_Folder += L'\\'; m_Folder += StringSid; } len = m_Folder.GetLength(); m_Folder += L"\\" RECYCLE_BIN_FILE_NAME;
m_hInfo = CreateFileW(m_Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (m_hInfo == INVALID_HANDLE_VALUE && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND)) { m_Folder = m_Folder.Left(len); hr = RecycleBin5_Create(m_Folder, TokenUserInfo ? TokenUserInfo->User.Sid : NULL); m_Folder += L"\\" RECYCLE_BIN_FILE_NAME; if (!SUCCEEDED(hr)) goto cleanup; m_hInfo = CreateFileW(m_Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); }
if (m_hInfo == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; }
m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); if (!m_hInfoMapped) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; }
m_Folder = m_Folder.Left(len); hr = S_OK;
cleanup: if (tokenHandle != INVALID_HANDLE_VALUE) CloseHandle(tokenHandle); HeapFree(GetProcessHeap(), 0, TokenUserInfo); if (StringSid) LocalFree(StringSid); return hr;}
EXTERN_CHRESULT 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;}