[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / shellrecyclebin / recyclebin_v5_enumerator.c
1 /*
2 * PROJECT: Recycle bin management
3 * LICENSE: GPL v2 - See COPYING in the top level directory
4 * FILE: lib/recyclebin/recyclebin_v5_enumerator.c
5 * PURPOSE: Enumerates contents of a MS Windows 2000/XP/2003 recyclebin
6 * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 #include "recyclebin_private.h"
10
11 struct RecycleBin5File
12 {
13 ULONG ref;
14 IRecycleBin5 *recycleBin;
15 DELETED_FILE_RECORD deletedFile;
16 IRecycleBinFile recycleBinFileImpl;
17 WCHAR FullName[ANY_SIZE];
18 };
19
20 static HRESULT STDMETHODCALLTYPE
21 RecycleBin5File_RecycleBinFile_QueryInterface(
22 IN IRecycleBinFile *This,
23 IN REFIID riid,
24 OUT void **ppvObject)
25 {
26 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
27
28 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
29
30 if (!ppvObject)
31 return E_POINTER;
32
33 if (IsEqualIID(riid, &IID_IUnknown))
34 *ppvObject = &s->recycleBinFileImpl;
35 else if (IsEqualIID(riid, &IID_IRecycleBinFile))
36 *ppvObject = &s->recycleBinFileImpl;
37 else
38 {
39 *ppvObject = NULL;
40 return E_NOINTERFACE;
41 }
42
43 IUnknown_AddRef(This);
44 return S_OK;
45 }
46
47 static ULONG STDMETHODCALLTYPE
48 RecycleBin5File_RecycleBinFile_AddRef(
49 IN IRecycleBinFile *This)
50 {
51 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
52 ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
53 TRACE("(%p)\n", This);
54 return refCount;
55 }
56
57 static VOID
58 RecycleBin5File_Destructor(
59 struct RecycleBin5File *s)
60 {
61 TRACE("(%p)\n", s);
62
63 IRecycleBin5_Release(s->recycleBin);
64 CoTaskMemFree(s);
65 }
66
67 static ULONG STDMETHODCALLTYPE
68 RecycleBin5File_RecycleBinFile_Release(
69 IN IRecycleBinFile *This)
70 {
71 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
72 ULONG refCount;
73
74 TRACE("(%p)\n", This);
75
76 refCount = InterlockedDecrement((PLONG)&s->ref);
77
78 if (refCount == 0)
79 RecycleBin5File_Destructor(s);
80
81 return refCount;
82 }
83
84 static HRESULT STDMETHODCALLTYPE
85 RecycleBin5File_RecycleBinFile_GetLastModificationTime(
86 IN IRecycleBinFile *This,
87 OUT FILETIME *pLastModificationTime)
88 {
89 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
90 HRESULT hr;
91 DWORD dwAttributes;
92 HANDLE hFile;
93
94 TRACE("(%p, %p)\n", This, pLastModificationTime);
95
96 dwAttributes = GetFileAttributesW(s->FullName);
97 if (dwAttributes == INVALID_FILE_ATTRIBUTES)
98 return HRESULT_FROM_WIN32(GetLastError());
99 if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
100 hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
101 else
102 hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
103 if (hFile == INVALID_HANDLE_VALUE)
104 return HRESULT_FROM_WIN32(GetLastError());
105
106 if (GetFileTime(hFile, NULL, NULL, pLastModificationTime))
107 hr = S_OK;
108 else
109 hr = HRESULT_FROM_WIN32(GetLastError());
110 CloseHandle(hFile);
111 return hr;
112 }
113
114 static HRESULT STDMETHODCALLTYPE
115 RecycleBin5File_RecycleBinFile_GetDeletionTime(
116 IN IRecycleBinFile *This,
117 OUT FILETIME *pDeletionTime)
118 {
119 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
120 TRACE("(%p, %p)\n", This, pDeletionTime);
121 *pDeletionTime = s->deletedFile.DeletionTime;
122 return S_OK;
123 }
124
125 static HRESULT STDMETHODCALLTYPE
126 RecycleBin5File_RecycleBinFile_GetFileSize(
127 IN IRecycleBinFile *This,
128 OUT ULARGE_INTEGER *pFileSize)
129 {
130 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
131 HRESULT hr;
132 DWORD dwAttributes;
133 HANDLE hFile;
134
135 TRACE("(%p, %p)\n", This, pFileSize);
136
137 dwAttributes = GetFileAttributesW(s->FullName);
138 if (dwAttributes == INVALID_FILE_ATTRIBUTES)
139 return HRESULT_FROM_WIN32(GetLastError());
140 if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
141 {
142 pFileSize->QuadPart = 0;
143 return S_OK;
144 }
145
146 hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
147 if (hFile == INVALID_HANDLE_VALUE)
148 return HRESULT_FROM_WIN32(GetLastError());
149 pFileSize->u.LowPart = GetFileSize(hFile, &pFileSize->u.HighPart);
150 if (pFileSize->u.LowPart != INVALID_FILE_SIZE)
151 hr = S_OK;
152 else
153 hr = HRESULT_FROM_WIN32(GetLastError());
154 CloseHandle(hFile);
155 return hr;
156 }
157
158 static HRESULT STDMETHODCALLTYPE
159 RecycleBin5File_RecycleBinFile_GetPhysicalFileSize(
160 IN IRecycleBinFile *This,
161 OUT ULARGE_INTEGER *pPhysicalFileSize)
162 {
163 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
164 TRACE("(%p, %p)\n", This, pPhysicalFileSize);
165 pPhysicalFileSize->u.HighPart = 0;
166 pPhysicalFileSize->u.LowPart = s->deletedFile.dwPhysicalFileSize;
167 return S_OK;
168 }
169
170 static HRESULT STDMETHODCALLTYPE
171 RecycleBin5File_RecycleBinFile_GetAttributes(
172 IN IRecycleBinFile *This,
173 OUT DWORD *pAttributes)
174 {
175 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
176 DWORD dwAttributes;
177
178 TRACE("(%p, %p)\n", This, pAttributes);
179
180 dwAttributes = GetFileAttributesW(s->FullName);
181 if (dwAttributes == INVALID_FILE_ATTRIBUTES)
182 return HRESULT_FROM_WIN32(GetLastError());
183
184 *pAttributes = dwAttributes;
185 return S_OK;
186 }
187
188 static HRESULT STDMETHODCALLTYPE
189 RecycleBin5File_RecycleBinFile_GetFileName(
190 IN IRecycleBinFile *This,
191 IN SIZE_T BufferSize,
192 IN OUT LPWSTR Buffer,
193 OUT SIZE_T *RequiredSize)
194 {
195 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
196 DWORD dwRequired;
197
198 TRACE("(%p, %u, %p, %p)\n", This, BufferSize, Buffer, RequiredSize);
199
200 dwRequired = (DWORD)(wcslen(s->deletedFile.FileNameW) + 1) * sizeof(WCHAR);
201 if (RequiredSize)
202 *RequiredSize = dwRequired;
203
204 if (BufferSize == 0 && !Buffer)
205 return S_OK;
206
207 if (BufferSize < dwRequired)
208 return E_OUTOFMEMORY;
209 CopyMemory(Buffer, s->deletedFile.FileNameW, dwRequired);
210 return S_OK;
211 }
212
213 static HRESULT STDMETHODCALLTYPE
214 RecycleBin5File_RecycleBinFile_Delete(
215 IN IRecycleBinFile *This)
216 {
217 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
218 TRACE("(%p)\n", This);
219 return IRecycleBin5_Delete(s->recycleBin, s->FullName, &s->deletedFile);
220 }
221
222 static HRESULT STDMETHODCALLTYPE
223 RecycleBin5File_RecycleBinFile_Restore(
224 IN IRecycleBinFile *This)
225 {
226 struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
227 TRACE("(%p)\n", This);
228 return IRecycleBin5_Restore(s->recycleBin, s->FullName, &s->deletedFile);
229 }
230
231 CONST_VTBL struct IRecycleBinFileVtbl RecycleBin5FileVtbl =
232 {
233 RecycleBin5File_RecycleBinFile_QueryInterface,
234 RecycleBin5File_RecycleBinFile_AddRef,
235 RecycleBin5File_RecycleBinFile_Release,
236 RecycleBin5File_RecycleBinFile_GetLastModificationTime,
237 RecycleBin5File_RecycleBinFile_GetDeletionTime,
238 RecycleBin5File_RecycleBinFile_GetFileSize,
239 RecycleBin5File_RecycleBinFile_GetPhysicalFileSize,
240 RecycleBin5File_RecycleBinFile_GetAttributes,
241 RecycleBin5File_RecycleBinFile_GetFileName,
242 RecycleBin5File_RecycleBinFile_Delete,
243 RecycleBin5File_RecycleBinFile_Restore,
244 };
245
246 static HRESULT
247 RecycleBin5File_Constructor(
248 IN IRecycleBin5 *prb,
249 IN LPCWSTR Folder,
250 IN PDELETED_FILE_RECORD pDeletedFile,
251 OUT IRecycleBinFile **ppFile)
252 {
253 struct RecycleBin5File *s = NULL;
254 LPCWSTR Extension;
255 SIZE_T Needed;
256
257 if (!ppFile)
258 return E_POINTER;
259
260 Extension = wcsrchr(pDeletedFile->FileNameW, '.');
261 if (Extension < wcsrchr(pDeletedFile->FileNameW, '\\'))
262 Extension = NULL;
263 Needed = wcslen(Folder) + 13;
264 if (Extension)
265 Needed += wcslen(Extension);
266 Needed *= sizeof(WCHAR);
267
268 s = CoTaskMemAlloc(sizeof(struct RecycleBin5File) + Needed);
269 if (!s)
270 return E_OUTOFMEMORY;
271 ZeroMemory(s, sizeof(struct RecycleBin5File) + Needed);
272 s->recycleBinFileImpl.lpVtbl = &RecycleBin5FileVtbl;
273 s->ref = 1;
274 s->deletedFile = *pDeletedFile;
275 s->recycleBin = prb;
276 IRecycleBin5_AddRef(s->recycleBin);
277 *ppFile = &s->recycleBinFileImpl;
278 wsprintfW(s->FullName, L"%s\\D%c%lu%s", Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension);
279 if (GetFileAttributesW(s->FullName) == INVALID_FILE_ATTRIBUTES)
280 {
281 RecycleBin5File_Destructor(s);
282 return E_FAIL;
283 }
284
285 return S_OK;
286 }
287
288 struct RecycleBin5Enum
289 {
290 ULONG ref;
291 IRecycleBin5 *recycleBin;
292 HANDLE hInfo;
293 INFO2_HEADER *pInfo;
294 DWORD dwCurrent;
295 IRecycleBinEnumList recycleBinEnumImpl;
296 WCHAR szPrefix[ANY_SIZE];
297 };
298
299 static HRESULT STDMETHODCALLTYPE
300 RecycleBin5Enum_RecycleBinEnumList_QueryInterface(
301 IN IRecycleBinEnumList *This,
302 IN REFIID riid,
303 OUT void **ppvObject)
304 {
305 struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
306
307 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
308
309 if (!ppvObject)
310 return E_POINTER;
311
312 if (IsEqualIID(riid, &IID_IUnknown))
313 *ppvObject = &s->recycleBinEnumImpl;
314 else if (IsEqualIID(riid, &IID_IRecycleBinEnumList))
315 *ppvObject = &s->recycleBinEnumImpl;
316 else
317 {
318 *ppvObject = NULL;
319 return E_NOINTERFACE;
320 }
321
322 IUnknown_AddRef(This);
323 return S_OK;
324 }
325
326 static ULONG STDMETHODCALLTYPE
327 RecycleBin5Enum_RecycleBinEnumList_AddRef(
328 IN IRecycleBinEnumList *This)
329 {
330 struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
331 ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
332 TRACE("(%p)\n", This);
333 return refCount;
334 }
335
336 static VOID
337 RecycleBin5Enum_Destructor(
338 struct RecycleBin5Enum *s)
339 {
340 TRACE("(%p)\n", s);
341
342 IRecycleBin5_OnClosing(s->recycleBin, &s->recycleBinEnumImpl);
343 UnmapViewOfFile(s->pInfo);
344 IRecycleBin5_Release(s->recycleBin);
345 CoTaskMemFree(s);
346 }
347
348 static ULONG STDMETHODCALLTYPE
349 RecycleBin5Enum_RecycleBinEnumList_Release(
350 IN IRecycleBinEnumList *This)
351 {
352 struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
353 ULONG refCount;
354
355 TRACE("(%p)\n", This);
356
357 refCount = InterlockedDecrement((PLONG)&s->ref);
358
359 if (refCount == 0)
360 RecycleBin5Enum_Destructor(s);
361
362 return refCount;
363 }
364
365 static HRESULT STDMETHODCALLTYPE
366 RecycleBin5Enum_RecycleBinEnumList_Next(
367 IRecycleBinEnumList *This,
368 IN DWORD celt,
369 IN OUT IRecycleBinFile **rgelt,
370 OUT DWORD *pceltFetched)
371 {
372 struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
373 ULARGE_INTEGER FileSize;
374 INFO2_HEADER *pHeader = s->pInfo;
375 DELETED_FILE_RECORD *pDeletedFile;
376 DWORD fetched = 0, i;
377 DWORD dwEntries;
378 HRESULT hr;
379
380 TRACE("(%p, %u, %p, %p)\n", This, celt, rgelt, pceltFetched);
381
382 if (!rgelt)
383 return E_POINTER;
384 if (!pceltFetched && celt > 1)
385 return E_INVALIDARG;
386
387 FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
388 if (FileSize.u.LowPart == 0)
389 return HRESULT_FROM_WIN32(GetLastError());
390 dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
391
392 i = s->dwCurrent;
393 pDeletedFile = (DELETED_FILE_RECORD *)(pHeader + 1) + i;
394 for (; i < dwEntries && fetched < celt; i++)
395 {
396 hr = RecycleBin5File_Constructor(s->recycleBin, s->szPrefix, pDeletedFile, &rgelt[fetched]);
397 if (SUCCEEDED(hr))
398 fetched++;
399 pDeletedFile++;
400 }
401
402 s->dwCurrent = i;
403 if (pceltFetched)
404 *pceltFetched = fetched;
405 if (fetched == celt)
406 return S_OK;
407 else
408 return S_FALSE;
409 }
410
411 static HRESULT STDMETHODCALLTYPE
412 RecycleBin5Enum_RecycleBinEnumList_Skip(
413 IN IRecycleBinEnumList *This,
414 IN DWORD celt)
415 {
416 struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
417 TRACE("(%p, %u)\n", This, celt);
418 s->dwCurrent += celt;
419 return S_OK;
420 }
421
422 static HRESULT STDMETHODCALLTYPE
423 RecycleBin5Enum_RecycleBinEnumList_Reset(
424 IN IRecycleBinEnumList *This)
425 {
426 struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
427 TRACE("(%p)\n", This);
428 s->dwCurrent = 0;
429 return S_OK;
430 }
431
432 CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBin5EnumVtbl =
433 {
434 RecycleBin5Enum_RecycleBinEnumList_QueryInterface,
435 RecycleBin5Enum_RecycleBinEnumList_AddRef,
436 RecycleBin5Enum_RecycleBinEnumList_Release,
437 RecycleBin5Enum_RecycleBinEnumList_Next,
438 RecycleBin5Enum_RecycleBinEnumList_Skip,
439 RecycleBin5Enum_RecycleBinEnumList_Reset,
440 };
441
442 HRESULT
443 RecycleBin5Enum_Constructor(
444 IN IRecycleBin5 *prb,
445 IN HANDLE hInfo,
446 IN HANDLE hInfoMapped,
447 IN LPCWSTR szPrefix,
448 OUT IUnknown **ppUnknown)
449 {
450 struct RecycleBin5Enum *s = NULL;
451 SIZE_T Needed;
452
453 if (!ppUnknown)
454 return E_POINTER;
455
456 Needed = (wcslen(szPrefix) + 1) * sizeof(WCHAR);
457
458 s = CoTaskMemAlloc(sizeof(struct RecycleBin5Enum) + Needed);
459 if (!s)
460 return E_OUTOFMEMORY;
461 ZeroMemory(s, sizeof(struct RecycleBin5Enum) + Needed);
462 s->recycleBinEnumImpl.lpVtbl = &RecycleBin5EnumVtbl;
463 s->ref = 1;
464 s->recycleBin = prb;
465 wcscpy(s->szPrefix, szPrefix);
466 s->hInfo = hInfo;
467 s->pInfo = MapViewOfFile(hInfoMapped, FILE_MAP_READ, 0, 0, 0);
468 if (!s->pInfo)
469 {
470 CoTaskMemFree(s);
471 return HRESULT_FROM_WIN32(GetLastError());
472 }
473 if (s->pInfo->dwVersion != 5 || s->pInfo->dwRecordSize != sizeof(DELETED_FILE_RECORD))
474 {
475 UnmapViewOfFile(s->pInfo);
476 CoTaskMemFree(s);
477 return E_FAIL;
478 }
479 IRecycleBin5_AddRef(s->recycleBin);
480 *ppUnknown = (IUnknown *)&s->recycleBinEnumImpl;
481
482 return S_OK;
483 }