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.

svn path=/trunk/; revision=21553
This commit is contained in:
Hervé Poussineau
2006-04-11 19:51:55 +00:00
parent 66eb03305d
commit 878040a922
10 changed files with 1543 additions and 4 deletions
+6 -4
View File
@@ -4,13 +4,12 @@
<directory name="3rdparty">
<xi:include href="3rdparty/3rdparty.rbuild" />
</directory>
<directory name="drivers">
<xi:include href="drivers/directory.rbuild" />
</directory>
<directory name="crt">
<xi:include href="crt/crt.rbuild" />
</directory>
<directory name="drivers">
<xi:include href="drivers/directory.rbuild" />
</directory>
<directory name="dxguid">
<xi:include href="dxguid/dxguid.rbuild" />
</directory>
@@ -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>
+315
View File
@@ -0,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 ([email protected])
*/
#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;
}
+14
View File
@@ -0,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
+319
View File
@@ -0,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 ([email protected])
*/
#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;
}
+109
View File
@@ -0,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 */
+7
View File
@@ -0,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>
+116
View File
@@ -0,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);
+539
View File
@@ -0,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 ([email protected])
*/
#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;
}
+76
View File
@@ -0,0 +1,76 @@
/* Recycle bin management
* This file is under the GPLv2 licence
* Copyright (C) 2006 Hervé Poussineau <[email protected]>
*/
#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);
+42
View File
@@ -0,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 ([email protected])
*/
#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;
}