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&am…
==============================================================================
--- 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?…
==============================================================================
--- 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(a)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?r…
==============================================================================
--- 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(a)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.r…
==============================================================================
--- 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_p…
==============================================================================
--- 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_v…
==============================================================================
--- 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(a)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_v…
==============================================================================
--- 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(a)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?r…
==============================================================================
--- 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(a)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;
+}