Create a branch for network fixes.
[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 EmptyRecycleBinA(
98 IN LPCSTR pszRoot OPTIONAL)
99 {
100 int len;
101 LPWSTR szRootW = NULL;
102 BOOL ret = FALSE;
103
104 TRACE("(%s)\n", debugstr_a(pszRoot));
105
106 if (pszRoot)
107 {
108 len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
109 if (len == 0)
110 goto cleanup;
111 szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
112 if (!szRootW)
113 {
114 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
115 goto cleanup;
116 }
117 if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
118 goto cleanup;
119 }
120
121 ret = EmptyRecycleBinW(szRootW);
122
123 cleanup:
124 HeapFree(GetProcessHeap(), 0, szRootW);
125 return ret;
126 }
127
128 BOOL WINAPI
129 EmptyRecycleBinW(
130 IN LPCWSTR pszRoot OPTIONAL)
131 {
132 IRecycleBin *prb;
133 HRESULT hr;
134
135 TRACE("(%s)\n", debugstr_w(pszRoot));
136
137 hr = GetDefaultRecycleBin(pszRoot, &prb);
138 if (!SUCCEEDED(hr))
139 goto cleanup;
140
141 hr = IRecycleBin_EmptyRecycleBin(prb);
142 IRecycleBin_Release(prb);
143
144 cleanup:
145 if (SUCCEEDED(hr))
146 return TRUE;
147 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
148 SetLastError(HRESULT_CODE(hr));
149 else
150 SetLastError(ERROR_GEN_FAILURE);
151 return FALSE;
152 }
153
154 BOOL WINAPI
155 EnumerateRecycleBinA(
156 IN LPCSTR pszRoot OPTIONAL,
157 IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
158 IN PVOID Context OPTIONAL)
159 {
160 int len;
161 LPWSTR szRootW = NULL;
162 BOOL ret = FALSE;
163
164 TRACE("(%s, %p, %p)\n", debugstr_a(pszRoot), pFnCallback, Context);
165
166 if (pszRoot)
167 {
168 len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
169 if (len == 0)
170 goto cleanup;
171 szRootW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
172 if (!szRootW)
173 {
174 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
175 goto cleanup;
176 }
177 if (MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, szRootW, len) == 0)
178 goto cleanup;
179 }
180
181 ret = EnumerateRecycleBinW(szRootW, pFnCallback, Context);
182
183 cleanup:
184 HeapFree(GetProcessHeap(), 0, szRootW);
185 return ret;
186 }
187
188 BOOL WINAPI
189 EnumerateRecycleBinW(
190 IN LPCWSTR pszRoot OPTIONAL,
191 IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
192 IN PVOID Context OPTIONAL)
193 {
194 IRecycleBin *prb = NULL;
195 IRecycleBinEnumList *prbel = NULL;
196 IRecycleBinFile *prbf;
197 HRESULT hr;
198
199 TRACE("(%s, %p, %p)\n", debugstr_w(pszRoot), pFnCallback, Context);
200
201 hr = GetDefaultRecycleBin(NULL, &prb);
202 if (!SUCCEEDED(hr))
203 goto cleanup;
204
205 hr = IRecycleBin_EnumObjects(prb, &prbel);
206 if (!SUCCEEDED(hr))
207 goto cleanup;
208 while (TRUE)
209 {
210 hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL);
211 if (hr == S_FALSE)
212 {
213 hr = S_OK;
214 goto cleanup;
215 }
216 else if (!SUCCEEDED(hr))
217 goto cleanup;
218 if (!pFnCallback(Context, (HANDLE)prbf))
219 {
220 hr = HRESULT_FROM_WIN32(GetLastError());
221 goto cleanup;
222 }
223 }
224
225 cleanup:
226 if (prb)
227 IRecycleBin_Release(prb);
228 if (prbel)
229 IRecycleBinEnumList_Release(prbel);
230 if (SUCCEEDED(hr))
231 return TRUE;
232 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
233 SetLastError(HRESULT_CODE(hr));
234 else
235 SetLastError(ERROR_GEN_FAILURE);
236 return FALSE;
237 }
238
239 BOOL WINAPI
240 GetDeletedFileDetailsA(
241 IN HANDLE hDeletedFile,
242 IN DWORD BufferSize,
243 IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL,
244 OUT LPDWORD RequiredSize OPTIONAL)
245 {
246 PDELETED_FILE_DETAILS_W FileDetailsW = NULL;
247 DWORD BufferSizeW = 0;
248 BOOL ret = FALSE;
249
250 TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
251
252 if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName))
253 {
254 BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName)
255 + (BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) * sizeof(WCHAR);
256 }
257 if (FileDetails && BufferSizeW)
258 {
259 FileDetailsW = HeapAlloc(GetProcessHeap(), 0, BufferSizeW);
260 if (!FileDetailsW)
261 {
262 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
263 goto cleanup;
264 }
265 }
266
267 ret = GetDeletedFileDetailsW(hDeletedFile, BufferSizeW, FileDetailsW, RequiredSize);
268 if (!ret)
269 goto cleanup;
270
271 if (FileDetails)
272 {
273 CopyMemory(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
274 if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL))
275 goto cleanup;
276 }
277 ret = TRUE;
278
279 cleanup:
280 HeapFree(GetProcessHeap(), 0, FileDetailsW);
281 return ret;
282 }
283
284 BOOL WINAPI
285 GetDeletedFileDetailsW(
286 IN HANDLE hDeletedFile,
287 IN DWORD BufferSize,
288 IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
289 OUT LPDWORD RequiredSize OPTIONAL)
290 {
291 IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
292 HRESULT hr;
293 SIZE_T NameSize, Needed;
294
295 TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
296
297 hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
298 if (!SUCCEEDED(hr))
299 goto cleanup;
300 Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + NameSize;
301 if (RequiredSize)
302 *RequiredSize = (DWORD)Needed;
303 if (Needed > BufferSize)
304 {
305 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
306 goto cleanup;
307 }
308 hr = IRecycleBinFile_GetFileName(rbf, NameSize, FileDetails->FileName, NULL);
309 if (!SUCCEEDED(hr))
310 goto cleanup;
311 hr = IRecycleBinFile_GetLastModificationTime(rbf, &FileDetails->LastModification);
312 if (!SUCCEEDED(hr))
313 goto cleanup;
314 hr = IRecycleBinFile_GetDeletionTime(rbf, &FileDetails->DeletionTime);
315 if (!SUCCEEDED(hr))
316 goto cleanup;
317 hr = IRecycleBinFile_GetFileSize(rbf, &FileDetails->FileSize);
318 if (!SUCCEEDED(hr))
319 goto cleanup;
320 hr = IRecycleBinFile_GetPhysicalFileSize(rbf, &FileDetails->PhysicalFileSize);
321 if (!SUCCEEDED(hr))
322 goto cleanup;
323 hr = IRecycleBinFile_GetAttributes(rbf, &FileDetails->Attributes);
324 if (!SUCCEEDED(hr))
325 goto cleanup;
326
327 cleanup:
328 if (SUCCEEDED(hr))
329 return TRUE;
330 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
331 SetLastError(HRESULT_CODE(hr));
332 else
333 SetLastError(ERROR_GEN_FAILURE);
334 return FALSE;
335 }
336
337 BOOL WINAPI
338 RestoreFile(
339 IN HANDLE hDeletedFile)
340 {
341 IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
342 HRESULT hr;
343
344 TRACE("(%p)\n", hDeletedFile);
345
346 hr = IRecycleBinFile_Restore(rbf);
347 if (SUCCEEDED(hr))
348 return TRUE;
349 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
350 SetLastError(HRESULT_CODE(hr));
351 else
352 SetLastError(ERROR_GEN_FAILURE);
353 return FALSE;
354 }
355
356 HRESULT WINAPI
357 GetDefaultRecycleBin(
358 IN LPCWSTR pszVolume OPTIONAL,
359 OUT IRecycleBin **pprb)
360 {
361 IUnknown *pUnk;
362 HRESULT hr;
363
364 TRACE("(%s, %p)\n", debugstr_w(pszVolume), pprb);
365
366 if (!pprb)
367 return E_POINTER;
368
369 if (!pszVolume)
370 hr = RecycleBinGeneric_Constructor(&pUnk);
371 else
372 {
373 /* FIXME: do a better validation! */
374 if (wcslen(pszVolume) != 3 || pszVolume[1] != ':' || pszVolume[2] != '\\')
375 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
376
377 /* For now, only support this type of recycle bins... */
378 hr = RecycleBin5_Constructor(pszVolume, &pUnk);
379 }
380 if (!SUCCEEDED(hr))
381 return hr;
382 hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBin, (void **)pprb);
383 IUnknown_Release(pUnk);
384 return hr;
385 }