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