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 = IRecycleBinFileFromHDELFILE(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
DeleteFileInRecycleBin(IN HDELFILE hDeletedFile)93 DeleteFileInRecycleBin(
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, (HDELFILE)prbf))
235         {
236             UINT error = GetLastError();
237             hr = HRESULT_FROM_WIN32(error);
238             goto cleanup;
239         }
240     }
241 
242 cleanup:
243     if (prb)
244         IRecycleBin_Release(prb);
245     if (prbel)
246         IRecycleBinEnumList_Release(prbel);
247     if (SUCCEEDED(hr))
248         return TRUE;
249     if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
250         SetLastError(HRESULT_CODE(hr));
251     else
252         SetLastError(ERROR_GEN_FAILURE);
253     return FALSE;
254 }
255 
256 typedef struct _BBENUMFILECONTEXT
257 {
258     const RECYCLEBINFILEIDENTITY *pFI;
259     HDELFILE hDelFile;
260 } BBENUMFILECONTEXT;
261 
262 static BOOL CALLBACK
GetRecycleBinFileHandleCallback(IN PVOID Context,IN HDELFILE hDeletedFile)263 GetRecycleBinFileHandleCallback(IN PVOID Context, IN HDELFILE hDeletedFile)
264 {
265     BBENUMFILECONTEXT *pCtx = (BBENUMFILECONTEXT*)Context;
266     IRecycleBinFile *pRBF = IRecycleBinFileFromHDELFILE(hDeletedFile);
267     if (IRecycleBinFile_IsEqualIdentity(pRBF, pCtx->pFI) == S_OK)
268     {
269         pCtx->hDelFile = hDeletedFile;
270         return FALSE;
271     }
272     CloseRecycleBinHandle(hDeletedFile);
273     return TRUE;
274 }
275 
276 EXTERN_C HDELFILE
GetRecycleBinFileHandle(IN LPCWSTR pszRoot OPTIONAL,IN const RECYCLEBINFILEIDENTITY * pFI)277 GetRecycleBinFileHandle(
278     IN LPCWSTR pszRoot OPTIONAL,
279     IN const RECYCLEBINFILEIDENTITY *pFI)
280 {
281     BBENUMFILECONTEXT context = { pFI, NULL };
282     EnumerateRecycleBinW(pszRoot, GetRecycleBinFileHandleCallback, &context);
283     return context.hDelFile;
284 }
285 
286 BOOL WINAPI
RestoreFileFromRecycleBin(IN HDELFILE hDeletedFile)287 RestoreFileFromRecycleBin(
288     IN HDELFILE hDeletedFile)
289 {
290     IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
291     HRESULT hr;
292 
293     TRACE("(%p)\n", hDeletedFile);
294 
295     hr = IRecycleBinFile_Restore(rbf);
296     if (SUCCEEDED(hr))
297         return TRUE;
298     if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
299         SetLastError(HRESULT_CODE(hr));
300     else
301         SetLastError(ERROR_GEN_FAILURE);
302     return FALSE;
303 }
304 
305 EXTERN_C HRESULT
GetDefaultRecycleBin(IN LPCWSTR pszVolume OPTIONAL,OUT IRecycleBin ** pprb)306 GetDefaultRecycleBin(
307     IN LPCWSTR pszVolume OPTIONAL,
308     OUT IRecycleBin **pprb)
309 {
310     IUnknown *pUnk;
311     HRESULT hr;
312 
313     TRACE("(%s, %p)\n", debugstr_w(pszVolume), pprb);
314 
315     if (!pprb)
316         return E_POINTER;
317 
318     if (!pszVolume)
319         hr = RecycleBinGeneric_Constructor(&pUnk);
320     else
321     {
322         /* FIXME: do a better validation! */
323         if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
324             return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
325 
326         /* For now, only support this type of recycle bins... */
327         hr = RecycleBin5_Constructor(pszVolume, &pUnk);
328     }
329     if (!SUCCEEDED(hr))
330         return hr;
331     hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBin, (void **)pprb);
332     IUnknown_Release(pUnk);
333     return hr;
334 }
335 
336 EXTERN_C HRESULT
GetRecycleBinPathFromDriveNumber(UINT Drive,LPWSTR Path)337 GetRecycleBinPathFromDriveNumber(UINT Drive, LPWSTR Path)
338 {
339     const WCHAR volume[] = { LOWORD('A' + Drive), ':', '\\', '\0' };
340     IRecycleBin *pRB;
341     HRESULT hr = GetDefaultRecycleBin(volume, &pRB);
342     if (SUCCEEDED(hr))
343     {
344         hr = IRecycleBin_GetDirectory(pRB, Path);
345         IRecycleBin_Release(pRB);
346     }
347     return hr;
348 }
349