2007-10-31 08:57:35 +00:00
|
|
|
|
/*
|
|
|
|
|
* PROJECT: Recycle bin management
|
|
|
|
|
* LICENSE: GPL v2 - See COPYING in the top level directory
|
|
|
|
|
* FILE: lib/recyclebin/recyclebin_generic.c
|
|
|
|
|
* PURPOSE: Deals with a system-wide recycle bin
|
|
|
|
|
* PROGRAMMERS: Copyright 2007 Herv<EFBFBD> Poussineau (hpoussin@reactos.org)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define COBJMACROS
|
|
|
|
|
#include "recyclebin_private.h"
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
2007-10-31 13:04:47 +00:00
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
|
|
|
|
|
|
2007-10-31 08:57:35 +00:00
|
|
|
|
struct RecycleBinGeneric
|
|
|
|
|
{
|
|
|
|
|
ULONG ref;
|
|
|
|
|
IRecycleBin recycleBinImpl;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
2007-11-27 08:22:16 +00:00
|
|
|
|
RecycleBinGeneric_RecycleBin_QueryInterface(
|
2007-10-31 08:57:35 +00:00
|
|
|
|
IRecycleBin *This,
|
|
|
|
|
REFIID riid,
|
|
|
|
|
void **ppvObject)
|
|
|
|
|
{
|
|
|
|
|
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
|
|
|
|
|
|
2007-10-31 13:04:47 +00:00
|
|
|
|
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
|
|
|
|
|
|
2007-10-31 08:57:35 +00:00
|
|
|
|
if (!ppvObject)
|
|
|
|
|
return E_POINTER;
|
|
|
|
|
|
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown))
|
|
|
|
|
*ppvObject = &s->recycleBinImpl;
|
|
|
|
|
else if (IsEqualIID(riid, &IID_IRecycleBin))
|
|
|
|
|
*ppvObject = &s->recycleBinImpl;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*ppvObject = NULL;
|
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IUnknown_AddRef(This);
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ULONG STDMETHODCALLTYPE
|
2007-11-27 08:22:16 +00:00
|
|
|
|
RecycleBinGeneric_RecycleBin_AddRef(
|
2007-10-31 08:57:35 +00:00
|
|
|
|
IRecycleBin *This)
|
|
|
|
|
{
|
|
|
|
|
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
|
|
|
|
|
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
|
2007-10-31 13:04:47 +00:00
|
|
|
|
TRACE("(%p)\n", This);
|
2007-10-31 08:57:35 +00:00
|
|
|
|
return refCount;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-27 08:22:16 +00:00
|
|
|
|
static VOID
|
|
|
|
|
RecycleBinGeneric_Destructor(
|
|
|
|
|
struct RecycleBinGeneric *s)
|
|
|
|
|
{
|
|
|
|
|
TRACE("(%p)\n", s);
|
|
|
|
|
|
|
|
|
|
CoTaskMemFree(s);
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-31 08:57:35 +00:00
|
|
|
|
static ULONG STDMETHODCALLTYPE
|
2007-11-27 08:22:16 +00:00
|
|
|
|
RecycleBinGeneric_RecycleBin_Release(
|
2007-10-31 08:57:35 +00:00
|
|
|
|
IRecycleBin *This)
|
|
|
|
|
{
|
|
|
|
|
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
|
|
|
|
|
ULONG refCount;
|
|
|
|
|
|
2007-10-31 13:04:47 +00:00
|
|
|
|
TRACE("(%p)\n", This);
|
2007-10-31 08:57:35 +00:00
|
|
|
|
|
|
|
|
|
refCount = InterlockedDecrement((PLONG)&s->ref);
|
|
|
|
|
|
|
|
|
|
if (refCount == 0)
|
2007-11-27 08:22:16 +00:00
|
|
|
|
RecycleBinGeneric_Destructor(s);
|
2007-10-31 08:57:35 +00:00
|
|
|
|
|
|
|
|
|
return refCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
2007-11-27 08:22:16 +00:00
|
|
|
|
RecycleBinGeneric_RecycleBin_DeleteFile(
|
2007-10-31 08:57:35 +00:00
|
|
|
|
IN IRecycleBin *This,
|
|
|
|
|
IN LPCWSTR szFileName)
|
|
|
|
|
{
|
|
|
|
|
IRecycleBin *prb;
|
|
|
|
|
LPWSTR szFullName = NULL;
|
|
|
|
|
DWORD dwBufferLength = 0;
|
|
|
|
|
DWORD len;
|
|
|
|
|
WCHAR szVolume[MAX_PATH];
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
2007-10-31 13:04:47 +00:00
|
|
|
|
TRACE("(%p, %s)\n", This, debugstr_w(szFileName));
|
|
|
|
|
|
2007-10-31 08:57:35 +00:00
|
|
|
|
/* Get full file name */
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, NULL);
|
|
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
if (szFullName)
|
|
|
|
|
CoTaskMemFree(szFullName);
|
|
|
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
|
}
|
|
|
|
|
else if (len < dwBufferLength)
|
|
|
|
|
break;
|
|
|
|
|
if (szFullName)
|
|
|
|
|
CoTaskMemFree(szFullName);
|
|
|
|
|
dwBufferLength = len;
|
|
|
|
|
szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
|
|
|
|
|
if (!szFullName)
|
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get associated volume path */
|
|
|
|
|
#ifndef __REACTOS__
|
|
|
|
|
if (!GetVolumePathNameW(szFullName, szVolume, MAX_PATH))
|
|
|
|
|
{
|
|
|
|
|
CoTaskMemFree(szFullName);
|
|
|
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
swprintf(szVolume, L"%c:\\", szFullName[0]);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Skip namespace (if any) */
|
|
|
|
|
if (szVolume[0] == '\\'
|
|
|
|
|
&& szVolume[1] == '\\'
|
|
|
|
|
&& (szVolume[2] == '.' || szVolume[2] == '?')
|
|
|
|
|
&& szVolume[3] == '\\')
|
|
|
|
|
{
|
|
|
|
|
MoveMemory(szVolume, &szVolume[4], (MAX_PATH - 4) * sizeof(WCHAR));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hr = GetDefaultRecycleBin(szVolume, &prb);
|
|
|
|
|
if (!SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
CoTaskMemFree(szFullName);
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hr = IRecycleBin_DeleteFile(prb, szFullName);
|
|
|
|
|
CoTaskMemFree(szFullName);
|
|
|
|
|
IRecycleBin_Release(prb);
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
2007-11-27 08:22:16 +00:00
|
|
|
|
RecycleBinGeneric_RecycleBin_EmptyRecycleBin(
|
2007-10-31 08:57:35 +00:00
|
|
|
|
IN IRecycleBin *This)
|
|
|
|
|
{
|
|
|
|
|
WCHAR szVolumeName[MAX_PATH];
|
|
|
|
|
DWORD dwLogicalDrives, i;
|
|
|
|
|
IRecycleBin *prb;
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
2007-10-31 13:04:47 +00:00
|
|
|
|
TRACE("(%p)\n", This);
|
|
|
|
|
|
2007-10-31 08:57:35 +00:00
|
|
|
|
dwLogicalDrives = GetLogicalDrives();
|
|
|
|
|
if (dwLogicalDrives == 0)
|
|
|
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 26; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!(dwLogicalDrives & (1 << i)))
|
|
|
|
|
continue;
|
|
|
|
|
swprintf(szVolumeName, L"%c:\\", 'A' + i);
|
|
|
|
|
if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
|
|
|
|
|
continue;
|
2007-11-27 08:22:16 +00:00
|
|
|
|
|
2007-10-31 08:57:35 +00:00
|
|
|
|
hr = GetDefaultRecycleBin(szVolumeName, &prb);
|
|
|
|
|
if (!SUCCEEDED(hr))
|
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
|
|
hr = IRecycleBin_EmptyRecycleBin(prb);
|
|
|
|
|
IRecycleBin_Release(prb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HRESULT STDMETHODCALLTYPE
|
2007-11-27 08:22:16 +00:00
|
|
|
|
RecycleBinGeneric_RecycleBin_EnumObjects(
|
2007-10-31 08:57:35 +00:00
|
|
|
|
IN IRecycleBin *This,
|
|
|
|
|
OUT IRecycleBinEnumList **ppEnumList)
|
|
|
|
|
{
|
2007-10-31 13:04:47 +00:00
|
|
|
|
TRACE("(%p, %p)\n", This, ppEnumList);
|
2007-11-27 08:22:16 +00:00
|
|
|
|
return RecycleBinGenericEnum_Constructor(ppEnumList);
|
2007-10-31 08:57:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CONST_VTBL struct IRecycleBinVtbl RecycleBinGenericVtbl =
|
|
|
|
|
{
|
2007-11-27 08:22:16 +00:00
|
|
|
|
RecycleBinGeneric_RecycleBin_QueryInterface,
|
|
|
|
|
RecycleBinGeneric_RecycleBin_AddRef,
|
|
|
|
|
RecycleBinGeneric_RecycleBin_Release,
|
|
|
|
|
RecycleBinGeneric_RecycleBin_DeleteFile,
|
|
|
|
|
RecycleBinGeneric_RecycleBin_EmptyRecycleBin,
|
|
|
|
|
RecycleBinGeneric_RecycleBin_EnumObjects,
|
2007-10-31 08:57:35 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown)
|
|
|
|
|
{
|
|
|
|
|
/* This RecycleBin implementation was introduced to be able to manage all
|
|
|
|
|
* drives at once, and instanciate the 'real' implementations when needed */
|
|
|
|
|
struct RecycleBinGeneric *s;
|
|
|
|
|
|
|
|
|
|
s = CoTaskMemAlloc(sizeof(struct RecycleBinGeneric));
|
|
|
|
|
if (!s)
|
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
s->ref = 1;
|
|
|
|
|
s->recycleBinImpl.lpVtbl = &RecycleBinGenericVtbl;
|
|
|
|
|
|
|
|
|
|
*ppUnknown = (IUnknown *)&s->recycleBinImpl;
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|