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)
9 #include "recyclebin_private.h"
11 struct RecycleBin5File
14 IRecycleBin5
*recycleBin
;
15 DELETED_FILE_RECORD deletedFile
;
16 IRecycleBinFile recycleBinFileImpl
;
17 WCHAR FullName
[ANY_SIZE
];
20 static HRESULT STDMETHODCALLTYPE
21 RecycleBin5File_RecycleBinFile_QueryInterface(
22 IN IRecycleBinFile
*This
,
26 struct RecycleBin5File
*s
= CONTAINING_RECORD(This
, struct RecycleBin5File
, recycleBinFileImpl
);
28 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
33 if (IsEqualIID(riid
, &IID_IUnknown
))
34 *ppvObject
= &s
->recycleBinFileImpl
;
35 else if (IsEqualIID(riid
, &IID_IRecycleBinFile
))
36 *ppvObject
= &s
->recycleBinFileImpl
;
43 IUnknown_AddRef(This
);
47 static ULONG STDMETHODCALLTYPE
48 RecycleBin5File_RecycleBinFile_AddRef(
49 IN IRecycleBinFile
*This
)
51 struct RecycleBin5File
*s
= CONTAINING_RECORD(This
, struct RecycleBin5File
, recycleBinFileImpl
);
52 ULONG refCount
= InterlockedIncrement((PLONG
)&s
->ref
);
53 TRACE("(%p)\n", This
);
58 RecycleBin5File_Destructor(
59 struct RecycleBin5File
*s
)
63 IRecycleBin5_Release(s
->recycleBin
);
67 static ULONG STDMETHODCALLTYPE
68 RecycleBin5File_RecycleBinFile_Release(
69 IN IRecycleBinFile
*This
)
71 struct RecycleBin5File
*s
= CONTAINING_RECORD(This
, struct RecycleBin5File
, recycleBinFileImpl
);
74 TRACE("(%p)\n", This
);
76 refCount
= InterlockedDecrement((PLONG
)&s
->ref
);
79 RecycleBin5File_Destructor(s
);
84 static HRESULT STDMETHODCALLTYPE
85 RecycleBin5File_RecycleBinFile_GetLastModificationTime(
86 IN IRecycleBinFile
*This
,
87 OUT FILETIME
*pLastModificationTime
)
89 struct RecycleBin5File
*s
= CONTAINING_RECORD(This
, struct RecycleBin5File
, recycleBinFileImpl
);
94 TRACE("(%p, %p)\n", This
, pLastModificationTime
);
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
);
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());
106 if (GetFileTime(hFile
, NULL
, NULL
, pLastModificationTime
))
109 hr
= HRESULT_FROM_WIN32(GetLastError());
114 static HRESULT STDMETHODCALLTYPE
115 RecycleBin5File_RecycleBinFile_GetDeletionTime(
116 IN IRecycleBinFile
*This
,
117 OUT FILETIME
*pDeletionTime
)
119 struct RecycleBin5File
*s
= CONTAINING_RECORD(This
, struct RecycleBin5File
, recycleBinFileImpl
);
120 TRACE("(%p, %p)\n", This
, pDeletionTime
);
121 *pDeletionTime
= s
->deletedFile
.DeletionTime
;
125 static HRESULT STDMETHODCALLTYPE
126 RecycleBin5File_RecycleBinFile_GetFileSize(
127 IN IRecycleBinFile
*This
,
128 OUT ULARGE_INTEGER
*pFileSize
)
130 struct RecycleBin5File
*s
= CONTAINING_RECORD(This
, struct RecycleBin5File
, recycleBinFileImpl
);
135 TRACE("(%p, %p)\n", This
, pFileSize
);
137 dwAttributes
= GetFileAttributesW(s
->FullName
);
138 if (dwAttributes
== INVALID_FILE_ATTRIBUTES
)
139 return HRESULT_FROM_WIN32(GetLastError());
140 if (dwAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
142 pFileSize
->QuadPart
= 0;
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
)
153 hr
= HRESULT_FROM_WIN32(GetLastError());
158 static HRESULT STDMETHODCALLTYPE
159 RecycleBin5File_RecycleBinFile_GetPhysicalFileSize(
160 IN IRecycleBinFile
*This
,
161 OUT ULARGE_INTEGER
*pPhysicalFileSize
)
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
;
170 static HRESULT STDMETHODCALLTYPE
171 RecycleBin5File_RecycleBinFile_GetAttributes(
172 IN IRecycleBinFile
*This
,
173 OUT DWORD
*pAttributes
)
175 struct RecycleBin5File
*s
= CONTAINING_RECORD(This
, struct RecycleBin5File
, recycleBinFileImpl
);
178 TRACE("(%p, %p)\n", This
, pAttributes
);
180 dwAttributes
= GetFileAttributesW(s
->FullName
);
181 if (dwAttributes
== INVALID_FILE_ATTRIBUTES
)
182 return HRESULT_FROM_WIN32(GetLastError());
184 *pAttributes
= dwAttributes
;
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
)
195 struct RecycleBin5File
*s
= CONTAINING_RECORD(This
, struct RecycleBin5File
, recycleBinFileImpl
);
198 TRACE("(%p, %u, %p, %p)\n", This
, BufferSize
, Buffer
, RequiredSize
);
200 dwRequired
= (DWORD
)(wcslen(s
->deletedFile
.FileNameW
) + 1) * sizeof(WCHAR
);
202 *RequiredSize
= dwRequired
;
204 if (BufferSize
== 0 && !Buffer
)
207 if (BufferSize
< dwRequired
)
208 return E_OUTOFMEMORY
;
209 CopyMemory(Buffer
, s
->deletedFile
.FileNameW
, dwRequired
);
213 static HRESULT STDMETHODCALLTYPE
214 RecycleBin5File_RecycleBinFile_Delete(
215 IN IRecycleBinFile
*This
)
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
);
222 static HRESULT STDMETHODCALLTYPE
223 RecycleBin5File_RecycleBinFile_Restore(
224 IN IRecycleBinFile
*This
)
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
);
231 CONST_VTBL
struct IRecycleBinFileVtbl RecycleBin5FileVtbl
=
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
,
247 RecycleBin5File_Constructor(
248 IN IRecycleBin5
*prb
,
250 IN PDELETED_FILE_RECORD pDeletedFile
,
251 OUT IRecycleBinFile
**ppFile
)
253 struct RecycleBin5File
*s
= NULL
;
260 Extension
= wcsrchr(pDeletedFile
->FileNameW
, '.');
261 if (Extension
< wcsrchr(pDeletedFile
->FileNameW
, '\\'))
263 Needed
= wcslen(Folder
) + 13;
265 Needed
+= wcslen(Extension
);
266 Needed
*= sizeof(WCHAR
);
268 s
= CoTaskMemAlloc(sizeof(struct RecycleBin5File
) + Needed
);
270 return E_OUTOFMEMORY
;
271 ZeroMemory(s
, sizeof(struct RecycleBin5File
) + Needed
);
272 s
->recycleBinFileImpl
.lpVtbl
= &RecycleBin5FileVtbl
;
274 s
->deletedFile
= *pDeletedFile
;
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
)
281 RecycleBin5File_Destructor(s
);
288 struct RecycleBin5Enum
291 IRecycleBin5
*recycleBin
;
295 IRecycleBinEnumList recycleBinEnumImpl
;
296 WCHAR szPrefix
[ANY_SIZE
];
299 static HRESULT STDMETHODCALLTYPE
300 RecycleBin5Enum_RecycleBinEnumList_QueryInterface(
301 IN IRecycleBinEnumList
*This
,
303 OUT
void **ppvObject
)
305 struct RecycleBin5Enum
*s
= CONTAINING_RECORD(This
, struct RecycleBin5Enum
, recycleBinEnumImpl
);
307 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
312 if (IsEqualIID(riid
, &IID_IUnknown
))
313 *ppvObject
= &s
->recycleBinEnumImpl
;
314 else if (IsEqualIID(riid
, &IID_IRecycleBinEnumList
))
315 *ppvObject
= &s
->recycleBinEnumImpl
;
319 return E_NOINTERFACE
;
322 IUnknown_AddRef(This
);
326 static ULONG STDMETHODCALLTYPE
327 RecycleBin5Enum_RecycleBinEnumList_AddRef(
328 IN IRecycleBinEnumList
*This
)
330 struct RecycleBin5Enum
*s
= CONTAINING_RECORD(This
, struct RecycleBin5Enum
, recycleBinEnumImpl
);
331 ULONG refCount
= InterlockedIncrement((PLONG
)&s
->ref
);
332 TRACE("(%p)\n", This
);
337 RecycleBin5Enum_Destructor(
338 struct RecycleBin5Enum
*s
)
342 IRecycleBin5_OnClosing(s
->recycleBin
, &s
->recycleBinEnumImpl
);
343 UnmapViewOfFile(s
->pInfo
);
344 IRecycleBin5_Release(s
->recycleBin
);
348 static ULONG STDMETHODCALLTYPE
349 RecycleBin5Enum_RecycleBinEnumList_Release(
350 IN IRecycleBinEnumList
*This
)
352 struct RecycleBin5Enum
*s
= CONTAINING_RECORD(This
, struct RecycleBin5Enum
, recycleBinEnumImpl
);
355 TRACE("(%p)\n", This
);
357 refCount
= InterlockedDecrement((PLONG
)&s
->ref
);
360 RecycleBin5Enum_Destructor(s
);
365 static HRESULT STDMETHODCALLTYPE
366 RecycleBin5Enum_RecycleBinEnumList_Next(
367 IRecycleBinEnumList
*This
,
369 IN OUT IRecycleBinFile
**rgelt
,
370 OUT DWORD
*pceltFetched
)
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
;
380 TRACE("(%p, %u, %p, %p)\n", This
, celt
, rgelt
, pceltFetched
);
384 if (!pceltFetched
&& celt
> 1)
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
));
393 pDeletedFile
= (DELETED_FILE_RECORD
*)(pHeader
+ 1) + i
;
394 for (; i
< dwEntries
&& fetched
< celt
; i
++)
396 hr
= RecycleBin5File_Constructor(s
->recycleBin
, s
->szPrefix
, pDeletedFile
, &rgelt
[fetched
]);
404 *pceltFetched
= fetched
;
411 static HRESULT STDMETHODCALLTYPE
412 RecycleBin5Enum_RecycleBinEnumList_Skip(
413 IN IRecycleBinEnumList
*This
,
416 struct RecycleBin5Enum
*s
= CONTAINING_RECORD(This
, struct RecycleBin5Enum
, recycleBinEnumImpl
);
417 TRACE("(%p, %u)\n", This
, celt
);
418 s
->dwCurrent
+= celt
;
422 static HRESULT STDMETHODCALLTYPE
423 RecycleBin5Enum_RecycleBinEnumList_Reset(
424 IN IRecycleBinEnumList
*This
)
426 struct RecycleBin5Enum
*s
= CONTAINING_RECORD(This
, struct RecycleBin5Enum
, recycleBinEnumImpl
);
427 TRACE("(%p)\n", This
);
432 CONST_VTBL
struct IRecycleBinEnumListVtbl RecycleBin5EnumVtbl
=
434 RecycleBin5Enum_RecycleBinEnumList_QueryInterface
,
435 RecycleBin5Enum_RecycleBinEnumList_AddRef
,
436 RecycleBin5Enum_RecycleBinEnumList_Release
,
437 RecycleBin5Enum_RecycleBinEnumList_Next
,
438 RecycleBin5Enum_RecycleBinEnumList_Skip
,
439 RecycleBin5Enum_RecycleBinEnumList_Reset
,
443 RecycleBin5Enum_Constructor(
444 IN IRecycleBin5
*prb
,
446 IN HANDLE hInfoMapped
,
448 OUT IUnknown
**ppUnknown
)
450 struct RecycleBin5Enum
*s
= NULL
;
456 Needed
= (wcslen(szPrefix
) + 1) * sizeof(WCHAR
);
458 s
= CoTaskMemAlloc(sizeof(struct RecycleBin5Enum
) + Needed
);
460 return E_OUTOFMEMORY
;
461 ZeroMemory(s
, sizeof(struct RecycleBin5Enum
) + Needed
);
462 s
->recycleBinEnumImpl
.lpVtbl
= &RecycleBin5EnumVtbl
;
465 wcscpy(s
->szPrefix
, szPrefix
);
467 s
->pInfo
= MapViewOfFile(hInfoMapped
, FILE_MAP_READ
, 0, 0, 0);
471 return HRESULT_FROM_WIN32(GetLastError());
473 if (s
->pInfo
->dwVersion
!= 5 || s
->pInfo
->dwRecordSize
!= sizeof(DELETED_FILE_RECORD
))
475 UnmapViewOfFile(s
->pInfo
);
479 IRecycleBin5_AddRef(s
->recycleBin
);
480 *ppUnknown
= (IUnknown
*)&s
->recycleBinEnumImpl
;