[SHELL32]
[reactos.git] / reactos / sdk / 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 #include "recyclebin_private.h"
10
11 BOOL WINAPI
12 CloseRecycleBinHandle(
13 IN HANDLE 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 HANDLE 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 GetDeletedFileDetailsA(
257 IN HANDLE hDeletedFile,
258 IN DWORD BufferSize,
259 IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL,
260 OUT LPDWORD RequiredSize OPTIONAL)
261 {
262 PDELETED_FILE_DETAILS_W FileDetailsW = NULL;
263 DWORD BufferSizeW = 0;
264 BOOL ret = FALSE;
265
266 TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
267
268 if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName))
269 {
270 BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName)
271 + (BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) * sizeof(WCHAR);
272 }
273 if (FileDetails && BufferSizeW)
274 {
275 FileDetailsW = HeapAlloc(GetProcessHeap(), 0, BufferSizeW);
276 if (!FileDetailsW)
277 {
278 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
279 goto cleanup;
280 }
281 }
282
283 ret = GetDeletedFileDetailsW(hDeletedFile, BufferSizeW, FileDetailsW, RequiredSize);
284 if (!ret)
285 goto cleanup;
286
287 if (FileDetails)
288 {
289 CopyMemory(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
290 if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL))
291 goto cleanup;
292 }
293 ret = TRUE;
294
295 cleanup:
296 HeapFree(GetProcessHeap(), 0, FileDetailsW);
297 return ret;
298 }
299
300 BOOL WINAPI
301 GetDeletedFileDetailsW(
302 IN HANDLE hDeletedFile,
303 IN DWORD BufferSize,
304 IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
305 OUT LPDWORD RequiredSize OPTIONAL)
306 {
307 IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
308 HRESULT hr;
309 SIZE_T NameSize, Needed;
310
311 TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
312
313 hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
314 if (!SUCCEEDED(hr))
315 goto cleanup;
316 Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + NameSize;
317 if (RequiredSize)
318 *RequiredSize = (DWORD)Needed;
319 if (Needed > BufferSize)
320 {
321 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
322 goto cleanup;
323 }
324 hr = IRecycleBinFile_GetFileName(rbf, NameSize, FileDetails->FileName, NULL);
325 if (!SUCCEEDED(hr))
326 goto cleanup;
327 hr = IRecycleBinFile_GetLastModificationTime(rbf, &FileDetails->LastModification);
328 if (!SUCCEEDED(hr))
329 goto cleanup;
330 hr = IRecycleBinFile_GetDeletionTime(rbf, &FileDetails->DeletionTime);
331 if (!SUCCEEDED(hr))
332 goto cleanup;
333 hr = IRecycleBinFile_GetFileSize(rbf, &FileDetails->FileSize);
334 if (!SUCCEEDED(hr))
335 goto cleanup;
336 hr = IRecycleBinFile_GetPhysicalFileSize(rbf, &FileDetails->PhysicalFileSize);
337 if (!SUCCEEDED(hr))
338 goto cleanup;
339 hr = IRecycleBinFile_GetAttributes(rbf, &FileDetails->Attributes);
340 if (!SUCCEEDED(hr))
341 goto cleanup;
342
343 cleanup:
344 if (SUCCEEDED(hr))
345 return TRUE;
346 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
347 SetLastError(HRESULT_CODE(hr));
348 else
349 SetLastError(ERROR_GEN_FAILURE);
350 return FALSE;
351 }
352
353 BOOL WINAPI
354 GetRecycleBinDetails(
355 IN LPCWSTR pszVolume OPTIONAL,
356 OUT ULARGE_INTEGER *pulTotalItems,
357 OUT ULARGE_INTEGER *pulTotalSize)
358 {
359 pulTotalItems->QuadPart = 0;
360 pulTotalSize->QuadPart = 0;
361 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
362 return FALSE;
363 }
364
365 BOOL WINAPI
366 RestoreFile(
367 IN HANDLE hDeletedFile)
368 {
369 IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
370 HRESULT hr;
371
372 TRACE("(%p)\n", hDeletedFile);
373
374 hr = IRecycleBinFile_Restore(rbf);
375 if (SUCCEEDED(hr))
376 return TRUE;
377 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
378 SetLastError(HRESULT_CODE(hr));
379 else
380 SetLastError(ERROR_GEN_FAILURE);
381 return FALSE;
382 }
383
384 HRESULT WINAPI
385 GetDefaultRecycleBin(
386 IN LPCWSTR pszVolume OPTIONAL,
387 OUT IRecycleBin **pprb)
388 {
389 IUnknown *pUnk;
390 HRESULT hr;
391
392 TRACE("(%s, %p)\n", debugstr_w(pszVolume), pprb);
393
394 if (!pprb)
395 return E_POINTER;
396
397 if (!pszVolume)
398 hr = RecycleBinGeneric_Constructor(&pUnk);
399 else
400 {
401 /* FIXME: do a better validation! */
402 if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
403 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
404
405 /* For now, only support this type of recycle bins... */
406 hr = RecycleBin5_Constructor(pszVolume, &pUnk);
407 }
408 if (!SUCCEEDED(hr))
409 return hr;
410 hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBin, (void **)pprb);
411 IUnknown_Release(pUnk);
412 return hr;
413 }