- Move NCI generated files to arch-specific directories
[reactos.git] / reactos / 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/openclose.c
5 * PURPOSE: Public interface
6 * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 #include "recyclebin_private.h"
10
11 typedef struct _ENUMERATE_RECYCLE_BIN_CONTEXT
12 {
13 PRECYCLE_BIN bin;
14 PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback;
15 PVOID Context;
16 } ENUMERATE_RECYCLE_BIN_CONTEXT, *PENUMERATE_RECYCLE_BIN_CONTEXT;
17
18 BOOL WINAPI
19 CloseRecycleBinHandle(
20 IN HANDLE hDeletedFile)
21 {
22 BOOL ret = FALSE;
23
24 if (!IntCheckDeletedFileHandle(hDeletedFile))
25 SetLastError(ERROR_INVALID_HANDLE);
26 else
27 {
28 PDELETED_FILE_HANDLE file = (PDELETED_FILE_HANDLE)hDeletedFile;
29 ret = DereferenceHandle(&file->refCount);
30 }
31
32 return ret;
33 }
34
35 BOOL WINAPI
36 DeleteFileToRecycleBinA(
37 IN LPCSTR FileName)
38 {
39 int len;
40 LPWSTR FileNameW = NULL;
41 BOOL ret = FALSE;
42
43 /* Check parameters */
44 if (FileName == NULL)
45 {
46 SetLastError(ERROR_INVALID_PARAMETER);
47 goto cleanup;
48 }
49
50 len = MultiByteToWideChar(CP_ACP, 0, FileName, -1, NULL, 0);
51 if (len == 0)
52 goto cleanup;
53 FileNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
54 if (!FileNameW)
55 {
56 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
57 goto cleanup;
58 }
59 if (MultiByteToWideChar(CP_ACP, 0, FileName, -1, FileNameW, len) == 0)
60 goto cleanup;
61
62 ret = DeleteFileToRecycleBinW(FileNameW);
63
64 cleanup:
65 HeapFree(GetProcessHeap(), 0, FileNameW);
66 return ret;
67 }
68
69 BOOL WINAPI
70 DeleteFileToRecycleBinW(
71 IN LPCWSTR FileName)
72 {
73 LPWSTR FullFileName = NULL;
74 DWORD dwBufferLength = 0;
75 LPWSTR lpFilePart;
76 DWORD len;
77 PRECYCLE_BIN bin = NULL;
78 BOOL ret = FALSE;
79
80 /* Check parameters */
81 if (FileName == NULL)
82 {
83 SetLastError(ERROR_INVALID_PARAMETER);
84 goto cleanup;
85 }
86
87 /* Get full file name */
88 while (TRUE)
89 {
90 len = GetFullPathNameW(FileName, dwBufferLength, FullFileName, &lpFilePart);
91 if (len == 0)
92 goto cleanup;
93 else if (len < dwBufferLength)
94 break;
95 HeapFree(GetProcessHeap(), 0, FullFileName);
96 dwBufferLength = len;
97 FullFileName = HeapAlloc(GetProcessHeap(), 0, dwBufferLength * sizeof(WCHAR));
98 if (!FullFileName)
99 {
100 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
101 goto cleanup;
102 }
103 }
104
105 if (!lpFilePart || dwBufferLength < 2 || FullFileName[1] != ':')
106 {
107 /* Only a directory name, or not a local file */
108 SetLastError(ERROR_INVALID_NAME);
109 }
110
111 /* Open recycle bin */
112 bin = IntReferenceRecycleBin(FullFileName[0]);
113 if (!bin)
114 goto cleanup;
115
116 if (bin->Callbacks.DeleteFile)
117 ret = bin->Callbacks.DeleteFile(bin, FullFileName, lpFilePart);
118 else
119 SetLastError(ERROR_NOT_SUPPORTED);
120
121 cleanup:
122 HeapFree(GetProcessHeap(), 0, FullFileName);
123 if (bin)
124 DereferenceHandle(&bin->refCount);
125 return ret;
126 }
127
128 BOOL WINAPI
129 EmptyRecycleBinA(
130 IN CHAR driveLetter)
131 {
132 return EmptyRecycleBinW((WCHAR)driveLetter);
133 }
134
135 BOOL WINAPI
136 EmptyRecycleBinW(
137 IN WCHAR driveLetter)
138 {
139 PRECYCLE_BIN bin = NULL;
140 BOOL ret = FALSE;
141
142 /* Open recycle bin */
143 bin = IntReferenceRecycleBin(driveLetter);
144 if (!bin)
145 goto cleanup;
146
147 if (bin->Callbacks.EmptyRecycleBin)
148 ret = bin->Callbacks.EmptyRecycleBin(&bin);
149 else
150 SetLastError(ERROR_NOT_SUPPORTED);
151
152 cleanup:
153 if (bin)
154 DereferenceHandle(&bin->refCount);
155 return ret;
156 }
157
158 BOOL WINAPI
159 EnumerateRecycleBinA(
160 IN CHAR driveLetter,
161 IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
162 IN PVOID Context OPTIONAL)
163 {
164 return EnumerateRecycleBinW((WCHAR)driveLetter, pFnCallback, Context);
165 }
166
167 static BOOL
168 IntCloseDeletedFileHandle(
169 IN PREFCOUNT_DATA pData)
170 {
171 PDELETED_FILE_HANDLE file;
172
173 file = CONTAINING_RECORD(pData, DELETED_FILE_HANDLE, refCount);
174 if (!DereferenceHandle(&file->bin->refCount))
175 return FALSE;
176
177 file->magic = 0;
178 HeapFree(GetProcessHeap(), 0, file);
179 return TRUE;
180 }
181
182 static BOOL
183 IntEnumerateRecycleBinCallback(
184 IN PVOID Context,
185 IN HANDLE hDeletedFile)
186 {
187 PENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext = (PENUMERATE_RECYCLE_BIN_CONTEXT)Context;
188 PDELETED_FILE_HANDLE DeletedFileHandle = NULL;
189 BOOL ret = FALSE;
190
191 DeletedFileHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(DELETED_FILE_HANDLE));
192 if (!DeletedFileHandle)
193 {
194 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
195 goto cleanup;
196 }
197
198 ReferenceHandle(&CallbackContext->bin->refCount);
199 InitializeHandle(&DeletedFileHandle->refCount, IntCloseDeletedFileHandle);
200 DeletedFileHandle->magic = DELETEDFILE_MAGIC;
201 DeletedFileHandle->bin = CallbackContext->bin;
202 DeletedFileHandle->hDeletedFile = hDeletedFile;
203
204 ret = CallbackContext->pFnCallback(CallbackContext->Context, DeletedFileHandle);
205
206 cleanup:
207 if (!ret)
208 {
209 if (DeletedFileHandle)
210 DereferenceHandle(&DeletedFileHandle->refCount);
211 }
212 return ret;
213 }
214
215 BOOL WINAPI
216 EnumerateRecycleBinW(
217 IN WCHAR driveLetter,
218 IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback,
219 IN PVOID Context OPTIONAL)
220 {
221 PRECYCLE_BIN bin = NULL;
222 BOOL ret = FALSE;
223
224 /* Check parameters */
225 if (pFnCallback == NULL)
226 {
227 SetLastError(ERROR_INVALID_PARAMETER);
228 goto cleanup;
229 }
230
231 /* Open recycle bin */
232 bin = IntReferenceRecycleBin(driveLetter);
233 if (!bin)
234 goto cleanup;
235
236 if (bin->Callbacks.EnumerateFiles)
237 {
238 ENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext;
239
240 CallbackContext.bin = bin;
241 CallbackContext.pFnCallback = pFnCallback;
242 CallbackContext.Context = Context;
243
244 ret = bin->Callbacks.EnumerateFiles(bin, IntEnumerateRecycleBinCallback, &CallbackContext);
245 }
246 else
247 SetLastError(ERROR_NOT_SUPPORTED);
248
249 cleanup:
250 if (bin)
251 DereferenceHandle(&bin->refCount);
252 return ret;
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 if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName))
267 {
268 BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName)
269 + (BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) * sizeof(WCHAR);
270 }
271 if (FileDetails && BufferSizeW)
272 {
273 FileDetailsW = HeapAlloc(GetProcessHeap(), 0, BufferSizeW);
274 if (!FileDetailsW)
275 {
276 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
277 goto cleanup;
278 }
279 }
280
281 ret = GetDeletedFileDetailsW(hDeletedFile, BufferSizeW, FileDetailsW, RequiredSize);
282 if (!ret)
283 goto cleanup;
284
285 if (FileDetails)
286 {
287 memcpy(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName));
288 if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL))
289 goto cleanup;
290 }
291 ret = TRUE;
292
293 cleanup:
294 HeapFree(GetProcessHeap(), 0, FileDetailsW);
295 return ret;
296 }
297
298 BOOL WINAPI
299 GetDeletedFileDetailsW(
300 IN HANDLE hDeletedFile,
301 IN DWORD BufferSize,
302 IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL,
303 OUT LPDWORD RequiredSize OPTIONAL)
304 {
305 BOOL ret = FALSE;
306
307 if (!IntCheckDeletedFileHandle(hDeletedFile))
308 SetLastError(ERROR_INVALID_HANDLE);
309 else
310 {
311 PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile;
312 if (DeletedFile->bin->Callbacks.GetDetails)
313 ret = DeletedFile->bin->Callbacks.GetDetails(DeletedFile->bin, DeletedFile->hDeletedFile, BufferSize, FileDetails, RequiredSize);
314 else
315 SetLastError(ERROR_NOT_SUPPORTED);
316 }
317
318 return ret;
319 }
320
321 BOOL WINAPI
322 RestoreFile(
323 IN HANDLE hDeletedFile)
324 {
325 BOOL ret = FALSE;
326
327 if (!IntCheckDeletedFileHandle(hDeletedFile))
328 SetLastError(ERROR_INVALID_HANDLE);
329 else
330 {
331 PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile;
332 if (DeletedFile->bin->Callbacks.RestoreFile)
333 ret = DeletedFile->bin->Callbacks.RestoreFile(DeletedFile->bin, DeletedFile->hDeletedFile);
334 else
335 SetLastError(ERROR_NOT_SUPPORTED);
336 }
337
338 return ret;
339 }