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