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