Better compatibility with MS Windows recycle bin

Add traces

svn path=/trunk/; revision=30811
This commit is contained in:
Hervé Poussineau
2007-11-27 08:22:16 +00:00
parent df9ecdbb80
commit 5220fd6970
8 changed files with 144 additions and 84 deletions
-1
View File
@@ -4,7 +4,6 @@ It is aimed to be compatible with Windows 2000/XP/2003 (at least) on FAT or NTFS
TODO
- Empty a recycle bin containing directories (v5)
- Set security on recycle bin folder
- Delete files > 4Gb
- Make the library thread-safe
3 levels
+24
View File
@@ -10,6 +10,8 @@
#include "recyclebin_private.h"
#include <stdio.h>
WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
BOOL WINAPI
CloseRecycleBinHandle(
IN HANDLE hDeletedFile)
@@ -17,6 +19,8 @@ CloseRecycleBinHandle(
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
HRESULT hr;
TRACE("(%p)\n", hDeletedFile);
hr = IRecycleBinFile_Release(rbf);
if (SUCCEEDED(hr))
return TRUE;
@@ -35,6 +39,8 @@ DeleteFileToRecycleBinA(
LPWSTR FileNameW = NULL;
BOOL ret = FALSE;
TRACE("(%s)\n", debugstr_a(FileName));
/* Check parameters */
if (FileName == NULL)
{
@@ -68,6 +74,8 @@ DeleteFileToRecycleBinW(
IRecycleBin *prb;
HRESULT hr;
TRACE("(%s)\n", debugstr_w(FileName));
hr = GetDefaultRecycleBin(NULL, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
@@ -93,6 +101,8 @@ EmptyRecycleBinA(
LPWSTR szRootW = NULL;
BOOL ret = FALSE;
TRACE("(%s)\n", debugstr_a(pszRoot));
if (pszRoot)
{
len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
@@ -122,6 +132,8 @@ EmptyRecycleBinW(
IRecycleBin *prb;
HRESULT hr;
TRACE("(%s)\n", debugstr_w(pszRoot));
hr = GetDefaultRecycleBin(pszRoot, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
@@ -149,6 +161,8 @@ EnumerateRecycleBinA(
LPWSTR szRootW = NULL;
BOOL ret = FALSE;
TRACE("(%s, %p, %p)\n", debugstr_a(pszRoot), pFnCallback, Context);
if (pszRoot)
{
len = MultiByteToWideChar(CP_ACP, 0, pszRoot, -1, NULL, 0);
@@ -182,6 +196,8 @@ EnumerateRecycleBinW(
IRecycleBinFile *prbf;
HRESULT hr;
TRACE("(%s, %p, %p)\n", debugstr_w(pszRoot), pFnCallback, Context);
hr = GetDefaultRecycleBin(NULL, &prb);
if (!SUCCEEDED(hr))
goto cleanup;
@@ -231,6 +247,8 @@ GetDeletedFileDetailsA(
DWORD BufferSizeW = 0;
BOOL ret = FALSE;
TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName))
{
BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName)
@@ -274,6 +292,8 @@ GetDeletedFileDetailsW(
HRESULT hr;
SIZE_T NameSize, Needed;
TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize);
hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize);
if (!SUCCEEDED(hr))
goto cleanup;
@@ -321,6 +341,8 @@ RestoreFile(
IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile;
HRESULT hr;
TRACE("(%p)\n", hDeletedFile);
hr = IRecycleBinFile_Restore(rbf);
if (SUCCEEDED(hr))
return TRUE;
@@ -339,6 +361,8 @@ GetDefaultRecycleBin(
IUnknown *pUnk;
HRESULT hr;
TRACE("(%s, %p)\n", debugstr_w(pszVolume), pprb);
if (!pprb)
return E_POINTER;
+24 -15
View File
@@ -19,7 +19,7 @@ struct RecycleBinGeneric
};
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_QueryInterface(
RecycleBinGeneric_RecycleBin_QueryInterface(
IRecycleBin *This,
REFIID riid,
void **ppvObject)
@@ -46,7 +46,7 @@ RecycleBinGenericVtbl_RecycleBin_QueryInterface(
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_AddRef(
RecycleBinGeneric_RecycleBin_AddRef(
IRecycleBin *This)
{
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
@@ -55,8 +55,17 @@ RecycleBinGenericVtbl_RecycleBin_AddRef(
return refCount;
}
static VOID
RecycleBinGeneric_Destructor(
struct RecycleBinGeneric *s)
{
TRACE("(%p)\n", s);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_Release(
RecycleBinGeneric_RecycleBin_Release(
IRecycleBin *This)
{
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
@@ -67,13 +76,13 @@ RecycleBinGenericVtbl_RecycleBin_Release(
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
CoTaskMemFree(s);
RecycleBinGeneric_Destructor(s);
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_DeleteFile(
RecycleBinGeneric_RecycleBin_DeleteFile(
IN IRecycleBin *This,
IN LPCWSTR szFileName)
{
@@ -140,7 +149,7 @@ RecycleBinGenericVtbl_RecycleBin_DeleteFile(
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin(
RecycleBinGeneric_RecycleBin_EmptyRecycleBin(
IN IRecycleBin *This)
{
WCHAR szVolumeName[MAX_PATH];
@@ -161,7 +170,7 @@ RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin(
swprintf(szVolumeName, L"%c:\\", 'A' + i);
if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
continue;
hr = GetDefaultRecycleBin(szVolumeName, &prb);
if (!SUCCEEDED(hr))
return hr;
@@ -174,22 +183,22 @@ RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin(
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericVtbl_RecycleBin_EnumObjects(
RecycleBinGeneric_RecycleBin_EnumObjects(
IN IRecycleBin *This,
OUT IRecycleBinEnumList **ppEnumList)
{
TRACE("(%p, %p)\n", This, ppEnumList);
return RecycleBinGeneric_Enumerator_Constructor(ppEnumList);
return RecycleBinGenericEnum_Constructor(ppEnumList);
}
CONST_VTBL struct IRecycleBinVtbl RecycleBinGenericVtbl =
{
RecycleBinGenericVtbl_RecycleBin_QueryInterface,
RecycleBinGenericVtbl_RecycleBin_AddRef,
RecycleBinGenericVtbl_RecycleBin_Release,
RecycleBinGenericVtbl_RecycleBin_DeleteFile,
RecycleBinGenericVtbl_RecycleBin_EmptyRecycleBin,
RecycleBinGenericVtbl_RecycleBin_EnumObjects,
RecycleBinGeneric_RecycleBin_QueryInterface,
RecycleBinGeneric_RecycleBin_AddRef,
RecycleBinGeneric_RecycleBin_Release,
RecycleBinGeneric_RecycleBin_DeleteFile,
RecycleBinGeneric_RecycleBin_EmptyRecycleBin,
RecycleBinGeneric_RecycleBin_EnumObjects,
};
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown)
@@ -58,6 +58,17 @@ RecycleBinGenericEnum_RecycleBinEnumList_AddRef(
return refCount;
}
static VOID
RecycleBinGenericEnum_Destructor(
struct RecycleBinGenericEnum *s)
{
TRACE("(%p)\n", s);
if (s->current)
IRecycleBinEnumList_Release(s->current);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Release(
IN IRecycleBinEnumList *This)
@@ -70,11 +81,7 @@ RecycleBinGenericEnum_RecycleBinEnumList_Release(
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
{
if (s->current)
IRecycleBinEnumList_Release(s->current);
CoTaskMemFree(s);
}
RecycleBinGenericEnum_Destructor(s);
return refCount;
}
@@ -213,7 +220,7 @@ CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBinGenericEnumVtbl =
};
HRESULT
RecycleBinGeneric_Enumerator_Constructor(
RecycleBinGenericEnum_Constructor(
OUT IRecycleBinEnumList **pprbel)
{
struct RecycleBinGenericEnum *s;
+3 -12
View File
@@ -3,8 +3,6 @@
#include <wine/debug.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"
@@ -12,13 +10,6 @@
#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 */
/* Structures on disk */
#include <pshpack1.h>
@@ -26,8 +17,8 @@
typedef struct _INFO2_HEADER
{
DWORD dwVersion;
DWORD dwNumberOfEntries;
DWORD dwHighestRecordUniqueId;
DWORD dwNumberOfEntries; /* unused */
DWORD dwHighestRecordUniqueId; /* unused */
DWORD dwRecordSize;
DWORD dwTotalLogicalSize;
} INFO2_HEADER, *PINFO2_HEADER;
@@ -42,7 +33,7 @@ HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown);
/* recyclebin_generic_enumerator.c */
HRESULT RecycleBinGeneric_Enumerator_Constructor(OUT IRecycleBinEnumList **pprbel);
HRESULT RecycleBinGenericEnum_Constructor(OUT IRecycleBinEnumList **pprbel);
/* recyclebin_v5.c */
+45 -29
View File
@@ -67,7 +67,7 @@ struct RecycleBin5
};
static HRESULT STDMETHODCALLTYPE
RecycleBin5_RecycleBin5_QueryInterface(
RecycleBin5_RecycleBin5_QueryInterface(
IRecycleBin5 *This,
REFIID riid,
void **ppvObject)
@@ -105,6 +105,19 @@ RecycleBin5_RecycleBin5_AddRef(
return refCount;
}
static VOID
RecycleBin5_Destructor(
struct RecycleBin5 *s)
{
TRACE("(%p)\n", s);
if (s->hInfo && s->hInfo != INVALID_HANDLE_VALUE)
CloseHandle(s->hInfo);
if (s->hInfoMapped)
CloseHandle(s->hInfoMapped);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBin5_RecycleBin5_Release(
IRecycleBin5 *This)
@@ -117,11 +130,7 @@ RecycleBin5_RecycleBin5_Release(
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
{
CloseHandle(s->hInfo);
CloseHandle(s->hInfoMapped);
CoTaskMemFree(s);
}
RecycleBin5_Destructor(s);
return refCount;
}
@@ -141,8 +150,8 @@ RecycleBin5_RecycleBin5_DeleteFile(
HANDLE hFile = INVALID_HANDLE_VALUE;
PINFO2_HEADER pHeader = NULL;
PDELETED_FILE_RECORD pDeletedFile;
ULARGE_INTEGER fileSize;
DWORD dwAttributes;
ULARGE_INTEGER FileSize;
DWORD dwAttributes, dwEntries;
SYSTEMTIME SystemTime;
DWORD ClusterSize, BytesPerSector, SectorsPerCluster;
HRESULT hr;
@@ -209,37 +218,51 @@ RecycleBin5_RecycleBin5_DeleteFile(
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
pDeletedFile = ((PDELETED_FILE_RECORD)(pHeader + 1)) + pHeader->dwNumberOfEntries;
/* Get number of entries */
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
if (FileSize.u.LowPart < sizeof(INFO2_HEADER))
{
UnmapViewOfFile(pHeader);
return HRESULT_FROM_WIN32(GetLastError());
}
dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)) - 1;
pDeletedFile = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries;
/* Get file size */
#if 0
if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&fileSize))
if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&FileSize))
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
#else
fileSize.u.LowPart = GetFileSize(hFile, &fileSize.u.HighPart);
if (fileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
FileSize.u.LowPart = GetFileSize(hFile, &FileSize.u.HighPart);
if (FileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
#endif
/* Check if file size is > 4Gb */
if (fileSize.u.HighPart != 0)
if (FileSize.u.HighPart != 0)
{
/* FIXME: how to delete files >= 4Gb? */
hr = E_NOTIMPL;
/* Yes, this recyclebin can't support this file */
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
goto cleanup;
}
pHeader->dwTotalLogicalSize += fileSize.u.LowPart;
pHeader->dwTotalLogicalSize += FileSize.u.LowPart;
/* Generate new name */
pHeader->dwHighestRecordUniqueId++;
Extension = wcsrchr(szFullName, '.');
ZeroMemory(pDeletedFile, sizeof(DELETED_FILE_RECORD));
pDeletedFile->dwRecordUniqueId = pHeader->dwHighestRecordUniqueId;
if (dwEntries == 0)
pDeletedFile->dwRecordUniqueId = 0;
else
{
PDELETED_FILE_RECORD pLastDeleted = ((PDELETED_FILE_RECORD)(pHeader + 1)) + dwEntries - 1;
pDeletedFile->dwRecordUniqueId = pLastDeleted->dwRecordUniqueId + 1;
}
pDeletedFile->dwDriveNumber = tolower(szFullName[0]) - 'a';
_snwprintf(DeletedFileName, MAX_PATH, L"%s\\D%c%lu%s", s->Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension);
@@ -258,7 +281,7 @@ RecycleBin5_RecycleBin5_DeleteFile(
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
pDeletedFile->dwPhysicalFileSize = ROUND_UP(fileSize.u.LowPart, ClusterSize);
pDeletedFile->dwPhysicalFileSize = ROUND_UP(FileSize.u.LowPart, ClusterSize);
/* Set name */
wcscpy(pDeletedFile->FileNameW, szFullName);
@@ -268,7 +291,6 @@ RecycleBin5_RecycleBin5_DeleteFile(
SetLastError(ERROR_INVALID_NAME);
goto cleanup;
}
pHeader->dwNumberOfEntries++;
/* Move file */
if (MoveFileW(szFullName, DeletedFileName))
@@ -323,7 +345,7 @@ RecycleBin5_RecycleBin5_EnumObjects(
TRACE("(%p, %p)\n", This, ppEnumList);
hr = RecycleBin5_Enumerator_Constructor(This, s->hInfo, s->hInfoMapped, s->Folder, &pUnk);
hr = RecycleBin5Enum_Constructor(This, s->hInfo, s->hInfoMapped, s->Folder, &pUnk);
if (!SUCCEEDED(hr))
return hr;
@@ -353,7 +375,7 @@ RecycleBin5_RecycleBin5_Delete(
if (s->EnumeratorCount != 0)
return E_FAIL;
pHeader = MapViewOfFile(s->hInfoMapped, FILE_MAP_WRITE, 0, 0, 0);
if (!pHeader)
return HRESULT_FROM_WIN32(GetLastError());
@@ -729,13 +751,7 @@ cleanup:
if (!SUCCEEDED(hr))
{
if (s)
{
if (s->hInfo && s->hInfo != INVALID_HANDLE_VALUE)
CloseHandle(s->hInfo);
if (s->hInfoMapped)
CloseHandle(s->hInfoMapped);
CoTaskMemFree(s);
}
RecycleBin5_Destructor(s);
}
return hr;
}
+1 -1
View File
@@ -97,7 +97,7 @@ interface IRecycleBin5
#endif
HRESULT
RecycleBin5_Enumerator_Constructor(
RecycleBin5Enum_Constructor(
IN IRecycleBin5 *prb,
IN HANDLE hInfo,
IN HANDLE hInfoMapped,
@@ -57,6 +57,16 @@ RecycleBin5File_RecycleBinFile_AddRef(
return refCount;
}
static VOID
RecycleBin5File_Destructor(
struct RecycleBin5File *s)
{
TRACE("(%p)\n", s);
IRecycleBin5_Release(s->recycleBin);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_Release(
IN IRecycleBinFile *This)
@@ -69,10 +79,7 @@ RecycleBin5File_RecycleBinFile_Release(
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
{
IRecycleBin5_Release(s->recycleBin);
CoTaskMemFree(s);
}
RecycleBin5File_Destructor(s);
return refCount;
}
@@ -240,7 +247,7 @@ CONST_VTBL struct IRecycleBinFileVtbl RecycleBin5FileVtbl =
};
static HRESULT
RecycleBin5_File_Constructor(
RecycleBin5File_Constructor(
IN IRecycleBin5 *prb,
IN LPCWSTR Folder,
IN PDELETED_FILE_RECORD pDeletedFile,
@@ -272,6 +279,11 @@ RecycleBin5_File_Constructor(
IRecycleBin5_AddRef(s->recycleBin);
*ppFile = &s->recycleBinFileImpl;
wsprintfW(s->FullName, L"%s\\D%c%lu%s", Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension);
if (GetFileAttributesW(s->FullName) == INVALID_FILE_ATTRIBUTES)
{
RecycleBin5File_Destructor(s);
return E_FAIL;
}
return S_OK;
}
@@ -324,6 +336,18 @@ RecycleBin5Enum_RecycleBinEnumList_AddRef(
return refCount;
}
static VOID
RecycleBin5Enum_Destructor(
struct RecycleBin5Enum *s)
{
TRACE("(%p)\n", s);
IRecycleBin5_OnClosing(s->recycleBin, &s->recycleBinEnumImpl);
UnmapViewOfFile(s->pInfo);
IRecycleBin5_Release(s->recycleBin);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Release(
IN IRecycleBinEnumList *This)
@@ -336,12 +360,7 @@ RecycleBin5Enum_RecycleBinEnumList_Release(
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
{
IRecycleBin5_OnClosing(s->recycleBin, This);
UnmapViewOfFile(s->pInfo);
IRecycleBin5_Release(s->recycleBin);
CoTaskMemFree(s);
}
RecycleBin5Enum_Destructor(s);
return refCount;
}
@@ -377,15 +396,10 @@ RecycleBin5Enum_RecycleBinEnumList_Next(
pDeletedFile = (DELETED_FILE_RECORD *)(pHeader + 1) + i;
for (; i < dwEntries && fetched < celt; i++)
{
hr = RecycleBin5_File_Constructor(s->recycleBin, s->szPrefix, pDeletedFile, &rgelt[fetched]);
if (!SUCCEEDED(hr))
{
for (i = 0; i < fetched; i++)
IRecycleBinFile_Release(rgelt[i]);
return hr;
}
hr = RecycleBin5File_Constructor(s->recycleBin, s->szPrefix, pDeletedFile, &rgelt[fetched]);
if (SUCCEEDED(hr))
fetched++;
pDeletedFile++;
fetched++;
}
s->dwCurrent = i;
@@ -429,7 +443,7 @@ CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBin5EnumVtbl =
};
HRESULT
RecycleBin5_Enumerator_Constructor(
RecycleBin5Enum_Constructor(
IN IRecycleBin5 *prb,
IN HANDLE hInfo,
IN HANDLE hInfoMapped,