1 /*
2 * PROJECT: Recycle bin management
3 * LICENSE: GPL v2 - See COPYING in the top level directory
4 * FILE: lib/recyclebin/recyclebin.c
5 * PURPOSE: Public interface
6 * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 #include "recyclebin_private.h"
10
11 BOOL WINAPI
CloseRecycleBinHandle(IN HDELFILE hDeletedFile)12 CloseRecycleBinHandle(
13 IN HDELFILE hDeletedFile)
14 {
15 IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
16 HRESULT hr;
17
18 TRACE("(%p)\n", hDeletedFile);
19
20 hr = IRecycleBinFile_Release(rbf);
21 if (SUCCEEDED(hr))
22 return TRUE;
23 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
24 SetLastError(HRESULT_CODE(hr));
25 else
26 SetLastError(ERROR_GEN_FAILURE);
27 return FALSE;
28 }
29
30 BOOL WINAPI
DeleteFileToRecycleBinA(IN LPCSTR FileName)31 DeleteFileToRecycleBinA(
32 IN LPCSTR FileName)
33 {
34 int len;
35 LPWSTR FileNameW = NULL;
36 BOOL ret = FALSE;
37
38 TRACE("(%s)\n", debugstr_a(FileName));
39
40 /* Check parameters */
41 if (FileName == NULL)
42 {
43 SetLastError(ERROR_INVALID_PARAMETER);
44 goto cleanup;
45 }
46
47 len = MultiByteToWideChar(CP_ACP, 0, FileName, -1, NULL, 0);
48 if (len == 0)
49 goto cleanup;
50 FileNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
51 if (!FileNameW)
52 {
53 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
54 goto cleanup;
55 }
56 if (MultiByteToWideChar(CP_ACP, 0, FileName, -1, FileNameW, len) == 0)
57 goto cleanup;
58
59 ret = DeleteFileToRecycleBinW(FileNameW);
60
61 cleanup:
62 HeapFree(GetProcessHeap(), 0, FileNameW);
63 return ret;
64 }
65
66 BOOL WINAPI
DeleteFileToRecycleBinW(IN LPCWSTR FileName)67 DeleteFileToRecycleBinW(
68 IN LPCWSTR FileName)
69 {
70 IRecycleBin *prb;
71 HRESULT hr;
72
73 TRACE("(%s)\n", debugstr_w(FileName));
74
75 hr = GetDefaultRecycleBin(NULL, &prb);
76 if (!SUCCEEDED(hr))
77 goto cleanup;
78
79 hr = IRecycleBin_DeleteFile(prb, FileName);
80 IRecycleBin_Release(prb);
81
82 cleanup:
83 if (SUCCEEDED(hr))
84 return TRUE;
85 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
86 SetLastError(HRESULT_CODE(hr));
87 else
88 SetLastError(ERROR_GEN_FAILURE);
89 return FALSE;
90 }
91
92 BOOL WINAPI
DeleteFileHandleToRecycleBin(IN HDELFILE hDeletedFile)93 DeleteFileHandleToRecycleBin(
94 IN HDELFILE hDeletedFile)
95 {
96 IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
97 HRESULT hr;
98
99 TRACE("(%p)\n", hDeletedFile);
100
101 hr = IRecycleBinFile_Delete(rbf);
102
103 if (SUCCEEDED(hr))
104 return TRUE;
105 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
106 SetLastError(HRESULT_CODE(hr));
107 else
108 SetLastError(ERROR_GEN_FAILURE);
109 return FALSE;
110 }
111
112 BOOL WINAPI
EmptyRecycleBinA(IN LPCSTR pszRoot OPTIONAL)113 EmptyRecycleBinA(
114 IN LPCSTR pszRoot OPTIONAL)
115 {
116 int len;
117 LPWSTR szRootW = NULL;
118 BOOL ret = FALSE;
119
120 TRACE("(%s)\n", debugstr_a(pszRoot));
121
122 if (pszRoot)
123 {
124 len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
125 if (len == 0)
126 goto cleanup;
127 szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
128 if (!szRootW)
129 {
130 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
131 goto cleanup;
132 }
133 if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
134 goto cleanup;
135 }
136
137 ret = EmptyRecycleBinW(szRootW);
138
139 cleanup:
140 HeapFree(GetProcessHeap(), 0, szRootW);
141 return ret;
142 }
143
144 BOOL WINAPI
EmptyRecycleBinW(IN LPCWSTR pszRoot OPTIONAL)145 EmptyRecycleBinW(
146 IN LPCWSTR pszRoot OPTIONAL)
147 {
148 IRecycleBin *prb;
149 HRESULT hr;
150
151 TRACE("(%s)\n", debugstr_w(pszRoot));
152
153 hr = GetDefaultRecycleBin(pszRoot, &prb);
154 if (!SUCCEEDED(hr))
155 goto cleanup;
156
157 hr = IRecycleBin_EmptyRecycleBin(prb);
158 IRecycleBin_Release(prb);
159
160 cleanup:
161 if (SUCCEEDED(hr))
162 return TRUE;
163 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
164 SetLastError(HRESULT_CODE(hr));
165 else
166 SetLastError(ERROR_GEN_FAILURE);
167 return FALSE;
168 }
169
170 BOOL WINAPI
EnumerateRecycleBinA(IN LPCSTR pszRoot OPTIONAL,IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,IN PVOID Context OPTIONAL)171 EnumerateRecycleBinA(
172 IN LPCSTR pszRoot OPTIONAL,
173 IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
174 IN PVOID Context OPTIONAL)
175 {
176 int len;
177 LPWSTR szRootW = NULL;
178 BOOL ret = FALSE;
179
180 TRACE("(%s, %p, %p)\n", debugstr_a(pszRoot), pFnCallback, Context);
181
182 if (pszRoot)
183 {
184 len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
185 if (len == 0)
186 goto cleanup;
187 szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
188 if (!szRootW)
189 {
190 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
191 goto cleanup;
192 }
193 if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
194 goto cleanup;
195 }
196
197 ret = EnumerateRecycleBinW(szRootW, pFnCallback, Context);
198
199 cleanup:
200 HeapFree(GetProcessHeap(), 0, szRootW);
201 return ret;
202 }
203
204 BOOL WINAPI
EnumerateRecycleBinW(IN LPCWSTR pszRoot OPTIONAL,IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,IN PVOID Context OPTIONAL)205 EnumerateRecycleBinW(
206 IN LPCWSTR pszRoot OPTIONAL,
207 IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
208 IN PVOID Context OPTIONAL)
209 {
210 IRecycleBin *prb = NULL;
211 IRecycleBinEnumList *prbel = NULL;
212 IRecycleBinFile *prbf;
213 HRESULT hr;
214
215 TRACE("(%s, %p, %p)\n", debugstr_w(pszRoot), pFnCallback, Context);
216
217 hr = GetDefaultRecycleBin(NULL, &prb);
218 if (!SUCCEEDED(hr))
219 goto cleanup;
220
221 hr = IRecycleBin_EnumObjects(prb, &prbel);
222 if (!SUCCEEDED(hr))
223 goto cleanup;
224 while (TRUE)
225 {
226 hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
227 if (hr == S_FALSE)
228 {
229 hr = S_OK;
230 goto cleanup;
231 }
232 else if (!SUCCEEDED(hr))
233 goto cleanup;
234 if (!pFnCallback(Context, (HANDLE)prbf))
235 {
236 hr = HRESULT_FROM_WIN32(GetLastError());
237 goto cleanup;
238 }
239 }
240
241 cleanup:
242 if (prb)
243 IRecycleBin_Release(prb);
244 if (prbel)
245 IRecycleBinEnumList_Release(prbel);
246 if (SUCCEEDED(hr))
247 return TRUE;
248 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
249 SetLastError(HRESULT_CODE(hr));
250 else
251 SetLastError(ERROR_GEN_FAILURE);
252 return FALSE;
253 }
254
255 BOOL WINAPI
GetDeletedFileTypeNameW(IN HDELFILE hDeletedFile,OUT LPWSTR pTypeName,IN DWORD BufferSize,OUT LPDWORD RequiredSize OPTIONAL)256 GetDeletedFileTypeNameW(
257 IN HDELFILE hDeletedFile,
258 OUT LPWSTR pTypeName,
259 IN DWORD BufferSize,
260 OUT LPDWORD RequiredSize OPTIONAL)
261 {
262 IRecycleBinFile *prbf = (IRecycleBinFile *)hDeletedFile;
263 SIZE_T FinalSize;
264
265 HRESULT hr = IRecycleBinFile_GetTypeName(prbf, BufferSize, pTypeName, &FinalSize);
266
267 if (SUCCEEDED(hr))
268 {
269 if (RequiredSize)
270 *RequiredSize = (DWORD)FinalSize;
271
272 return TRUE;
273 }
274 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
275 SetLastError(HRESULT_CODE(hr));
276 else
277 SetLastError(ERROR_GEN_FAILURE);
278 return FALSE;
279 }
280
281 BOOL WINAPI
GetDeletedFileDetailsA(IN HDELFILE hDeletedFile,IN DWORD BufferSize,IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL,OUT LPDWORD RequiredSize OPTIONAL)282 GetDeletedFileDetailsA(
283 IN HDELFILE hDeletedFile,
284 IN DWORD BufferSize,
285 IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL,
286 OUT LPDWORD RequiredSize OPTIONAL)
287 {
288 PDELETED_FILE_DETAILS_W FileDetailsW = NULL;
289 DWORD BufferSizeW = 0;
290 BOOL ret = FALSE;
291
292 TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
293
294 if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName))
295 {
296 BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName)
297 + (BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) * sizeof(WCHAR);
298 }
299 if (FileDetails && BufferSizeW)
300 {
301 FileDetailsW = HeapAlloc(GetProcessHeap(), 0, BufferSizeW);
302 if (!FileDetailsW)
303 {
304 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
305 goto cleanup;
306 }
307 }
308
309 ret = GetDeletedFileDetailsW(hDeletedFile, BufferSizeW, FileDetailsW, RequiredSize);
310 if (!ret)
311 goto cleanup;
312
313 if (FileDetails)
314 {
315 CopyMemory(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
316 if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL))
317 goto cleanup;
318 }
319 ret = TRUE;
320
321 cleanup:
322 HeapFree(GetProcessHeap(), 0, FileDetailsW);
323 return ret;
324 }
325
326 BOOL WINAPI
GetDeletedFileDetailsW(IN HDELFILE hDeletedFile,IN DWORD BufferSize,IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,OUT LPDWORD RequiredSize OPTIONAL)327 GetDeletedFileDetailsW(
328 IN HDELFILE hDeletedFile,
329 IN DWORD BufferSize,
330 IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
331 OUT LPDWORD RequiredSize OPTIONAL)
332 {
333 IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
334 HRESULT hr;
335 SIZE_T NameSize, Needed;
336
337 TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
338
339 hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
340 if (!SUCCEEDED(hr))
341 goto cleanup;
342 Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + NameSize;
343 if (RequiredSize)
344 *RequiredSize = (DWORD)Needed;
345 if (Needed > BufferSize)
346 {
347 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
348 goto cleanup;
349 }
350 hr = IRecycleBinFile_GetFileName(rbf, NameSize, FileDetails->FileName, NULL);
351 if (!SUCCEEDED(hr))
352 goto cleanup;
353 hr = IRecycleBinFile_GetLastModificationTime(rbf, &FileDetails->LastModification);
354 if (!SUCCEEDED(hr))
355 goto cleanup;
356 hr = IRecycleBinFile_GetDeletionTime(rbf, &FileDetails->DeletionTime);
357 if (!SUCCEEDED(hr))
358 goto cleanup;
359 hr = IRecycleBinFile_GetFileSize(rbf, &FileDetails->FileSize);
360 if (!SUCCEEDED(hr))
361 goto cleanup;
362 hr = IRecycleBinFile_GetPhysicalFileSize(rbf, &FileDetails->PhysicalFileSize);
363 if (!SUCCEEDED(hr))
364 goto cleanup;
365 hr = IRecycleBinFile_GetAttributes(rbf, &FileDetails->Attributes);
366 if (!SUCCEEDED(hr))
367 goto cleanup;
368
369 cleanup:
370 if (SUCCEEDED(hr))
371 return TRUE;
372 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
373 SetLastError(HRESULT_CODE(hr));
374 else
375 SetLastError(ERROR_GEN_FAILURE);
376 return FALSE;
377 }
378
379 BOOL WINAPI
RestoreFile(IN HDELFILE hDeletedFile)380 RestoreFile(
381 IN HDELFILE hDeletedFile)
382 {
383 IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
384 HRESULT hr;
385
386 TRACE("(%p)\n", hDeletedFile);
387
388 hr = IRecycleBinFile_Restore(rbf);
389 if (SUCCEEDED(hr))
390 return TRUE;
391 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
392 SetLastError(HRESULT_CODE(hr));
393 else
394 SetLastError(ERROR_GEN_FAILURE);
395 return FALSE;
396 }
397
398 HRESULT WINAPI
GetDefaultRecycleBin(IN LPCWSTR pszVolume OPTIONAL,OUT IRecycleBin ** pprb)399 GetDefaultRecycleBin(
400 IN LPCWSTR pszVolume OPTIONAL,
401 OUT IRecycleBin **pprb)
402 {
403 IUnknown *pUnk;
404 HRESULT hr;
405
406 TRACE("(%s, %p)\n", debugstr_w(pszVolume), pprb);
407
408 if (!pprb)
409 return E_POINTER;
410
411 if (!pszVolume)
412 hr = RecycleBinGeneric_Constructor(&pUnk);
413 else
414 {
415 /* FIXME: do a better validation! */
416 if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
417 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
418
419 /* For now, only support this type of recycle bins... */
420 hr = RecycleBin5_Constructor(pszVolume, &pUnk);
421 }
422 if (!SUCCEEDED(hr))
423 return hr;
424 hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBin, (void **)pprb);
425 IUnknown_Release(pUnk);
426 return hr;
427 }
428