1 /* 2 * PROJECT: Recycle bin management 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Enumerates contents of all recycle bins 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 RecycleBinGenericEnum : public IRecycleBinEnumList 12 { 13 public: 14 RecycleBinGenericEnum(); 15 virtual ~RecycleBinGenericEnum(); 16 17 /* IUnknown methods */ 18 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override; 19 STDMETHODIMP_(ULONG) AddRef() override; 20 STDMETHODIMP_(ULONG) Release() override; 21 22 /* IRecycleBinEnumList methods */ 23 STDMETHODIMP Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched) override; 24 STDMETHODIMP Skip(DWORD celt) override; 25 STDMETHODIMP Reset() override; 26 27 protected: 28 LONG m_ref; 29 IRecycleBinEnumList *m_current; 30 DWORD m_dwLogicalDrives; 31 SIZE_T m_skip; 32 }; 33 34 STDMETHODIMP 35 RecycleBinGenericEnum::QueryInterface(REFIID riid, void **ppvObject) 36 { 37 TRACE("(%p, %s, %p)\n", this, debugstr_guid(&riid), ppvObject); 38 39 if (!ppvObject) 40 return E_POINTER; 41 42 if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRecycleBinEnumList)) 43 *ppvObject = static_cast<IRecycleBinEnumList *>(this); 44 else 45 { 46 *ppvObject = NULL; 47 return E_NOINTERFACE; 48 } 49 50 AddRef(); 51 return S_OK; 52 } 53 54 STDMETHODIMP_(ULONG) 55 RecycleBinGenericEnum::AddRef() 56 { 57 ULONG refCount = InterlockedIncrement(&m_ref); 58 TRACE("(%p)\n", this); 59 return refCount; 60 } 61 62 RecycleBinGenericEnum::~RecycleBinGenericEnum() 63 { 64 TRACE("(%p)\n", this); 65 66 if (m_current) 67 m_current->Release(); 68 } 69 70 STDMETHODIMP_(ULONG) 71 RecycleBinGenericEnum::Release() 72 { 73 TRACE("(%p)\n", this); 74 75 ULONG refCount = InterlockedDecrement(&m_ref); 76 if (refCount == 0) 77 delete this; 78 return refCount; 79 } 80 81 STDMETHODIMP 82 RecycleBinGenericEnum::Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched) 83 { 84 TRACE("(%p, %u, %p, %p)\n", this, celt, rgelt, pceltFetched); 85 86 if (!rgelt) 87 return E_POINTER; 88 if (!pceltFetched && celt > 1) 89 return E_INVALIDARG; 90 91 HRESULT hr; 92 DWORD fetched = 0; 93 while (TRUE) 94 { 95 /* Get enumerator implementation */ 96 if (!m_current && m_dwLogicalDrives) 97 { 98 for (DWORD i = 0; i < L'Z' - L'A' + 1; ++i) 99 { 100 if (m_dwLogicalDrives & (1 << i)) 101 { 102 WCHAR szVolumeName[4]; 103 szVolumeName[0] = (WCHAR)(L'A' + i); 104 szVolumeName[1] = L':'; 105 szVolumeName[2] = L'\\'; 106 szVolumeName[3] = UNICODE_NULL; 107 if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED) 108 { 109 m_dwLogicalDrives &= ~(1 << i); 110 continue; 111 } 112 113 IRecycleBin *prb; 114 hr = GetDefaultRecycleBin(szVolumeName, &prb); 115 if (!SUCCEEDED(hr)) 116 return hr; 117 hr = prb->EnumObjects(&m_current); 118 prb->Release(); 119 120 if (!SUCCEEDED(hr)) 121 return hr; 122 123 m_dwLogicalDrives &= ~(1 << i); 124 break; 125 } 126 } 127 } 128 129 if (!m_current) 130 { 131 /* Nothing more to enumerate */ 132 if (pceltFetched) 133 *pceltFetched = fetched; 134 return S_FALSE; 135 } 136 137 /* Skip some elements */ 138 while (m_skip > 0) 139 { 140 IRecycleBinFile *rbf; 141 hr = m_current->Next(1, &rbf, NULL); 142 if (hr == S_OK) 143 rbf->Release(); 144 else if (hr == S_FALSE) 145 break; 146 else if (!SUCCEEDED(hr)) 147 return hr; 148 } 149 150 if (m_skip > 0) 151 continue; 152 153 /* Fill area */ 154 DWORD newFetched; 155 hr = m_current->Next(celt - fetched, &rgelt[fetched], &newFetched); 156 if (SUCCEEDED(hr)) 157 fetched += newFetched; 158 159 if (hr == S_FALSE || newFetched == 0) 160 { 161 m_current->Release(); 162 m_current = NULL; 163 } 164 else if (!SUCCEEDED(hr)) 165 return hr; 166 167 if (fetched == celt) 168 { 169 if (pceltFetched) 170 *pceltFetched = fetched; 171 return S_OK; 172 } 173 } 174 175 /* Never go here */ 176 UNREACHABLE; 177 } 178 179 STDMETHODIMP RecycleBinGenericEnum::Skip(DWORD celt) 180 { 181 TRACE("(%p, %u)\n", this, celt); 182 m_skip += celt; 183 return S_OK; 184 } 185 186 STDMETHODIMP RecycleBinGenericEnum::Reset() 187 { 188 TRACE("(%p)\n", this); 189 190 if (m_current) 191 { 192 m_current->Release(); 193 m_current = NULL; 194 } 195 m_skip = 0; 196 m_dwLogicalDrives = ::GetLogicalDrives(); 197 return S_OK; 198 } 199 200 RecycleBinGenericEnum::RecycleBinGenericEnum() 201 : m_ref(1) 202 , m_current(NULL) 203 , m_dwLogicalDrives(0) 204 , m_skip(0) 205 { 206 } 207 208 EXTERN_C 209 HRESULT 210 RecycleBinGenericEnum_Constructor( 211 OUT IRecycleBinEnumList **pprbel) 212 { 213 RecycleBinGenericEnum *pThis = new RecycleBinGenericEnum(); 214 if (!pThis) 215 return E_OUTOFMEMORY; 216 217 *pprbel = static_cast<IRecycleBinEnumList *>(pThis); 218 return (*pprbel)->Reset(); 219 } 220