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