Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenrecyclebin_v5.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: Recycle bin management 00003 * LICENSE: GPL v2 - See COPYING in the top level directory 00004 * FILE: lib/recyclebin/recyclebin_v5.c 00005 * PURPOSE: Deals with recycle bins of Windows 2000/XP/2003 00006 * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org) 00007 */ 00008 00009 #define COBJMACROS 00010 #include "recyclebin_v5.h" 00011 #include <stdio.h> 00012 00013 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin); 00014 00015 static BOOL 00016 IntDeleteRecursive( 00017 IN LPCWSTR FullName) 00018 { 00019 DWORD RemovableAttributes = FILE_ATTRIBUTE_READONLY; 00020 WIN32_FIND_DATAW FindData; 00021 HANDLE hSearch = INVALID_HANDLE_VALUE; 00022 LPWSTR FullPath = NULL, pFilePart; 00023 DWORD FileAttributes; 00024 SIZE_T dwLength; 00025 BOOL ret = FALSE; 00026 00027 FileAttributes = GetFileAttributesW(FullName); 00028 if (FileAttributes == INVALID_FILE_ATTRIBUTES) 00029 { 00030 if (GetLastError() == ERROR_FILE_NOT_FOUND) 00031 ret = TRUE; 00032 goto cleanup; 00033 } 00034 if (FileAttributes & RemovableAttributes) 00035 { 00036 if (!SetFileAttributesW(FullName, FileAttributes & ~RemovableAttributes)) 00037 goto cleanup; 00038 } 00039 if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00040 { 00041 /* Prepare file specification */ 00042 dwLength = wcslen(FullName); 00043 FullPath = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1 + MAX_PATH + 1) * sizeof(WCHAR)); 00044 if (!FullPath) 00045 { 00046 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00047 goto cleanup; 00048 } 00049 wcscpy(FullPath, FullName); 00050 if (FullPath[dwLength - 1] != '\\') 00051 { 00052 FullPath[dwLength] = '\\'; 00053 dwLength++; 00054 } 00055 pFilePart = &FullPath[dwLength]; 00056 wcscpy(pFilePart, L"*"); 00057 00058 /* Enumerate contents, and delete it */ 00059 hSearch = FindFirstFileW(FullPath, &FindData); 00060 if (hSearch == INVALID_HANDLE_VALUE) 00061 goto cleanup; 00062 do 00063 { 00064 if (!(FindData.cFileName[0] == '.' && 00065 (FindData.cFileName[1] == '\0' || (FindData.cFileName[1] == '.' && FindData.cFileName[2] == '\0')))) 00066 { 00067 wcscpy(pFilePart, FindData.cFileName); 00068 if (!IntDeleteRecursive(FullPath)) 00069 { 00070 FindClose(hSearch); 00071 goto cleanup; 00072 } 00073 } 00074 } 00075 while (FindNextFileW(hSearch, &FindData)); 00076 FindClose(hSearch); 00077 if (GetLastError() != ERROR_NO_MORE_FILES) 00078 goto cleanup; 00079 00080 /* Remove (now empty) directory */ 00081 if (!RemoveDirectoryW(FullName)) 00082 goto cleanup; 00083 } 00084 else 00085 { 00086 if (!DeleteFileW(FullName)) 00087 goto cleanup; 00088 } 00089 ret = TRUE; 00090 00091 cleanup: 00092 HeapFree(GetProcessHeap(), 0, FullPath); 00093 return ret; 00094 } 00095 00096 struct RecycleBin5 00097 { 00098 ULONG ref; 00099 IRecycleBin5 recycleBinImpl; 00100 HANDLE hInfo; 00101 HANDLE hInfoMapped; 00102 00103 DWORD EnumeratorCount; 00104 00105 LPWSTR VolumePath; 00106 WCHAR Folder[ANY_SIZE]; /* [drive]:\[RECYCLE_BIN_DIRECTORY]\{SID} */ 00107 }; 00108 00109 static HRESULT STDMETHODCALLTYPE 00110 RecycleBin5_RecycleBin5_QueryInterface( 00111 IRecycleBin5 *This, 00112 REFIID riid, 00113 void **ppvObject) 00114 { 00115 struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); 00116 00117 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject); 00118 00119 if (!ppvObject) 00120 return E_POINTER; 00121 00122 if (IsEqualIID(riid, &IID_IUnknown)) 00123 *ppvObject = &s->recycleBinImpl; 00124 else if (IsEqualIID(riid, &IID_IRecycleBin)) 00125 *ppvObject = &s->recycleBinImpl; 00126 else if (IsEqualIID(riid, &IID_IRecycleBin5)) 00127 *ppvObject = &s->recycleBinImpl; 00128 else 00129 { 00130 *ppvObject = NULL; 00131 return E_NOINTERFACE; 00132 } 00133 00134 IUnknown_AddRef(This); 00135 return S_OK; 00136 } 00137 00138 static ULONG STDMETHODCALLTYPE 00139 RecycleBin5_RecycleBin5_AddRef( 00140 IRecycleBin5 *This) 00141 { 00142 struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); 00143 ULONG refCount = InterlockedIncrement((PLONG)&s->ref); 00144 TRACE("(%p)\n", This); 00145 return refCount; 00146 } 00147 00148 static VOID 00149 RecycleBin5_Destructor( 00150 struct RecycleBin5 *s) 00151 { 00152 TRACE("(%p)\n", s); 00153 00154 if (s->hInfo && s->hInfo != INVALID_HANDLE_VALUE) 00155 CloseHandle(s->hInfo); 00156 if (s->hInfoMapped) 00157 CloseHandle(s->hInfoMapped); 00158 CoTaskMemFree(s); 00159 } 00160 00161 static ULONG STDMETHODCALLTYPE 00162 RecycleBin5_RecycleBin5_Release( 00163 IRecycleBin5 *This) 00164 { 00165 struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); 00166 ULONG refCount; 00167 00168 TRACE("(%p)\n", This); 00169 00170 refCount = InterlockedDecrement((PLONG)&s->ref); 00171 00172 if (refCount == 0) 00173 RecycleBin5_Destructor(s); 00174 00175 return refCount; 00176 } 00177 00178 static HRESULT STDMETHODCALLTYPE 00179 RecycleBin5_RecycleBin5_DeleteFile( 00180 IN IRecycleBin5 *This, 00181 IN LPCWSTR szFileName) 00182 { 00183 struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); 00184 LPWSTR szFullName = NULL; 00185 DWORD dwBufferLength = 0; 00186 LPWSTR lpFilePart; 00187 LPCWSTR Extension; 00188 WCHAR DeletedFileName[MAX_PATH]; 00189 DWORD len; 00190 HANDLE hFile = INVALID_HANDLE_VALUE; 00191 PINFO2_HEADER pHeader = NULL; 00192 PDELETED_FILE_RECORD pDeletedFile; 00193 ULARGE_INTEGER FileSize; 00194 DWORD dwAttributes, dwEntries; 00195 SYSTEMTIME SystemTime; 00196 DWORD ClusterSize, BytesPerSector, SectorsPerCluster; 00197 HRESULT hr; 00198 00199 TRACE("(%p, %s)\n", This, debugstr_w(szFileName)); 00200 00201 if (s->EnumeratorCount != 0) 00202 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION); 00203 00204 /* Get full file name */ 00205 while (TRUE) 00206 { 00207 len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, &lpFilePart); 00208 if (len == 0) 00209 { 00210 if (szFullName) 00211 CoTaskMemFree(szFullName); 00212 return HRESULT_FROM_WIN32(GetLastError()); 00213 } 00214 else if (len < dwBufferLength) 00215 break; 00216 if (szFullName) 00217 CoTaskMemFree(szFullName); 00218 dwBufferLength = len; 00219 szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR)); 00220 if (!szFullName) 00221 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); 00222 } 00223 00224 /* Check if file exists */ 00225 dwAttributes = GetFileAttributesW(szFullName); 00226 if (dwAttributes == INVALID_FILE_ATTRIBUTES) 00227 return HRESULT_FROM_WIN32(GetLastError()); 00228 00229 if (dwBufferLength < 2 || szFullName[1] != ':') 00230 { 00231 /* Not a local file */ 00232 CoTaskMemFree(szFullName); 00233 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME); 00234 } 00235 00236 hFile = CreateFileW(szFullName, 0, 0, NULL, OPEN_EXISTING, 0, NULL); 00237 if (hFile == INVALID_HANDLE_VALUE) 00238 { 00239 hr = HRESULT_FROM_WIN32(GetLastError()); 00240 goto cleanup; 00241 } 00242 00243 /* Increase INFO2 file size */ 00244 CloseHandle(s->hInfoMapped); 00245 SetFilePointer(s->hInfo, sizeof(DELETED_FILE_RECORD), NULL, FILE_END); 00246 SetEndOfFile(s->hInfo); 00247 s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); 00248 if (!s->hInfoMapped) 00249 { 00250 hr = HRESULT_FROM_WIN32(GetLastError()); 00251 goto cleanup; 00252 } 00253 00254 /* Open INFO2 file */ 00255 pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); 00256 if (!pHeader) 00257 { 00258 hr = HRESULT_FROM_WIN32(GetLastError()); 00259 goto cleanup; 00260 } 00261 00262 /* Get number of entries */ 00263 FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart); 00264 if (FileSize.u.LowPart < sizeof(INFO2_HEADER)) 00265 { 00266 UnmapViewOfFile(pHeader); 00267 return HRESULT_FROM_WIN32(GetLastError()); 00268 } 00269 dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)) - 1; 00270 pDeletedFile = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries; 00271 00272 /* Get file size */ 00273 #if 0 00274 if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&FileSize)) 00275 { 00276 hr = HRESULT_FROM_WIN32(GetLastError()); 00277 goto cleanup; 00278 } 00279 #else 00280 FileSize.u.LowPart = GetFileSize(hFile, &FileSize.u.HighPart); 00281 if (FileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) 00282 { 00283 hr = HRESULT_FROM_WIN32(GetLastError()); 00284 goto cleanup; 00285 } 00286 #endif 00287 /* Check if file size is > 4Gb */ 00288 if (FileSize.u.HighPart != 0) 00289 { 00290 /* Yes, this recyclebin can't support this file */ 00291 hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); 00292 goto cleanup; 00293 } 00294 pHeader->dwTotalLogicalSize += FileSize.u.LowPart; 00295 00296 /* Generate new name */ 00297 Extension = wcsrchr(szFullName, '.'); 00298 ZeroMemory(pDeletedFile, sizeof(DELETED_FILE_RECORD)); 00299 if (dwEntries == 0) 00300 pDeletedFile->dwRecordUniqueId = 0; 00301 else 00302 { 00303 PDELETED_FILE_RECORD pLastDeleted = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries - 1; 00304 pDeletedFile->dwRecordUniqueId = pLastDeleted->dwRecordUniqueId + 1; 00305 } 00306 pDeletedFile->dwDriveNumber = tolower(szFullName[0]) - 'a'; 00307 _snwprintf(DeletedFileName, MAX_PATH, L"%s\\D%c%lu%s", s->Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension); 00308 00309 /* Get cluster size */ 00310 if (!GetDiskFreeSpaceW(s->VolumePath, &SectorsPerCluster, &BytesPerSector, NULL, NULL)) 00311 { 00312 hr = HRESULT_FROM_WIN32(GetLastError()); 00313 goto cleanup; 00314 } 00315 ClusterSize = BytesPerSector * SectorsPerCluster; 00316 00317 /* Get current time */ 00318 GetSystemTime(&SystemTime); 00319 if (!SystemTimeToFileTime(&SystemTime, &pDeletedFile->DeletionTime)) 00320 { 00321 hr = HRESULT_FROM_WIN32(GetLastError()); 00322 goto cleanup; 00323 } 00324 pDeletedFile->dwPhysicalFileSize = ROUND_UP(FileSize.u.LowPart, ClusterSize); 00325 00326 /* Set name */ 00327 wcscpy(pDeletedFile->FileNameW, szFullName); 00328 if (WideCharToMultiByte(CP_ACP, 0, pDeletedFile->FileNameW, -1, pDeletedFile->FileNameA, MAX_PATH, NULL, NULL) == 0) 00329 { 00330 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME); 00331 SetLastError(ERROR_INVALID_NAME); 00332 goto cleanup; 00333 } 00334 00335 /* Move file */ 00336 if (MoveFileW(szFullName, DeletedFileName)) 00337 hr = S_OK; 00338 else 00339 hr = HRESULT_FROM_WIN32(GetLastError()); 00340 00341 cleanup: 00342 if (pHeader) 00343 UnmapViewOfFile(pHeader); 00344 if (hFile != INVALID_HANDLE_VALUE) 00345 CloseHandle(hFile); 00346 CoTaskMemFree(szFullName); 00347 return hr; 00348 } 00349 00350 static HRESULT STDMETHODCALLTYPE 00351 RecycleBin5_RecycleBin5_EmptyRecycleBin( 00352 IN IRecycleBin5 *This) 00353 { 00354 IRecycleBinEnumList *prbel; 00355 IRecycleBinFile *prbf; 00356 HRESULT hr; 00357 00358 TRACE("(%p)\n", This); 00359 00360 while (TRUE) 00361 { 00362 hr = IRecycleBin5_EnumObjects(This, &prbel); 00363 if (!SUCCEEDED(hr)) 00364 return hr; 00365 hr = IRecycleBinEnumList_Next(prbel, 1, &prbf, NULL); 00366 IRecycleBinEnumList_Release(prbel); 00367 if (hr == S_FALSE) 00368 return S_OK; 00369 hr = IRecycleBinFile_Delete(prbf); 00370 IRecycleBinFile_Release(prbf); 00371 if (!SUCCEEDED(hr)) 00372 return hr; 00373 } 00374 } 00375 00376 static HRESULT STDMETHODCALLTYPE 00377 RecycleBin5_RecycleBin5_EnumObjects( 00378 IN IRecycleBin5 *This, 00379 OUT IRecycleBinEnumList **ppEnumList) 00380 { 00381 struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); 00382 IRecycleBinEnumList *prbel; 00383 HRESULT hr; 00384 IUnknown *pUnk; 00385 00386 TRACE("(%p, %p)\n", This, ppEnumList); 00387 00388 hr = RecycleBin5Enum_Constructor(This, s->hInfo, s->hInfoMapped, s->Folder, &pUnk); 00389 if (!SUCCEEDED(hr)) 00390 return hr; 00391 00392 hr = IUnknown_QueryInterface(pUnk, &IID_IRecycleBinEnumList, (void **)&prbel); 00393 if (SUCCEEDED(hr)) 00394 { 00395 s->EnumeratorCount++; 00396 *ppEnumList = prbel; 00397 } 00398 IUnknown_Release(pUnk); 00399 return hr; 00400 } 00401 00402 static HRESULT STDMETHODCALLTYPE 00403 RecycleBin5_RecycleBin5_Delete( 00404 IN IRecycleBin5 *This, 00405 IN LPCWSTR pDeletedFileName, 00406 IN DELETED_FILE_RECORD *pDeletedFile) 00407 { 00408 struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); 00409 ULARGE_INTEGER FileSize; 00410 PINFO2_HEADER pHeader; 00411 DELETED_FILE_RECORD *pRecord, *pLast; 00412 DWORD dwEntries, i; 00413 00414 TRACE("(%p, %s, %p)\n", This, debugstr_w(pDeletedFileName), pDeletedFile); 00415 00416 if (s->EnumeratorCount != 0) 00417 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION); 00418 00419 pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); 00420 if (!pHeader) 00421 return HRESULT_FROM_WIN32(GetLastError()); 00422 00423 FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart); 00424 if (FileSize.u.LowPart == 0) 00425 { 00426 UnmapViewOfFile(pHeader); 00427 return HRESULT_FROM_WIN32(GetLastError()); 00428 } 00429 dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)); 00430 00431 pRecord = (DELETED_FILE_RECORD *)(pHeader + 1); 00432 for (i = 0; i < dwEntries; i++) 00433 { 00434 if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId) 00435 { 00436 /* Delete file */ 00437 if (!IntDeleteRecursive(pDeletedFileName)) 00438 { 00439 UnmapViewOfFile(pHeader); 00440 return HRESULT_FROM_WIN32(GetLastError()); 00441 } 00442 00443 /* Clear last entry in the file */ 00444 MoveMemory(pRecord, pRecord + 1, (dwEntries - i - 1) * sizeof(DELETED_FILE_RECORD)); 00445 pLast = pRecord + (dwEntries - i - 1); 00446 ZeroMemory(pLast, sizeof(DELETED_FILE_RECORD)); 00447 UnmapViewOfFile(pHeader); 00448 00449 /* Resize file */ 00450 CloseHandle(s->hInfoMapped); 00451 SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END); 00452 SetEndOfFile(s->hInfo); 00453 s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); 00454 if (!s->hInfoMapped) 00455 return HRESULT_FROM_WIN32(GetLastError()); 00456 return S_OK; 00457 } 00458 pRecord++; 00459 } 00460 UnmapViewOfFile(pHeader); 00461 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 00462 } 00463 00464 static HRESULT STDMETHODCALLTYPE 00465 RecycleBin5_RecycleBin5_Restore( 00466 IN IRecycleBin5 *This, 00467 IN LPCWSTR pDeletedFileName, 00468 IN DELETED_FILE_RECORD *pDeletedFile) 00469 { 00470 struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); 00471 ULARGE_INTEGER FileSize; 00472 PINFO2_HEADER pHeader; 00473 DELETED_FILE_RECORD *pRecord, *pLast; 00474 DWORD dwEntries, i; 00475 SHFILEOPSTRUCTW op; 00476 00477 TRACE("(%p, %s, %p)\n", This, debugstr_w(pDeletedFileName), pDeletedFile); 00478 00479 if (s->EnumeratorCount != 0) 00480 return HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION); 00481 00482 pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); 00483 if (!pHeader) 00484 return HRESULT_FROM_WIN32(GetLastError()); 00485 00486 FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart); 00487 if (FileSize.u.LowPart == 0) 00488 { 00489 UnmapViewOfFile(pHeader); 00490 return HRESULT_FROM_WIN32(GetLastError()); 00491 } 00492 dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)); 00493 00494 pRecord = (DELETED_FILE_RECORD *)(pHeader + 1); 00495 for (i = 0; i < dwEntries; i++) 00496 { 00497 if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId) 00498 { 00499 /* Restore file */ 00500 ZeroMemory(&op, sizeof(op)); 00501 op.wFunc = FO_COPY; 00502 op.pFrom = pDeletedFileName; 00503 op.pTo = pDeletedFile->FileNameW; 00504 00505 if (!SHFileOperationW(&op)) 00506 { 00507 UnmapViewOfFile(pHeader); 00508 return HRESULT_FROM_WIN32(GetLastError()); 00509 } 00510 00511 /* Clear last entry in the file */ 00512 MoveMemory(pRecord, pRecord + 1, (dwEntries - i - 1) * sizeof(DELETED_FILE_RECORD)); 00513 pLast = pRecord + (dwEntries - i - 1); 00514 ZeroMemory(pLast, sizeof(DELETED_FILE_RECORD)); 00515 UnmapViewOfFile(pHeader); 00516 00517 /* Resize file */ 00518 CloseHandle(s->hInfoMapped); 00519 SetFilePointer(s->hInfo, -(LONG)sizeof(DELETED_FILE_RECORD), NULL, FILE_END); 00520 SetEndOfFile(s->hInfo); 00521 s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); 00522 if (!s->hInfoMapped) 00523 return HRESULT_FROM_WIN32(GetLastError()); 00524 return S_OK; 00525 } 00526 pRecord++; 00527 } 00528 00529 UnmapViewOfFile(pHeader); 00530 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 00531 } 00532 00533 static HRESULT STDMETHODCALLTYPE 00534 RecycleBin5_RecycleBin5_OnClosing( 00535 IN IRecycleBin5 *This, 00536 IN IRecycleBinEnumList *prbel) 00537 { 00538 struct RecycleBin5 *s = CONTAINING_RECORD(This, struct RecycleBin5, recycleBinImpl); 00539 TRACE("(%p, %p)\n", This, prbel); 00540 s->EnumeratorCount--; 00541 return S_OK; 00542 } 00543 00544 CONST_VTBL struct IRecycleBin5Vtbl RecycleBin5Vtbl = 00545 { 00546 RecycleBin5_RecycleBin5_QueryInterface, 00547 RecycleBin5_RecycleBin5_AddRef, 00548 RecycleBin5_RecycleBin5_Release, 00549 RecycleBin5_RecycleBin5_DeleteFile, 00550 RecycleBin5_RecycleBin5_EmptyRecycleBin, 00551 RecycleBin5_RecycleBin5_EnumObjects, 00552 RecycleBin5_RecycleBin5_Delete, 00553 RecycleBin5_RecycleBin5_Restore, 00554 RecycleBin5_RecycleBin5_OnClosing, 00555 }; 00556 00557 static HRESULT 00558 RecycleBin5_Create( 00559 IN LPCWSTR Folder, 00560 IN PSID OwnerSid OPTIONAL) 00561 { 00562 LPWSTR BufferName = NULL; 00563 LPWSTR Separator; /* Pointer into BufferName buffer */ 00564 LPWSTR FileName; /* Pointer into BufferName buffer */ 00565 LPCSTR DesktopIniContents = "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n"; 00566 INFO2_HEADER Info2Contents[] = { { 5, 0, 0, 0x320, 0 } }; 00567 DWORD BytesToWrite, BytesWritten, Needed; 00568 HANDLE hFile = INVALID_HANDLE_VALUE; 00569 HRESULT hr; 00570 00571 Needed = (wcslen(Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR); 00572 BufferName = HeapAlloc(GetProcessHeap(), 0, Needed); 00573 if (!BufferName) 00574 { 00575 hr = ERROR_NOT_ENOUGH_MEMORY; 00576 goto cleanup; 00577 } 00578 00579 wcscpy(BufferName, Folder); 00580 Separator = wcsstr(&BufferName[3], L"\\"); 00581 if (Separator) 00582 *Separator = UNICODE_NULL; 00583 if (!CreateDirectoryW(BufferName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) 00584 { 00585 hr = HRESULT_FROM_WIN32(GetLastError()); 00586 goto cleanup; 00587 } 00588 SetFileAttributesW(BufferName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); 00589 if (Separator) 00590 { 00591 *Separator = L'\\'; 00592 if (!CreateDirectoryW(BufferName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) 00593 { 00594 hr = HRESULT_FROM_WIN32(GetLastError()); 00595 goto cleanup; 00596 } 00597 } 00598 00599 if (OwnerSid) 00600 { 00601 //DWORD rc; 00602 00603 /* Add ACL to allow only user/SYSTEM to open it */ 00604 /* FIXME: rc = SetNamedSecurityInfo( 00605 BufferName, 00606 SE_FILE_OBJECT, 00607 ???, 00608 OwnerSid, 00609 NULL, 00610 ???, 00611 ???); 00612 if (rc != ERROR_SUCCESS) 00613 { 00614 hr = HRESULT_FROM_WIN32(rc); 00615 goto cleanup; 00616 } 00617 */ 00618 } 00619 00620 wcscat(BufferName, L"\\"); 00621 FileName = &BufferName[wcslen(BufferName)]; 00622 00623 /* Create desktop.ini */ 00624 wcscpy(FileName, L"desktop.ini"); 00625 hFile = CreateFileW(BufferName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL); 00626 if (hFile == INVALID_HANDLE_VALUE) 00627 { 00628 hr = HRESULT_FROM_WIN32(GetLastError()); 00629 goto cleanup; 00630 } 00631 BytesToWrite = strlen(DesktopIniContents); 00632 if (!WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten, NULL)) 00633 { 00634 hr = HRESULT_FROM_WIN32(GetLastError()); 00635 goto cleanup; 00636 } 00637 if (BytesWritten != BytesToWrite) 00638 { 00639 hr = E_FAIL; 00640 goto cleanup; 00641 } 00642 CloseHandle(hFile); 00643 hFile = INVALID_HANDLE_VALUE; 00644 00645 /* Create empty INFO2 file */ 00646 wcscpy(FileName, RECYCLE_BIN_FILE_NAME); 00647 hFile = CreateFileW(BufferName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); 00648 if (hFile == INVALID_HANDLE_VALUE) 00649 { 00650 hr = HRESULT_FROM_WIN32(GetLastError()); 00651 goto cleanup; 00652 } 00653 BytesToWrite = sizeof(Info2Contents); 00654 if (!WriteFile(hFile, Info2Contents, (DWORD)BytesToWrite, &BytesWritten, NULL)) 00655 { 00656 hr = HRESULT_FROM_WIN32(GetLastError()); 00657 goto cleanup; 00658 } 00659 if (BytesWritten == BytesToWrite) 00660 hr = S_OK; 00661 else 00662 hr = E_FAIL; 00663 00664 cleanup: 00665 HeapFree(GetProcessHeap(), 0, BufferName); 00666 if (hFile != INVALID_HANDLE_VALUE) 00667 CloseHandle(hFile); 00668 return hr; 00669 } 00670 00671 HRESULT RecycleBin5_Constructor(IN LPCWSTR VolumePath, OUT IUnknown **ppUnknown) 00672 { 00673 struct RecycleBin5 *s = NULL; 00674 DWORD FileSystemFlags; 00675 LPCWSTR RecycleBinDirectory; 00676 HANDLE tokenHandle = INVALID_HANDLE_VALUE; 00677 PTOKEN_USER TokenUserInfo = NULL; 00678 LPWSTR StringSid = NULL, p; 00679 DWORD Needed, DirectoryLength; 00680 INT len; 00681 HRESULT hr; 00682 00683 if (!ppUnknown) 00684 return E_POINTER; 00685 00686 /* Get information about file system */ 00687 if (!GetVolumeInformationW( 00688 VolumePath, 00689 NULL, 00690 0, 00691 NULL, 00692 NULL, 00693 &FileSystemFlags, 00694 NULL, 00695 0)) 00696 { 00697 hr = HRESULT_FROM_WIN32(GetLastError()); 00698 goto cleanup; 00699 } 00700 if (!(FileSystemFlags & FILE_PERSISTENT_ACLS)) 00701 RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL; 00702 else 00703 { 00704 RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL; 00705 00706 /* Get user SID */ 00707 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle)) 00708 { 00709 hr = HRESULT_FROM_WIN32(GetLastError()); 00710 goto cleanup; 00711 } 00712 if (GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &Needed)) 00713 { 00714 hr = E_FAIL; 00715 goto cleanup; 00716 } 00717 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 00718 { 00719 hr = HRESULT_FROM_WIN32(GetLastError()); 00720 goto cleanup; 00721 } 00722 TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed); 00723 if (!TokenUserInfo) 00724 { 00725 hr = E_OUTOFMEMORY; 00726 goto cleanup; 00727 } 00728 if (!GetTokenInformation(tokenHandle, TokenUser, TokenUserInfo, (DWORD)Needed, &Needed)) 00729 { 00730 hr = HRESULT_FROM_WIN32(GetLastError()); 00731 goto cleanup; 00732 } 00733 if (!ConvertSidToStringSidW(TokenUserInfo->User.Sid, &StringSid)) 00734 { 00735 hr = HRESULT_FROM_WIN32(GetLastError()); 00736 goto cleanup; 00737 } 00738 } 00739 00740 DirectoryLength = wcslen(VolumePath) + wcslen(RecycleBinDirectory) + 1; 00741 if (StringSid) 00742 DirectoryLength += wcslen(StringSid) + 1; 00743 DirectoryLength += 1 + wcslen(RECYCLE_BIN_FILE_NAME); 00744 DirectoryLength += wcslen(VolumePath) + 1; 00745 Needed = (DirectoryLength + 1) * sizeof(WCHAR); 00746 00747 s = CoTaskMemAlloc(sizeof(struct RecycleBin5) + Needed); 00748 if (!s) 00749 { 00750 hr = E_OUTOFMEMORY; 00751 goto cleanup; 00752 } 00753 ZeroMemory(s, sizeof(struct RecycleBin5)); 00754 s->recycleBinImpl.lpVtbl = &RecycleBin5Vtbl; 00755 s->ref = 1; 00756 if (StringSid) 00757 len = swprintf(s->Folder, L"%s%s\\%s", VolumePath, RecycleBinDirectory, StringSid); 00758 else 00759 len = swprintf(s->Folder, L"%s%s", VolumePath, RecycleBinDirectory); 00760 p = &s->Folder[len]; 00761 wcscpy(p, L"\\" RECYCLE_BIN_FILE_NAME); 00762 s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 00763 if (s->hInfo == INVALID_HANDLE_VALUE && (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND)) 00764 { 00765 *p = UNICODE_NULL; 00766 hr = RecycleBin5_Create(s->Folder, TokenUserInfo ? TokenUserInfo->User.Sid : NULL); 00767 *p = L'\\'; 00768 if (!SUCCEEDED(hr)) 00769 goto cleanup; 00770 s->hInfo = CreateFileW(s->Folder, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 00771 } 00772 if (s->hInfo == INVALID_HANDLE_VALUE) 00773 { 00774 hr = HRESULT_FROM_WIN32(GetLastError()); 00775 goto cleanup; 00776 } 00777 s->hInfoMapped = CreateFileMappingW(s->hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); 00778 if (!s->hInfoMapped) 00779 { 00780 hr = HRESULT_FROM_WIN32(GetLastError()); 00781 goto cleanup; 00782 } 00783 *p = UNICODE_NULL; 00784 s->VolumePath = p + 1; 00785 wcscpy(s->VolumePath, VolumePath); 00786 00787 *ppUnknown = (IUnknown *)&s->recycleBinImpl; 00788 00789 hr = S_OK; 00790 00791 cleanup: 00792 if (tokenHandle != INVALID_HANDLE_VALUE) 00793 CloseHandle(tokenHandle); 00794 HeapFree(GetProcessHeap(), 0, TokenUserInfo); 00795 if (StringSid) 00796 LocalFree(StringSid); 00797 if (!SUCCEEDED(hr)) 00798 { 00799 if (s) 00800 RecycleBin5_Destructor(s); 00801 } 00802 return hr; 00803 } Generated on Sun May 27 2012 04:36:16 for ReactOS by
1.7.6.1
|