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
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
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
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
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
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
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
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
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
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
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
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
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
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