1 /* 2 * PROJECT: Recycle bin management 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Deals with a system-wide recycle bin 5 * COPYRIGHT: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org) 6 * Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 7 */ 8 9 #include "recyclebin_private.h" 10 11 class RecycleBinGeneric : public IRecycleBin 12 { 13 public: 14 RecycleBinGeneric(); 15 virtual ~RecycleBinGeneric(); 16 17 /* IUnknown methods */ 18 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override; 19 STDMETHODIMP_(ULONG) AddRef() override; 20 STDMETHODIMP_(ULONG) Release() override; 21 22 /* IRecycleBin methods */ 23 STDMETHODIMP DeleteFile(LPCWSTR szFileName) override; 24 STDMETHODIMP EmptyRecycleBin() override; 25 STDMETHODIMP EnumObjects(IRecycleBinEnumList **ppEnumList) override; 26 27 protected: 28 LONG m_ref; 29 }; 30 31 STDMETHODIMP RecycleBinGeneric::QueryInterface(REFIID riid, void **ppvObject) 32 { 33 TRACE("(%p, %s, %p)\n", this, debugstr_guid(&riid), ppvObject); 34 35 if (!ppvObject) 36 return E_POINTER; 37 38 if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRecycleBin)) 39 *ppvObject = static_cast<IRecycleBin *>(this); 40 else 41 { 42 *ppvObject = NULL; 43 return E_NOINTERFACE; 44 } 45 46 AddRef(); 47 return S_OK; 48 } 49 50 STDMETHODIMP_(ULONG) RecycleBinGeneric::AddRef() 51 { 52 ULONG refCount = InterlockedIncrement(&m_ref); 53 TRACE("(%p)\n", this); 54 return refCount; 55 } 56 57 RecycleBinGeneric::~RecycleBinGeneric() 58 { 59 TRACE("(%p)\n", this); 60 } 61 62 STDMETHODIMP_(ULONG) RecycleBinGeneric::Release() 63 { 64 TRACE("(%p)\n", this); 65 66 ULONG refCount = InterlockedDecrement(&m_ref); 67 if (refCount == 0) 68 delete this; 69 return refCount; 70 } 71 72 STDMETHODIMP RecycleBinGeneric::DeleteFile(LPCWSTR szFileName) 73 { 74 TRACE("(%p, %s)\n", this, debugstr_w(szFileName)); 75 76 /* Get full file name */ 77 LPWSTR szFullName = NULL; 78 DWORD dwBufferLength = 0; 79 while (TRUE) 80 { 81 DWORD len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, NULL); 82 if (len == 0) 83 { 84 if (szFullName) 85 CoTaskMemFree(szFullName); 86 return HRESULT_FROM_WIN32(GetLastError()); 87 } 88 else if (len < dwBufferLength) 89 break; 90 if (szFullName) 91 CoTaskMemFree(szFullName); 92 dwBufferLength = len; 93 szFullName = (LPWSTR)CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR)); 94 if (!szFullName) 95 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); 96 } 97 98 /* Get associated volume path */ 99 WCHAR szVolume[MAX_PATH]; 100 #ifndef __REACTOS__ 101 if (!GetVolumePathNameW(szFullName, szVolume, _countof(szVolume))) 102 { 103 CoTaskMemFree(szFullName); 104 return HRESULT_FROM_WIN32(GetLastError()); 105 } 106 #else 107 swprintf(szVolume, L"%c:\\", szFullName[0]); 108 #endif 109 110 /* Skip namespace (if any): "\\.\" or "\\?\" */ 111 if (szVolume[0] == '\\' && 112 szVolume[1] == '\\' && 113 (szVolume[2] == '.' || szVolume[2] == '?') && 114 szVolume[3] == '\\') 115 { 116 MoveMemory(szVolume, &szVolume[4], (_countof(szVolume) - 4) * sizeof(WCHAR)); 117 } 118 119 IRecycleBin *prb; 120 HRESULT hr = GetDefaultRecycleBin(szVolume, &prb); 121 if (!SUCCEEDED(hr)) 122 { 123 CoTaskMemFree(szFullName); 124 return hr; 125 } 126 127 hr = prb->DeleteFile(szFullName); 128 CoTaskMemFree(szFullName); 129 prb->Release(); 130 return hr; 131 } 132 133 STDMETHODIMP RecycleBinGeneric::EmptyRecycleBin() 134 { 135 TRACE("(%p)\n", this); 136 137 DWORD dwLogicalDrives = GetLogicalDrives(); 138 if (dwLogicalDrives == 0) 139 return HRESULT_FROM_WIN32(GetLastError()); 140 141 for (DWORD i = 0; i < 'Z' - 'A' + 1; i++) 142 { 143 if (!(dwLogicalDrives & (1 << i))) 144 continue; 145 146 WCHAR szVolumeName[MAX_PATH]; 147 swprintf(szVolumeName, L"%c:\\", L'A' + i); 148 if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED) 149 continue; 150 151 IRecycleBin *prb; 152 HRESULT hr = GetDefaultRecycleBin(szVolumeName, &prb); 153 if (!SUCCEEDED(hr)) 154 return hr; 155 156 hr = prb->EmptyRecycleBin(); 157 prb->Release(); 158 } 159 160 return S_OK; 161 } 162 163 STDMETHODIMP RecycleBinGeneric::EnumObjects(IRecycleBinEnumList **ppEnumList) 164 { 165 TRACE("(%p, %p)\n", this, ppEnumList); 166 return RecycleBinGenericEnum_Constructor(ppEnumList); 167 } 168 169 RecycleBinGeneric::RecycleBinGeneric() 170 : m_ref(1) 171 { 172 } 173 174 EXTERN_C 175 HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown) 176 { 177 /* This RecycleBin implementation was introduced to be able to manage all 178 * drives at once, and instanciate the 'real' implementations when needed */ 179 RecycleBinGeneric *pThis = new RecycleBinGeneric(); 180 if (!pThis) 181 return E_OUTOFMEMORY; 182 183 *ppUnknown = static_cast<IRecycleBin *>(pThis); 184 return S_OK; 185 } 186