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