Author: hpoussin Date: Tue Apr 11 23:51:55 2006 New Revision: 21553
URL: http://svn.reactos.ru/svn/reactos?rev=21553&view=rev Log: Add library to deal with recycle bin. It is aimed to be compatible with Windows 2000/XP/2003 (at least) on FAT or NTFS volumes.
Added: trunk/reactos/lib/recyclebin/ trunk/reactos/lib/recyclebin/openclose.c trunk/reactos/lib/recyclebin/readme.txt trunk/reactos/lib/recyclebin/recyclebin.c trunk/reactos/lib/recyclebin/recyclebin.h trunk/reactos/lib/recyclebin/recyclebin.rbuild trunk/reactos/lib/recyclebin/recyclebin_private.h trunk/reactos/lib/recyclebin/recyclebin_v5.c trunk/reactos/lib/recyclebin/recyclebin_v5.h trunk/reactos/lib/recyclebin/refcount.c Modified: trunk/reactos/lib/lib.rbuild
Modified: trunk/reactos/lib/lib.rbuild URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/lib.rbuild?rev=21553&... ============================================================================== --- trunk/reactos/lib/lib.rbuild (original) +++ trunk/reactos/lib/lib.rbuild Tue Apr 11 23:51:55 2006 @@ -4,12 +4,11 @@ <directory name="3rdparty"> <xi:include href="3rdparty/3rdparty.rbuild" /> </directory> +<directory name="crt"> + <xi:include href="crt/crt.rbuild" /> +</directory> <directory name="drivers"> <xi:include href="drivers/directory.rbuild" /> -</directory> - -<directory name="crt"> - <xi:include href="crt/crt.rbuild" /> </directory> <directory name="dxguid"> <xi:include href="dxguid/dxguid.rbuild" /> @@ -38,6 +37,9 @@ <directory name="pseh"> <xi:include href="pseh/pseh.rbuild" /> </directory> +<directory name="recyclebin"> + <xi:include href="recyclebin/recyclebin.rbuild" /> +</directory> <directory name="rossym"> <xi:include href="rossym/rossym.rbuild" /> </directory>
Added: trunk/reactos/lib/recyclebin/openclose.c URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/openclose.c?r... ============================================================================== --- trunk/reactos/lib/recyclebin/openclose.c (added) +++ trunk/reactos/lib/recyclebin/openclose.c Tue Apr 11 23:51:55 2006 @@ -1,0 +1,315 @@ +/* + * PROJECT: Recycle bin management + * LICENSE: GPL v2 - See COPYING in the top level directory + * FILE: lib/recyclebin/openclose.c + * PURPOSE: Open/close recycle bins + * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org) + */ + +#include "recyclebin_private.h" + +BOOL +IntCheckDeletedFileHandle( + IN HANDLE hDeletedFile) +{ + if (hDeletedFile == NULL || hDeletedFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (((PDELETED_FILE_HANDLE)hDeletedFile)->magic != DELETEDFILE_MAGIC) + return FALSE; + + return TRUE; +} + +static BOOL +IntCloseRecycleBinHandle( + IN PREFCOUNT_DATA pData) +{ + PRECYCLE_BIN bin; + + bin = CONTAINING_RECORD(pData, RECYCLE_BIN, refCount); + if (!CloseHandle(bin->hInfo)) + return FALSE; + + RemoveEntryList(&bin->ListEntry); + HeapFree(GetProcessHeap(), 0, bin); + return TRUE; +} + +static BOOL +IntCreateEmptyRecycleBin( + IN PRECYCLE_BIN bin, + IN PSID OwnerSid OPTIONAL) +{ + LPWSTR BufferName = NULL; + LPWSTR Separator; /* Pointer into BufferName buffer */ + LPWSTR FileName; /* Pointer into BufferName buffer */ + LPCSTR DesktopIniContents = "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n"; + DWORD Info2Contents[] = { 5, 0, 0, 0x320, 0 }; + SIZE_T BytesToWrite, BytesWritten, Needed; + HANDLE hFile = INVALID_HANDLE_VALUE; + BOOL ret = FALSE; + + Needed = (wcslen(bin->Folder) + 1 + max(wcslen(RECYCLE_BIN_FILE_NAME), wcslen(L"desktop.ini")) + 1) * sizeof(WCHAR); + BufferName = HeapAlloc(GetProcessHeap(), 0, Needed); + if (!BufferName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + + wcscpy(BufferName, bin->Folder); + Separator = wcsstr(&BufferName[3], L"\"); + if (Separator) + *Separator = UNICODE_NULL; + ret = CreateDirectoryW(BufferName, NULL); + if (!ret && GetLastError() != ERROR_ALREADY_EXISTS) + goto cleanup; + SetFileAttributesW(BufferName, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + if (Separator) + { + *Separator = L'\'; + ret = CreateDirectoryW(BufferName, NULL); + if (!ret && GetLastError() != ERROR_ALREADY_EXISTS) + goto cleanup; + } + + if (OwnerSid) + { + //DWORD rc; + + /* Add ACL to allow only user/SYSTEM to open it */ + /* FIXME: rc = SetNamedSecurityInfo( + BufferName, + SE_FILE_OBJECT, + ???, + OwnerSid, + NULL, + ???, + ???); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + */ + } + + wcscat(BufferName, L"\"); + FileName = &BufferName[wcslen(BufferName)]; + + /* Create desktop.ini */ + wcscpy(FileName, L"desktop.ini"); + hFile = CreateFileW(BufferName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL); + if (hFile == INVALID_HANDLE_VALUE) + goto cleanup; + BytesToWrite = strlen(DesktopIniContents); + ret = WriteFile(hFile, DesktopIniContents, (DWORD)BytesToWrite, &BytesWritten, NULL); + if (!ret) + goto cleanup; + if (BytesWritten != BytesToWrite) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + CloseHandle(hFile); + hFile = INVALID_HANDLE_VALUE; + + /* Create empty INFO2 file */ + wcscpy(FileName, RECYCLE_BIN_FILE_NAME); + hFile = CreateFileW(BufferName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); + if (hFile == INVALID_HANDLE_VALUE) + goto cleanup; + BytesToWrite = sizeof(Info2Contents); + ret = WriteFile(hFile, Info2Contents, (DWORD)BytesToWrite, &BytesWritten, NULL); + if (!ret) + goto cleanup; + if (BytesWritten != BytesToWrite) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + bin->hInfo = hFile; + ret = TRUE; + +cleanup: + HeapFree(GetProcessHeap(), 0, BufferName); + if (!ret) + { + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); + } + return ret; +} + +PRECYCLE_BIN +IntReferenceRecycleBin( + IN WCHAR driveLetter) +{ + PLIST_ENTRY ListEntry; + PRECYCLE_BIN bin = NULL, ret = NULL; + WCHAR RootPath[4]; + DWORD FileSystemFlags; + LPCWSTR RecycleBinDirectory; + HANDLE tokenHandle = INVALID_HANDLE_VALUE; + PTOKEN_USER TokenUserInfo = NULL; + LPWSTR StringSid = NULL; + SIZE_T Needed, DirectoryLength; + INFO2_HEADER Header; + BOOL AlreadyCreated = FALSE; + DWORD bytesRead; + + static LIST_ENTRY ListHead; + static BOOL ListInitialized = FALSE; + + if (!ListInitialized) + { + InitializeListHead(&ListHead); + ListInitialized = TRUE; + } + + /* Search if the recycle bin has already been opened */ + driveLetter = toupper(driveLetter); + ListEntry = ListHead.Flink; + while (ListEntry != &ListHead) + { + bin = CONTAINING_RECORD(ListEntry, RECYCLE_BIN, ListEntry); + if (bin->Folder[0] == driveLetter) + { + ReferenceHandle(&bin->refCount); + return bin; + } + ListEntry = ListEntry->Flink; + } + bin = NULL; + + /* We need to create a new recycle bin */ + + /* Get information about file system */ + wsprintfW(RootPath, L"%c:\", driveLetter); + if (!GetVolumeInformationW( + RootPath, + NULL, + 0, + NULL, + NULL, + &FileSystemFlags, + NULL, + 0)) + { + goto cleanup; + } + if (!(FileSystemFlags & FILE_PERSISTENT_ACLS)) + RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITHOUT_ACL; + else + { + RecycleBinDirectory = RECYCLE_BIN_DIRECTORY_WITH_ACL; + + /* Get user SID */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle)) + goto cleanup; + if (GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &Needed)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + goto cleanup; + TokenUserInfo = HeapAlloc(GetProcessHeap(), 0, Needed); + if (!TokenUserInfo) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + if (!GetTokenInformation(tokenHandle, TokenUser, TokenUserInfo, (DWORD)Needed, &Needed)) + goto cleanup; + if (!ConvertSidToStringSidW(TokenUserInfo->User.Sid, &StringSid)) + goto cleanup; + } + + /* Create RECYCLEBIN structure */ +openfile: + DirectoryLength = 3 + wcslen(RecycleBinDirectory) + 1; + if (StringSid) + DirectoryLength += wcslen(StringSid) + 1; + Needed = FIELD_OFFSET(RECYCLE_BIN, Folder) + (2 * DirectoryLength + 2 + wcslen(RECYCLE_BIN_FILE_NAME))* sizeof(WCHAR); + bin = HeapAlloc(GetProcessHeap(), 0, Needed); + if (!bin) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + memset(bin, 0, Needed); + InitializeHandle(&bin->refCount, IntCloseRecycleBinHandle); + bin->magic = RECYCLEBIN_MAGIC; + bin->hInfo = INVALID_HANDLE_VALUE; + bin->InfoFile = &bin->Folder[DirectoryLength]; + bin->Folder[0] = driveLetter; + bin->Folder[1] = '\0'; + wcscat(bin->Folder, L":\"); + wcscat(bin->Folder, RecycleBinDirectory); + if (StringSid) + { + wcscat(bin->Folder, L"\"); + wcscat(bin->Folder, StringSid); + } + wcscpy(bin->InfoFile, bin->Folder); + wcscat(bin->InfoFile, L"\"); + wcscat(bin->InfoFile, RECYCLE_BIN_FILE_NAME); + InsertTailList(&ListHead, &bin->ListEntry); + + /* Open info file */ + bin->hInfo = CreateFileW(bin->InfoFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (bin->hInfo == INVALID_HANDLE_VALUE) + { + if (GetLastError() == ERROR_PATH_NOT_FOUND || GetLastError() == ERROR_FILE_NOT_FOUND) + { + if (!IntCreateEmptyRecycleBin(bin, TokenUserInfo ? TokenUserInfo->User.Sid : NULL)) + goto cleanup; + AlreadyCreated = TRUE; + } + } + if (bin->hInfo == INVALID_HANDLE_VALUE) + goto cleanup; + + if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!ReadFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesRead, NULL)) + goto cleanup; + if (bytesRead != sizeof(INFO2_HEADER) && !AlreadyCreated) + { + /* Create a new file */ + if (!DereferenceHandle(&bin->refCount)) + goto cleanup; + if (!DeleteFileW(bin->InfoFile)) + goto cleanup; + goto openfile; + } + switch (Header.dwVersion) + { + case 5: + InitializeCallbacks5(&bin->Callbacks); + break; + default: + /* Unknown recycle bin version */ + SetLastError(ERROR_NOT_SUPPORTED); + goto cleanup; + } + + ret = bin; + +cleanup: + if (tokenHandle != INVALID_HANDLE_VALUE) + CloseHandle(tokenHandle); + HeapFree(GetProcessHeap(), 0, TokenUserInfo); + if (StringSid) + LocalFree(StringSid); + if (!ret) + { + if (bin && bin->hInfo != INVALID_HANDLE_VALUE) + DereferenceHandle(&bin->refCount); + HeapFree(GetProcessHeap(), 0, bin); + } + return ret; +}
Added: trunk/reactos/lib/recyclebin/readme.txt URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/readme.txt?re... ============================================================================== --- trunk/reactos/lib/recyclebin/readme.txt (added) +++ trunk/reactos/lib/recyclebin/readme.txt Tue Apr 11 23:51:55 2006 @@ -1,0 +1,14 @@ +This library deals with Recycle bin. +It is aimed to be compatible with Windows 2000/XP/2003 (at least) on FAT or NTFS volumes. + + +TODO +- Empty a recycle bin containing directories (v5) +- Set security on recycle bin folder +- Delete files > 4Gb + +3 levels +- 1: recyclebin.c: Public interface +- 2a: openclose.c: Open/close recycle bins +- 2b: refcount.c: Do reference counting on objects +- 3: recyclebin_v5.c: Deals with recycle bins of Windows 2000/XP/2003
Added: trunk/reactos/lib/recyclebin/recyclebin.c URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin.c?... ============================================================================== --- trunk/reactos/lib/recyclebin/recyclebin.c (added) +++ trunk/reactos/lib/recyclebin/recyclebin.c Tue Apr 11 23:51:55 2006 @@ -1,0 +1,319 @@ +/* + * PROJECT: Recycle bin management + * LICENSE: GPL v2 - See COPYING in the top level directory + * FILE: lib/recyclebin/openclose.c + * PURPOSE: Public interface + * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org) + */ + +#include "recyclebin_private.h" + +typedef struct _ENUMERATE_RECYCLE_BIN_CONTEXT +{ + PRECYCLE_BIN bin; + PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback; + PVOID Context; +} ENUMERATE_RECYCLE_BIN_CONTEXT, *PENUMERATE_RECYCLE_BIN_CONTEXT; + +BOOL WINAPI +CloseRecycleBinHandle( + IN HANDLE hDeletedFile) +{ + BOOL ret = FALSE; + + if (!IntCheckDeletedFileHandle(hDeletedFile)) + SetLastError(ERROR_INVALID_HANDLE); + else + { + PDELETED_FILE_HANDLE file = (PDELETED_FILE_HANDLE)hDeletedFile; + ret = DereferenceHandle(&file->refCount); + } + + return ret; +} + +BOOL WINAPI +DeleteFileToRecycleBinA( + IN LPCSTR FileName) +{ + int len; + LPWSTR FileNameW = NULL; + BOOL ret = FALSE; + + len = MultiByteToWideChar(CP_ACP, 0, FileName, -1, NULL, 0); + if (len == 0) + goto cleanup; + FileNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!FileNameW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + if (MultiByteToWideChar(CP_ACP, 0, FileName, -1, FileNameW, len) == 0) + goto cleanup; + + ret = DeleteFileToRecycleBinW(FileNameW); + +cleanup: + HeapFree(GetProcessHeap(), 0, FileNameW); + return ret; +} + +BOOL WINAPI +DeleteFileToRecycleBinW( + IN LPCWSTR FileName) +{ + LPWSTR FullFileName = NULL; + DWORD dwBufferLength = 0; + LPWSTR lpFilePart; + DWORD len; + PRECYCLE_BIN bin = NULL; + BOOL ret = FALSE; + + /* Get full file name */ + while (TRUE) + { + len = GetFullPathNameW(FileName, dwBufferLength, FullFileName, &lpFilePart); + if (len == 0) + goto cleanup; + else if (len < dwBufferLength) + break; + HeapFree(GetProcessHeap(), 0, FullFileName); + dwBufferLength = len; + FullFileName = HeapAlloc(GetProcessHeap(), 0, dwBufferLength * sizeof(WCHAR)); + if (!FullFileName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + } + + if (!lpFilePart || dwBufferLength < 2 || FullFileName[1] != ':') + { + /* Only a directory name, or not a local file */ + SetLastError(ERROR_INVALID_NAME); + } + + /* Open recycle bin */ + bin = IntReferenceRecycleBin(FullFileName[0]); + if (!bin) + goto cleanup; + + if (bin->Callbacks.DeleteFile) + ret = bin->Callbacks.DeleteFile(bin, FullFileName, lpFilePart); + else + SetLastError(ERROR_NOT_SUPPORTED); + +cleanup: + HeapFree(GetProcessHeap(), 0, FullFileName); + if (bin) + DereferenceHandle(&bin->refCount); + return ret; +} + +BOOL WINAPI +EmptyRecycleBinA( + IN CHAR driveLetter) +{ + return EmptyRecycleBinW((WCHAR)driveLetter); +} + +BOOL WINAPI +EmptyRecycleBinW( + IN WCHAR driveLetter) +{ + PRECYCLE_BIN bin = NULL; + BOOL ret = FALSE; + + /* Open recycle bin */ + bin = IntReferenceRecycleBin(driveLetter); + if (!bin) + goto cleanup; + + if (bin->Callbacks.EmptyRecycleBin) + ret = bin->Callbacks.EmptyRecycleBin(&bin); + else + SetLastError(ERROR_NOT_SUPPORTED); + +cleanup: + if (bin) + DereferenceHandle(&bin->refCount); + return ret; +} + +BOOL WINAPI +EnumerateRecycleBinA( + IN CHAR driveLetter, + IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, + IN PVOID Context) +{ + return EnumerateRecycleBinW((WCHAR)driveLetter, pFnCallback, Context); +} + +static BOOL +IntCloseDeletedFileHandle( + IN PREFCOUNT_DATA pData) +{ + PDELETED_FILE_HANDLE file; + + file = CONTAINING_RECORD(pData, DELETED_FILE_HANDLE, refCount); + if (!DereferenceHandle(&file->bin->refCount)) + return FALSE; + + file->magic = 0; + HeapFree(GetProcessHeap(), 0, file); + return TRUE; +} + +static BOOL +IntEnumerateRecycleBinCallback( + IN PVOID Context, + IN HANDLE hDeletedFile) +{ + PENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext = (PENUMERATE_RECYCLE_BIN_CONTEXT)Context; + PDELETED_FILE_HANDLE DeletedFileHandle = NULL; + BOOL ret = FALSE; + + DeletedFileHandle = HeapAlloc(GetProcessHeap(), 0, sizeof(DELETED_FILE_HANDLE)); + if (!DeletedFileHandle) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + + ReferenceHandle(&CallbackContext->bin->refCount); + InitializeHandle(&DeletedFileHandle->refCount, IntCloseDeletedFileHandle); + DeletedFileHandle->magic = DELETEDFILE_MAGIC; + DeletedFileHandle->bin = CallbackContext->bin; + DeletedFileHandle->hDeletedFile = hDeletedFile; + + ret = CallbackContext->pFnCallback(CallbackContext->Context, DeletedFileHandle); + +cleanup: + if (!ret) + { + if (DeletedFileHandle) + DereferenceHandle(&DeletedFileHandle->refCount); + } + return ret; +} + +BOOL WINAPI +EnumerateRecycleBinW( + IN WCHAR driveLetter, + IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, + IN PVOID Context) +{ + PRECYCLE_BIN bin = NULL; + BOOL ret = FALSE; + + /* Open recycle bin */ + bin = IntReferenceRecycleBin(driveLetter); + if (!bin) + goto cleanup; + + if (bin->Callbacks.EnumerateFiles) + { + ENUMERATE_RECYCLE_BIN_CONTEXT CallbackContext; + + CallbackContext.bin = bin; + CallbackContext.pFnCallback = pFnCallback; + CallbackContext.Context = Context; + + ret = bin->Callbacks.EnumerateFiles(bin, IntEnumerateRecycleBinCallback, &CallbackContext); + } + else + SetLastError(ERROR_NOT_SUPPORTED); + +cleanup: + if (bin) + DereferenceHandle(&bin->refCount); + return ret; +} + +BOOL WINAPI +GetDeletedFileDetailsA( + IN HANDLE hDeletedFile, + IN DWORD BufferSize, + IN OUT PDELETED_FILE_DETAILS_A FileDetails, + OUT LPDWORD RequiredSize OPTIONAL) +{ + PDELETED_FILE_DETAILS_W FileDetailsW = NULL; + DWORD BufferSizeW = 0; + DWORD RequiredSizeW; + BOOL ret = FALSE; + + if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) + { + BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + + (BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) * sizeof(WCHAR); + } + if (FileDetails && BufferSizeW) + { + FileDetailsW = HeapAlloc(GetProcessHeap(), 0, BufferSizeW); + if (!FileDetailsW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + } + + ret = GetDeletedFileDetailsW(hDeletedFile, BufferSizeW, FileDetailsW, &RequiredSizeW); + if (!ret) + goto cleanup; + + if (FileDetails) + { + memcpy(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)); + if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL)) + goto cleanup; + } + ret = TRUE; + +cleanup: + HeapFree(GetProcessHeap(), 0, FileDetailsW); + return ret; +} + +BOOL WINAPI +GetDeletedFileDetailsW( + IN HANDLE hDeletedFile, + IN DWORD BufferSize, + IN OUT PDELETED_FILE_DETAILS_W FileDetails, + OUT LPDWORD RequiredSize OPTIONAL) +{ + BOOL ret = FALSE; + + if (!IntCheckDeletedFileHandle(hDeletedFile)) + SetLastError(ERROR_INVALID_HANDLE); + else + { + PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile; + if (DeletedFile->bin->Callbacks.GetDetails) + ret = DeletedFile->bin->Callbacks.GetDetails(DeletedFile->bin, DeletedFile->hDeletedFile, BufferSize, FileDetails, RequiredSize); + else + SetLastError(ERROR_NOT_SUPPORTED); + } + + return ret; +} + +BOOL WINAPI +RestoreFile( + IN HANDLE hDeletedFile) +{ + BOOL ret = FALSE; + + if (!IntCheckDeletedFileHandle(hDeletedFile)) + SetLastError(ERROR_INVALID_HANDLE); + else + { + PDELETED_FILE_HANDLE DeletedFile = (PDELETED_FILE_HANDLE)hDeletedFile; + if (DeletedFile->bin->Callbacks.RestoreFile) + ret = DeletedFile->bin->Callbacks.RestoreFile(DeletedFile->bin, DeletedFile->hDeletedFile); + else + SetLastError(ERROR_NOT_SUPPORTED); + } + + return ret; +}
Added: trunk/reactos/lib/recyclebin/recyclebin.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin.h?... ============================================================================== --- trunk/reactos/lib/recyclebin/recyclebin.h (added) +++ trunk/reactos/lib/recyclebin/recyclebin.h Tue Apr 11 23:51:55 2006 @@ -1,0 +1,109 @@ +#ifndef __RECYCLEBIN_H +#define __RECYCLEBIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <windows.h> +#define ANY_SIZE 1 + +typedef struct _DELETED_FILE_DETAILS_A +{ + FILETIME LastModification; + FILETIME DeletionTime; + LARGE_INTEGER FileSize; + LARGE_INTEGER PhysicalFileSize; + DWORD Attributes; + CHAR FileName[ANY_SIZE]; +} DELETED_FILE_DETAILS_A, *PDELETED_FILE_DETAILS_A; +typedef struct _DELETED_FILE_DETAILS_W +{ + FILETIME LastModification; + FILETIME DeletionTime; + LARGE_INTEGER FileSize; + LARGE_INTEGER PhysicalFileSize; + DWORD Attributes; + WCHAR FileName[ANY_SIZE]; +} DELETED_FILE_DETAILS_W, *PDELETED_FILE_DETAILS_W; +#ifdef UNICODE +#define DELETED_FILE_DETAILS DELETED_FILE_DETAILS_W +#define PDELETED_FILE_DETAILS PDELETED_FILE_DETAILS_W +#else +#define DELETED_FILE_DETAILS DELETED_FILE_DETAILS_A +#define PDELETED_FILE_DETAILS PDELETED_FILE_DETAILS_A +#endif + +typedef BOOL (WINAPI *PENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context, IN HANDLE hDeletedFile); + +BOOL WINAPI +CloseRecycleBinHandle( + IN HANDLE hDeletedFile); + +BOOL WINAPI +DeleteFileToRecycleBinA( + IN LPCSTR FileName); +BOOL WINAPI +DeleteFileToRecycleBinW( + IN LPCWSTR FileName); +#ifdef UNICODE +#define DeleteFileToRecycleBin DeleteFileToRecycleBinW +#else +#define DeleteFileToRecycleBin DeleteFileToRecycleBinA +#endif + +BOOL WINAPI +EmptyRecycleBinA( + IN CHAR driveLetter); +BOOL WINAPI +EmptyRecycleBinW( + IN WCHAR driveLetter); +#ifdef UNICODE +#define EmptyRecycleBin EmptyRecycleBinW +#else +#define EmptyRecycleBin EmptyRecycleBinA +#endif + +BOOL WINAPI +EnumerateRecycleBinA( + IN CHAR driveLetter, + IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, + IN PVOID Context); +BOOL WINAPI +EnumerateRecycleBinW( + IN WCHAR driveLetter, + IN PENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, + IN PVOID Context); +#ifdef UNICODE +#define EnumerateRecycleBin EnumerateRecycleBinW +#else +#define EnumerateRecycleBin EnumerateRecycleBinA +#endif + +BOOL WINAPI +GetDeletedFileDetailsA( + IN HANDLE hDeletedFile, + IN DWORD BufferSize, + IN OUT PDELETED_FILE_DETAILS_A FileDetails, + OUT LPDWORD RequiredSize OPTIONAL); +BOOL WINAPI +GetDeletedFileDetailsW( + IN HANDLE hDeletedFile, + IN DWORD BufferSize, + IN OUT PDELETED_FILE_DETAILS_W FileDetails, + OUT LPDWORD RequiredSize OPTIONAL); +#ifdef UNICODE +#define GetDeletedFileDetails GetDeletedFileDetailsW +#else +#define GetDeletedFileDetails GetDeletedFileDetailsA +#endif + +BOOL WINAPI +RestoreFile( + IN HANDLE hDeletedFile); + +#ifdef __cplusplus +} +#endif + +#endif /* __RECYCLEBIN_H */
Added: trunk/reactos/lib/recyclebin/recyclebin.rbuild URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin.rb... ============================================================================== --- trunk/reactos/lib/recyclebin/recyclebin.rbuild (added) +++ trunk/reactos/lib/recyclebin/recyclebin.rbuild Tue Apr 11 23:51:55 2006 @@ -1,0 +1,7 @@ +<module name="recyclebin" type="staticlibrary"> + <define name="__USE_W32API" /> + <file>openclose.c</file> + <file>recyclebin.c</file> + <file>recyclebin_v5.c</file> + <file>refcount.c</file> +</module>
Added: trunk/reactos/lib/recyclebin/recyclebin_private.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_pr... ============================================================================== --- trunk/reactos/lib/recyclebin/recyclebin_private.h (added) +++ trunk/reactos/lib/recyclebin/recyclebin_private.h Tue Apr 11 23:51:55 2006 @@ -1,0 +1,116 @@ +#include "recyclebin.h" +#include "sddl.h" + +/* Defines */ +#define RECYCLEBIN_MAGIC 0x6e694252 +#define DELETEDFILE_MAGIC 0x6e694253 + +#define RECYCLE_BIN_DIRECTORY_WITH_ACL L"RECYCLER" +#define RECYCLE_BIN_DIRECTORY_WITHOUT_ACL L"RECYCLED" +#define RECYCLE_BIN_FILE_NAME L"INFO2" + +#define ROUND_UP(N, S) ((( (N) + (S) - 1) / (S) ) * (S) ) + +/* List manipulation */ +#define InitializeListHead(le) (void)((le)->Flink = (le)->Blink = (le)) +#define InsertTailList(le,e) do { PLIST_ENTRY b = (le)->Blink; (e)->Flink = (le); (e)->Blink = b; b->Flink = (e); (le)->Blink = (e); } while (0) +#define RemoveEntryList(Entry) { PLIST_ENTRY _EX_Blink, _EX_Flink; _EX_Flink = (Entry)->Flink; _EX_Blink = (Entry)->Blink; _EX_Blink->Flink = _EX_Flink; _EX_Flink->Blink = _EX_Blink; } + +/* Typedefs */ +struct _RECYCLE_BIN; +typedef struct _RECYCLE_BIN *PRECYCLE_BIN; +struct _REFCOUNT_DATA; +typedef struct _REFCOUNT_DATA *PREFCOUNT_DATA; + +typedef BOOL (*PINT_ENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context, IN HANDLE hDeletedFile); +typedef BOOL (*PDESTROY_DATA) (IN PREFCOUNT_DATA pData); + +typedef BOOL (*PCLOSE_HANDLE) (IN HANDLE hHandle); +typedef BOOL (*PDELETE_FILE) (IN PRECYCLE_BIN bin, IN LPCWSTR FullPath, IN LPCWSTR FileName); +typedef BOOL (*PEMPTY_RECYCLEBIN)(IN PRECYCLE_BIN* bin); +typedef BOOL (*PENUMERATE_FILES) (IN PRECYCLE_BIN bin, IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, IN PVOID Context); +typedef BOOL (*PGET_DETAILS) (IN PRECYCLE_BIN bin, IN HANDLE hDeletedFile, IN DWORD BufferSize, IN OUT PDELETED_FILE_DETAILS_W FileDetails, OUT LPDWORD RequiredSize OPTIONAL); +typedef BOOL (*PRESTORE_FILE) (IN PRECYCLE_BIN bin, IN HANDLE hDeletedFile); + +typedef struct _RECYCLEBIN_CALLBACKS +{ + PCLOSE_HANDLE CloseHandle; + PDELETE_FILE DeleteFile; + PEMPTY_RECYCLEBIN EmptyRecycleBin; + PENUMERATE_FILES EnumerateFiles; + PGET_DETAILS GetDetails; + PRESTORE_FILE RestoreFile; +} RECYCLEBIN_CALLBACKS, *PRECYCLEBIN_CALLBACKS; + +typedef struct _REFCOUNT_DATA +{ + DWORD ReferenceCount; + PDESTROY_DATA Close; +} REFCOUNT_DATA; + +typedef struct _RECYCLE_BIN +{ + DWORD magic; /* RECYCLEBIN_MAGIC */ + LIST_ENTRY ListEntry; + REFCOUNT_DATA refCount; + HANDLE hInfo; + RECYCLEBIN_CALLBACKS Callbacks; + LPWSTR InfoFile; + WCHAR Folder[ANY_SIZE]; /* [drive]:[RECYCLE_BIN_DIRECTORY]{SID} */ +} RECYCLE_BIN; + +typedef struct _DELETED_FILE_HANDLE +{ + DWORD magic; /* DELETEDFILE_MAGIC */ + REFCOUNT_DATA refCount; + PRECYCLE_BIN bin; + HANDLE hDeletedFile; /* specific to recycle bin format */ +} DELETED_FILE_HANDLE, *PDELETED_FILE_HANDLE; + +/* Structures on disk */ + +#include <pshpack1.h> + +typedef struct _INFO2_HEADER +{ + DWORD dwVersion; + DWORD dwNumberOfEntries; + DWORD dwHighestRecordUniqueId; + DWORD dwRecordSize; + DWORD dwTotalLogicalSize; +} INFO2_HEADER, *PINFO2_HEADER; + +#include <poppack.h> + +/* Prototypes */ + +/* openclose.c */ + +BOOL +IntCheckDeletedFileHandle( + IN HANDLE hDeletedFile); + +PRECYCLE_BIN +IntReferenceRecycleBin( + IN WCHAR driveLetter); + +/* recyclebin_v5.c */ + +VOID +InitializeCallbacks5( + IN OUT PRECYCLEBIN_CALLBACKS Callbacks); + +/* refcount.c */ + +BOOL +InitializeHandle( + IN PREFCOUNT_DATA pData, + IN PDESTROY_DATA pFnClose OPTIONAL); + +BOOL +ReferenceHandle( + IN PREFCOUNT_DATA pData); + +BOOL +DereferenceHandle( + IN PREFCOUNT_DATA pData);
Added: trunk/reactos/lib/recyclebin/recyclebin_v5.c URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_v5... ============================================================================== --- trunk/reactos/lib/recyclebin/recyclebin_v5.c (added) +++ trunk/reactos/lib/recyclebin/recyclebin_v5.c Tue Apr 11 23:51:55 2006 @@ -1,0 +1,539 @@ +/* + * PROJECT: Recycle bin management + * LICENSE: GPL v2 - See COPYING in the top level directory + * FILE: lib/recyclebin/openclose.c + * PURPOSE: Deals with recycle bins of Windows 2000/XP/2003 + * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org) + */ + +#include "recyclebin_v5.h" + +VOID +InitializeCallbacks5( + IN OUT PRECYCLEBIN_CALLBACKS Callbacks) +{ + Callbacks->CloseHandle = CloseHandle5; + Callbacks->DeleteFile = DeleteFile5; + Callbacks->EmptyRecycleBin = EmptyRecycleBin5; + Callbacks->EnumerateFiles = EnumerateFiles5; + Callbacks->GetDetails = GetDetails5; + Callbacks->RestoreFile = RestoreFile5; +} + +static BOOL +CloseHandle5( + IN HANDLE hDeletedFile) +{ + /* Nothing to do, as hDeletedFile is simply a DWORD... */ + return TRUE; +} + +static BOOL +DeleteFile5( + IN PRECYCLE_BIN bin, + IN LPCWSTR FullPath, + IN LPCWSTR FileName) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + INFO2_HEADER Header; + DELETED_FILE_RECORD DeletedFile; + DWORD bytesRead, bytesWritten; + LARGE_INTEGER fileSize; + SYSTEMTIME SystemTime; + WCHAR RootDir[4]; + WCHAR DeletedFileName[2 * MAX_PATH]; + LPCWSTR Extension; + DWORD ClusterSize, BytesPerSector, SectorsPerCluster; + BOOL ret = FALSE; + + if (wcslen(FullPath) >= MAX_PATH) + { + /* Unable to store a too long path in recycle bin */ + SetLastError(ERROR_INVALID_NAME); + goto cleanup; + } + + hFile = CreateFileW(FullPath, 0, 0, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + goto cleanup; + + if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!ReadFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesRead, NULL)) + goto cleanup; + if (bytesRead != sizeof(INFO2_HEADER) || Header.dwRecordSize == 0) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + /* Get file size */ +#if 0 + if (!GetFileSizeEx(hFile, &fileSize)) + goto cleanup; +#else + fileSize.u.LowPart = GetFileSize(hFile, &fileSize.u.HighPart); + if (fileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) + goto cleanup; +#endif + /* Check if file size is > 4Gb */ + if (fileSize.u.HighPart != 0) + { + /* FIXME: how to delete files >= 4Gb? */ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + goto cleanup; + } + Header.dwTotalLogicalSize += fileSize.u.LowPart; + + /* Generate new name */ + Header.dwHighestRecordUniqueId++; + Extension = wcsrchr(FileName, '.'); + wsprintfW(DeletedFileName, L"%s\D%c%lu%s", bin->Folder, FullPath[0] - 'A' + 'a', Header.dwHighestRecordUniqueId, Extension); + + /* Get cluster size */ + wsprintfW(RootDir, L"%c:\", bin->Folder[0]); + if (!GetDiskFreeSpaceW(RootDir, &SectorsPerCluster, &BytesPerSector, NULL, NULL)) + goto cleanup; + ClusterSize = BytesPerSector * SectorsPerCluster; + + /* Get current time */ + GetSystemTime(&SystemTime); + if (!SystemTimeToFileTime(&SystemTime, &DeletedFile.DeletionTime)) + goto cleanup; + + /* Update INFO2 */ + memset(&DeletedFile, 0, sizeof(DELETED_FILE_RECORD)); + if (WideCharToMultiByte(CP_ACP, 0, FullPath, -1, DeletedFile.FileNameA, MAX_PATH, NULL, NULL) == 0) + { + SetLastError(ERROR_INVALID_NAME); + goto cleanup; + } + DeletedFile.dwRecordUniqueId = Header.dwHighestRecordUniqueId; + DeletedFile.dwDriveNumber = tolower(bin->Folder[0]) - 'a'; + DeletedFile.dwPhysicalFileSize = ROUND_UP(fileSize.u.LowPart, ClusterSize); + wcscpy(DeletedFile.FileNameW, FullPath); + + if (!SetFilePointer(bin->hInfo, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!WriteFile(bin->hInfo, &DeletedFile, sizeof(DELETED_FILE_RECORD), &bytesWritten, NULL)) + goto cleanup; + if (bytesWritten != sizeof(DELETED_FILE_RECORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + Header.dwNumberOfEntries++; + if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + { + goto cleanup; + } + if (!WriteFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesWritten, NULL)) + goto cleanup; + if (bytesWritten != sizeof(INFO2_HEADER)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + /* Move file */ + if (!MoveFileW(FullPath, DeletedFileName)) + goto cleanup; + + ret = TRUE; + +cleanup: + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); + return ret; +} + +static BOOL +EmptyRecycleBin5( + IN PRECYCLE_BIN* bin) +{ + LPWSTR InfoFile = NULL; + BOOL ret = FALSE; + + InfoFile = HeapAlloc(GetProcessHeap(), 0, wcslen((*bin)->InfoFile) * sizeof(WCHAR) + sizeof(UNICODE_NULL)); + if (!InfoFile) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + wcscpy(InfoFile, (*bin)->InfoFile); + + /* Delete all files in the recycle bin */ + if (!EnumerateFiles5(*bin, IntEmptyRecycleBinCallback, *bin)) + goto cleanup; + + /* Delete INFO2 */ + if (!DereferenceHandle(&(*bin)->refCount)) + goto cleanup; + if (!DeleteFileW(InfoFile)) + goto cleanup; + *bin = NULL; + ret = TRUE; + +cleanup: + HeapFree(GetProcessHeap(), 0, InfoFile); + return ret; +} + +static BOOL +EnumerateFiles5( + IN PRECYCLE_BIN bin, + IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, + IN PVOID Context) +{ + INFO2_HEADER Header; + DELETED_FILE_RECORD DeletedFile; + DWORD bytesRead, dwEntries; + BOOL ret = FALSE; + + if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!ReadFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesRead, NULL)) + goto cleanup; + if (bytesRead != sizeof(INFO2_HEADER) || Header.dwRecordSize == 0) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + SetLastError(ERROR_SUCCESS); + for (dwEntries = 0; dwEntries < Header.dwNumberOfEntries; dwEntries++) + { + if (!ReadFile(bin->hInfo, &DeletedFile, Header.dwRecordSize, &bytesRead, NULL)) + goto cleanup; + if (bytesRead != Header.dwRecordSize) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + if (!pFnCallback(Context, (HANDLE)(ULONG_PTR)DeletedFile.dwRecordUniqueId)) + goto cleanup; + if (SetFilePointer(bin->hInfo, sizeof(INFO2_HEADER) + Header.dwRecordSize * dwEntries, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + goto cleanup; + } + + ret = TRUE; + +cleanup: + return ret; +} + +static BOOL +GetDetails5( + IN PRECYCLE_BIN bin, + IN HANDLE hDeletedFile, + IN DWORD BufferSize, + IN OUT PDELETED_FILE_DETAILS_W FileDetails, + OUT LPDWORD RequiredSize OPTIONAL) +{ + DELETED_FILE_RECORD DeletedFile; + SIZE_T Needed; + LPWSTR FullName = NULL; + HANDLE hFile = INVALID_HANDLE_VALUE; + BOOL ret = FALSE; + + if (!IntSearchRecord(bin, hDeletedFile, &DeletedFile, NULL)) + goto cleanup; + Needed = (DWORD)FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + (wcslen(DeletedFile.FileNameW) + 1) * sizeof(WCHAR); + if (RequiredSize) + *RequiredSize = (DWORD)Needed; + if (Needed > BufferSize) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + goto cleanup; + } + + if (!IntGetFullName(bin, &DeletedFile, &FullName)) + goto cleanup; + + /* Open file */ + FileDetails->Attributes = GetFileAttributesW(FullName); + if (FileDetails->Attributes == INVALID_FILE_ATTRIBUTES) + goto cleanup; + if (FileDetails->Attributes & FILE_ATTRIBUTE_DIRECTORY) + hFile = CreateFileW(FullName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + else + hFile = CreateFileW(FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + goto cleanup; + + /* Fill returned structure */ + if (!GetFileTime(hFile, NULL, NULL, &FileDetails->LastModification)) + goto cleanup; + memcpy(&FileDetails->DeletionTime, &DeletedFile.DeletionTime, sizeof(FILETIME)); + FileDetails->FileSize.u.LowPart = GetFileSize(hFile, &FileDetails->FileSize.u.HighPart); + if (FileDetails->FileSize.u.LowPart == INVALID_FILE_SIZE) + goto cleanup; + FileDetails->PhysicalFileSize.u.HighPart = 0; + FileDetails->PhysicalFileSize.u.LowPart = DeletedFile.dwPhysicalFileSize; + wcscpy(FileDetails->FileName, DeletedFile.FileNameW); + + ret = TRUE; + +cleanup: + HeapFree(GetProcessHeap(), 0, FullName); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); + return ret; +} + +static BOOL +RestoreFile5( + IN PRECYCLE_BIN bin, + IN HANDLE hDeletedFile) +{ + INFO2_HEADER Header; + DWORD bytesRead, bytesWritten; + LARGE_INTEGER Position; + DELETED_FILE_RECORD DeletedFile, LastFile; + LPWSTR FullName = NULL; + BOOL ret = FALSE; + + if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!ReadFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesRead, NULL)) + goto cleanup; + if (bytesRead != sizeof(INFO2_HEADER) || Header.dwRecordSize == 0) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + /* Search deleted entry */ + if (!IntSearchRecord(bin, hDeletedFile, &DeletedFile, &Position)) + goto cleanup; + /* Get destination full name */ + if (!IntGetFullName(bin, &DeletedFile, &FullName)) + goto cleanup; + /* Restore file */ + if (!MoveFileW(FullName, DeletedFile.FileNameW)) + goto cleanup; + + /* Update INFO2 */ + /* 1) If not last entry, copy last entry to the current one */ + if (SetFilePointer(bin->hInfo, -sizeof(DELETED_FILE_RECORD), NULL, FILE_END) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!ReadFile(bin->hInfo, &LastFile, sizeof(DELETED_FILE_RECORD), &bytesRead, NULL)) + goto cleanup; + if (bytesRead != sizeof(DELETED_FILE_RECORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + if (LastFile.dwRecordUniqueId != DeletedFile.dwRecordUniqueId) + { + /* Move the last entry to the current one */ + if (SetFilePointer(bin->hInfo, Position.u.LowPart, &Position.u.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!WriteFile(bin->hInfo, &LastFile, sizeof(DELETED_FILE_RECORD), &bytesWritten, NULL)) + goto cleanup; + if (bytesWritten != sizeof(DELETED_FILE_RECORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + } + /* 2) Update the header */ + Header.dwNumberOfEntries--; + if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!WriteFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesWritten, NULL)) + goto cleanup; + if (bytesWritten != sizeof(INFO2_HEADER)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + /* 3) Truncate file */ + if (SetFilePointer(bin->hInfo, -sizeof(DELETED_FILE_RECORD), NULL, FILE_END) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!SetEndOfFile(bin->hInfo)) + goto cleanup; + ret = TRUE; + +cleanup: + HeapFree(GetProcessHeap(), 0, FullName); + return ret; +} + +static BOOL +IntDeleteRecursive( + IN LPCWSTR FullName) +{ + DWORD RemovableAttributes = FILE_ATTRIBUTE_READONLY; + DWORD FileAttributes; + BOOL ret = FALSE; + + FileAttributes = GetFileAttributesW(FullName); + if (FileAttributes == INVALID_FILE_ATTRIBUTES) + { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + ret = TRUE; + goto cleanup; + } + if (FileAttributes & RemovableAttributes) + { + if (!SetFileAttributesW(FullName, FileAttributes & ~RemovableAttributes)) + goto cleanup; + } + if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + /* Recursive deletion */ + /* FIXME: recursive deletion */ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + goto cleanup; + + if (!RemoveDirectoryW(FullName)) + goto cleanup; + } + else + { + if (!DeleteFileW(FullName)) + goto cleanup; + } + ret = TRUE; + +cleanup: + return ret; +} + +static BOOL +IntEmptyRecycleBinCallback( + IN PVOID Context, + IN HANDLE hDeletedFile) +{ + PRECYCLE_BIN bin = (PRECYCLE_BIN)Context; + DELETED_FILE_RECORD DeletedFile; + LPWSTR FullName = NULL; + BOOL ret = FALSE; + + if (!IntSearchRecord(bin, hDeletedFile, &DeletedFile, NULL)) + goto cleanup; + + if (!IntGetFullName(bin, &DeletedFile, &FullName)) + goto cleanup; + + if (!IntDeleteRecursive(FullName)) + goto cleanup; + ret = TRUE; + +cleanup: + HeapFree(GetProcessHeap(), 0, FullName); + return ret; +} + +static BOOL +IntGetFullName( + IN PRECYCLE_BIN bin, + IN PDELETED_FILE_RECORD pDeletedFile, + OUT LPWSTR* pFullName) +{ + SIZE_T Needed; + LPCWSTR Extension; + LPWSTR FullName = NULL; + BOOL ret = FALSE; + + *pFullName = NULL; + Extension = wcsrchr(pDeletedFile->FileNameW, '.'); + if (Extension < wcsrchr(pDeletedFile->FileNameW, '\')) + Extension = NULL; + Needed = wcslen(bin->Folder) + 13; + if (Extension) + Needed += wcslen(Extension); + FullName = HeapAlloc(GetProcessHeap(), 0, Needed * sizeof(WCHAR)); + if (!FullName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + wsprintfW(FullName, L"%s\D%c%lu%s", bin->Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension); + *pFullName = FullName; + ret = TRUE; + +cleanup: + if (!ret) + HeapFree(GetProcessHeap(), 0, FullName); + return ret; +} + +static BOOL +IntSearchRecord( + IN PRECYCLE_BIN bin, + IN HANDLE hDeletedFile, + OUT PDELETED_FILE_RECORD pDeletedFile, + OUT PLARGE_INTEGER Position OPTIONAL) +{ + INFO2_HEADER Header; + DELETED_FILE_RECORD DeletedFile; + DWORD bytesRead, dwEntries; + BOOL ret = FALSE; + + if (SetFilePointer(bin->hInfo, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + goto cleanup; + if (!ReadFile(bin->hInfo, &Header, sizeof(INFO2_HEADER), &bytesRead, NULL)) + goto cleanup; + if (bytesRead != sizeof(INFO2_HEADER) || Header.dwRecordSize == 0) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + if (Header.dwVersion != 5 || Header.dwRecordSize != sizeof(DELETED_FILE_RECORD)) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + + SetLastError(ERROR_SUCCESS); + for (dwEntries = 0; dwEntries < Header.dwNumberOfEntries; dwEntries++) + { + if (Position) + { + LARGE_INTEGER Zero; + Zero.QuadPart = 0; + if (!SetFilePointerEx(bin->hInfo, Zero, Position, FILE_CURRENT)) + goto cleanup; + } + if (!ReadFile(bin->hInfo, &DeletedFile, Header.dwRecordSize, &bytesRead, NULL)) + goto cleanup; + if (bytesRead != Header.dwRecordSize) + { + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + if (DeletedFile.dwRecordUniqueId == (DWORD)(ULONG_PTR)hDeletedFile) + { + memcpy(pDeletedFile, &DeletedFile, Header.dwRecordSize); + ret = TRUE; + goto cleanup; + } + } + + /* Entry not found */ + SetLastError(ERROR_INVALID_HANDLE); + +cleanup: + return ret; +}
Added: trunk/reactos/lib/recyclebin/recyclebin_v5.h URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/recyclebin_v5... ============================================================================== --- trunk/reactos/lib/recyclebin/recyclebin_v5.h (added) +++ trunk/reactos/lib/recyclebin/recyclebin_v5.h Tue Apr 11 23:51:55 2006 @@ -1,0 +1,76 @@ +/* Recycle bin management + * This file is under the GPLv2 licence + * Copyright (C) 2006 Hervé Poussineau hpoussin@reactos.org + */ + +#include "recyclebin_private.h" + +#include <pshpack1.h> + +/* MS Windows 2000/XP/2003 */ +typedef struct _DELETED_FILE_RECORD +{ + CHAR FileNameA[MAX_PATH]; + DWORD dwRecordUniqueId; + DWORD dwDriveNumber; + FILETIME DeletionTime; + DWORD dwPhysicalFileSize; + WCHAR FileNameW[MAX_PATH]; +} DELETED_FILE_RECORD, *PDELETED_FILE_RECORD; + +#include <poppack.h> + +static BOOL +CloseHandle5( + IN HANDLE hDeletedFile); + +static BOOL +DeleteFile5( + IN PRECYCLE_BIN Context, + IN LPCWSTR FullPath, + IN LPCWSTR FileName); + +static BOOL +EmptyRecycleBin5( + IN PRECYCLE_BIN* bin); + +static BOOL +EnumerateFiles5( + IN PRECYCLE_BIN bin, + IN PINT_ENUMERATE_RECYCLEBIN_CALLBACK pFnCallback, + IN PVOID Context); + +static BOOL +GetDetails5( + IN PRECYCLE_BIN bin, + IN HANDLE hDeletedFile, + IN DWORD BufferSize, + IN OUT PDELETED_FILE_DETAILS_W FileDetails, + OUT LPDWORD RequiredSize OPTIONAL); + +static BOOL +RestoreFile5( + IN PRECYCLE_BIN Context, + IN HANDLE hDeletedFile); + +static BOOL +IntDeleteRecursive( + IN LPCWSTR FullName); + +static BOOL +IntEmptyRecycleBinCallback( + IN PVOID Context, + IN HANDLE hDeletedFile); + +static BOOL +IntGetFullName( + IN PRECYCLE_BIN bin, + IN PDELETED_FILE_RECORD pDeletedFile, + OUT LPWSTR* pFullName); + +static BOOL +IntSearchRecord( + IN PRECYCLE_BIN bin, + IN HANDLE hDeletedFile, + OUT PDELETED_FILE_RECORD DeletedFile, + OUT PLARGE_INTEGER Position OPTIONAL);
Added: trunk/reactos/lib/recyclebin/refcount.c URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/lib/recyclebin/refcount.c?re... ============================================================================== --- trunk/reactos/lib/recyclebin/refcount.c (added) +++ trunk/reactos/lib/recyclebin/refcount.c Tue Apr 11 23:51:55 2006 @@ -1,0 +1,42 @@ +/* + * PROJECT: Recycle bin management + * LICENSE: GPL v2 - See COPYING in the top level directory + * FILE: lib/recyclebin/openclose.c + * PURPOSE: Do reference counting on objects + * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org) + */ + +#include "recyclebin_private.h" + +BOOL +InitializeHandle( + IN PREFCOUNT_DATA pData, + IN PDESTROY_DATA pFnClose OPTIONAL) +{ + pData->ReferenceCount = 1; + pData->Close = pFnClose; + return TRUE; +} + +BOOL +ReferenceHandle( + IN PREFCOUNT_DATA pData) +{ + pData->ReferenceCount++; + return TRUE; +} + +BOOL +DereferenceHandle( + IN PREFCOUNT_DATA pData) +{ + pData->ReferenceCount--; + if (pData->ReferenceCount == 0) + { + if (pData->Close) + return pData->Close(pData); + else + return TRUE; + } + return TRUE; +}