512 lines
14 KiB
C++
512 lines
14 KiB
C++
/******************************************************************
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
diskcleanup.cpp -- disk cleanup COM object for SR
|
|
|
|
Description:
|
|
delete datastores from stale builds
|
|
|
|
|
|
******************************************************************/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windef.h>
|
|
#include <wtypes.h>
|
|
#include <winuser.h>
|
|
#include "diskcleanup.h"
|
|
#include "resource.h"
|
|
#include <utils.h>
|
|
#include <srdefs.h>
|
|
|
|
extern HMODULE ghModule;
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CSREmptyVolumeCache2::LoadBootIni
|
|
//
|
|
// Synopsis: parse the boot.ini file
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 20-Jul-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CSREmptyVolumeCache2::LoadBootIni()
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
WCHAR *pwszThisGuid = NULL;
|
|
CHAR *pszContent = NULL;
|
|
CHAR *pszLine = NULL;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
CHAR szArcName[MAX_PATH];
|
|
CHAR szOptions[MAX_PATH];
|
|
|
|
pwszThisGuid = GetMachineGuid (); // always exclude the current datastore
|
|
if (pwszThisGuid != NULL && pwszThisGuid[0] != L'\0')
|
|
{
|
|
lstrcpyW (_wszGuid[_ulGuids], s_cszRestoreDir);
|
|
lstrcatW (_wszGuid[_ulGuids], pwszThisGuid );
|
|
_ulGuids++;
|
|
}
|
|
|
|
// Read the contents of the boot.ini file into a string.
|
|
|
|
hFile = CreateFileW (L"c:\\boot.ini",
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
dwErr = GetLastError();
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD dwBytesRead = 0;
|
|
DWORD dwBytesToRead = GetFileSize(hFile, NULL);
|
|
|
|
if (dwBytesToRead == 0xFFFFFFFF || 0 == dwBytesToRead)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto Err;
|
|
}
|
|
|
|
pszContent = new CHAR [dwBytesToRead];
|
|
|
|
if (pszContent == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Err;
|
|
}
|
|
|
|
if (FALSE==ReadFile(hFile, pszContent, dwBytesToRead, &dwBytesRead, NULL))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto Err;
|
|
}
|
|
|
|
if (dwBytesToRead != dwBytesRead)
|
|
{
|
|
dwErr = ERROR_READ_FAULT;
|
|
goto Err;
|
|
}
|
|
|
|
CloseHandle (hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
|
|
pszLine = pszContent;
|
|
for (UINT i = 0; i < dwBytesRead; i++)
|
|
{
|
|
if (pszContent[i] == '=') // field indicator
|
|
pszContent[i] = '\0'; // process only the 1st field
|
|
|
|
if (pszContent[i] == '\n') // end-of-line indicator
|
|
{
|
|
pszContent[i] = '\0';
|
|
|
|
if (strncmp (pszLine, "multi", 5) == 0)
|
|
{
|
|
HANDLE hGuidFile;
|
|
WCHAR wcsPath[MAX_PATH];
|
|
WCHAR wcsGuid [RESTOREGUID_STRLEN];
|
|
OBJECT_ATTRIBUTES oa;
|
|
UNICODE_STRING us;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
wsprintfW (wcsPath, L"\\ArcName\\%hs\\System32\\Restore\\"
|
|
L"MachineGuid.txt", pszLine);
|
|
|
|
RtlInitUnicodeString (&us, wcsPath);
|
|
|
|
InitializeObjectAttributes ( &oa, &us, OBJ_CASE_INSENSITIVE,
|
|
NULL, NULL);
|
|
|
|
NTSTATUS nts = NtCreateFile (&hGuidFile,
|
|
FILE_GENERIC_READ,
|
|
&oa,
|
|
&iosb,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_WRITE | FILE_SHARE_DELETE | FILE_SHARE_READ,
|
|
FILE_OPEN,
|
|
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0);
|
|
|
|
if (!NT_SUCCESS(nts))
|
|
{
|
|
dwErr = RtlNtStatusToDosError (nts);
|
|
}
|
|
else
|
|
{
|
|
dwBytesToRead = RESTOREGUID_STRLEN * sizeof(WCHAR);
|
|
DWORD dwRead = 0;
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
if (FALSE == ReadFile (hGuidFile, (BYTE *) wcsGuid,
|
|
dwBytesToRead, &dwRead, NULL))
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
if (_ulGuids < ARRAYSIZE && ERROR_SUCCESS == dwErr)
|
|
{
|
|
lstrcpyW (_wszGuid[_ulGuids], s_cszRestoreDir);
|
|
lstrcatW (_wszGuid[_ulGuids], (wcsGuid[0]==0xFEFF) ?
|
|
&wcsGuid[1] : wcsGuid );
|
|
_ulGuids++;
|
|
}
|
|
NtClose (hGuidFile);
|
|
}
|
|
}
|
|
pszLine = &pszContent [i+1]; // skip to next line
|
|
}
|
|
}
|
|
|
|
Err:
|
|
if (pszContent != NULL)
|
|
delete [] pszContent;
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle (hFile);
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CSREmptyVolumeCache2::EnumDataStores
|
|
//
|
|
// Synopsis: enumerate the data store on a volume
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 20-Jul-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CSREmptyVolumeCache2::EnumDataStores (DWORDLONG *pdwlSpaceUsed,
|
|
IEmptyVolumeCacheCallBack *picb,
|
|
BOOL fPurge,
|
|
WCHAR *pwszVolume)
|
|
{
|
|
HANDLE hFind = NULL;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
WIN32_FIND_DATA wfd;
|
|
WCHAR wcsPath [MAX_PATH];
|
|
|
|
*pdwlSpaceUsed = 0;
|
|
|
|
if (pwszVolume == NULL || pwszVolume[0] == L'\0') // no volume defined
|
|
return dwErr;
|
|
|
|
wsprintfW (wcsPath, L"%s%s\\%s*", pwszVolume,
|
|
s_cszSysVolInfo, s_cszRestoreDir);
|
|
|
|
hFind = FindFirstFileW (wcsPath, &wfd);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE) // no files
|
|
return dwErr;
|
|
|
|
do
|
|
{
|
|
if (TRUE == _fStop)
|
|
{
|
|
FindClose (hFind);
|
|
return ERROR_OPERATION_ABORTED;
|
|
}
|
|
|
|
if (!lstrcmp(wfd.cFileName, L".") || !lstrcmp(wfd.cFileName, L".."))
|
|
continue;
|
|
|
|
for (UINT i=0; i < _ulGuids; i++)
|
|
{
|
|
if (lstrcmpi (_wszGuid[i], wfd.cFileName) == 0)
|
|
{
|
|
break; // data store match
|
|
}
|
|
}
|
|
|
|
if (i >= _ulGuids) // no data store match
|
|
{
|
|
if (picb != NULL)
|
|
{
|
|
WCHAR wcsDataStore[MAX_PATH];
|
|
|
|
lstrcpyW (wcsPath, pwszVolume);
|
|
lstrcatW (wcsPath, s_cszSysVolInfo);
|
|
lstrcatW (wcsPath, L"\\");
|
|
lstrcatW (wcsPath, wfd.cFileName);
|
|
|
|
if (!fPurge) // calculate space usage
|
|
{
|
|
dwErr = GetFileSize_Recurse (wcsPath,
|
|
(INT64*) pdwlSpaceUsed,
|
|
&_fStop);
|
|
}
|
|
else // delete the data store
|
|
{
|
|
dwErr = Delnode_Recurse (wcsPath, TRUE, &_fStop);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pdwlSpaceUsed = 1; // indicate something to clean up
|
|
}
|
|
}
|
|
}
|
|
while (FindNextFileW (hFind, &wfd));
|
|
|
|
FindClose (hFind);
|
|
|
|
if (picb != NULL) // update the progress bar
|
|
{
|
|
if (!fPurge)
|
|
picb->ScanProgress (*pdwlSpaceUsed, EVCCBF_LASTNOTIFICATION , NULL);
|
|
else
|
|
picb->PurgeProgress (*pdwlSpaceUsed,0,EVCCBF_LASTNOTIFICATION,NULL);
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CSREmptyVolumeCache2::ForAllMountPoints
|
|
//
|
|
// Synopsis: call EnumerateDataStores for each mount point
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 20-Jul-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSREmptyVolumeCache2::ForAllMountPoints (DWORDLONG *pdwlSpaceUsed,
|
|
IEmptyVolumeCacheCallBack *picb,
|
|
BOOL fPurge)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
dwErr = EnumDataStores (pdwlSpaceUsed, picb, fPurge, _wszVolume);
|
|
|
|
if (ERROR_SUCCESS == dwErr)
|
|
{
|
|
WCHAR wszMount [MAX_PATH];
|
|
HANDLE hFind = FindFirstVolumeMountPoint (_wszVolume,wszMount,MAX_PATH);
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
dwErr = EnumDataStores (pdwlSpaceUsed, picb, fPurge, wszMount);
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
while (FindNextVolumeMountPoint (hFind, wszMount, MAX_PATH));
|
|
|
|
FindVolumeMountPointClose (hFind);
|
|
}
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32 (dwErr);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CSRClassFactory::CreateInstance
|
|
//
|
|
// Synopsis: create the disk cleanup plugin object
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 20-Jul-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSRClassFactory::CreateInstance (IUnknown *pUnkOuter,
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pUnkOuter != NULL)
|
|
return CLASS_E_NOAGGREGATION;
|
|
|
|
CSREmptyVolumeCache2 *pevc = new CSREmptyVolumeCache2();
|
|
if (pevc == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
hr = pevc->QueryInterface (riid, ppvObject);
|
|
|
|
pevc->Release(); // release constructor's reference
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CSREmptyVolumeCache2::InitializeEx
|
|
//
|
|
// Synopsis: initialize the disk cleanup plugin object
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 20-Jul-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSREmptyVolumeCache2::InitializeEx (
|
|
HKEY hkRegKey,
|
|
const WCHAR *pcwszVolume,
|
|
const WCHAR *pcwszKeyName,
|
|
WCHAR **ppwszDisplayName,
|
|
WCHAR **ppwszDescription,
|
|
WCHAR **ppwszBtnText,
|
|
DWORD *pdwFlags)
|
|
{
|
|
DWORDLONG dwlSpaceUsed = 0;
|
|
WCHAR *pwszDisplay = NULL;
|
|
WCHAR *pwszDescription = NULL;
|
|
HRESULT hr=S_OK;
|
|
|
|
pwszDisplay = (WCHAR *) CoTaskMemAlloc (MAX_PATH / 2 * sizeof(WCHAR));
|
|
if (NULL == pwszDisplay)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Err;
|
|
}
|
|
|
|
pwszDescription = (WCHAR *) CoTaskMemAlloc (MAX_PATH * 2 * sizeof(WCHAR));
|
|
if (NULL == pwszDescription)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Err;
|
|
}
|
|
|
|
if (0 == LoadStringW (ghModule, IDS_DISKCLEANUP_DISPLAY,
|
|
pwszDisplay, MAX_PATH / 2))
|
|
{
|
|
hr = HRESULT_FROM_WIN32 (GetLastError());
|
|
goto Err;
|
|
}
|
|
|
|
if (0 == LoadStringW (ghModule, IDS_DISKCLEANUP_DESCRIPTION,
|
|
pwszDescription, MAX_PATH * 2))
|
|
{
|
|
hr = HRESULT_FROM_WIN32 (GetLastError());
|
|
goto Err;
|
|
}
|
|
|
|
lstrcpyW (_wszVolume, pcwszVolume);
|
|
|
|
LoadBootIni(); // best effort, okay to fail
|
|
|
|
ForAllMountPoints (&dwlSpaceUsed, NULL, FALSE);
|
|
|
|
if (pdwFlags)
|
|
{
|
|
*pdwFlags |= (EVCF_ENABLEBYDEFAULT |
|
|
EVCF_ENABLEBYDEFAULT_AUTO |
|
|
EVCF_DONTSHOWIFZERO);
|
|
}
|
|
|
|
if (dwlSpaceUsed == 0)
|
|
hr = S_FALSE;
|
|
|
|
Err:
|
|
if (FAILED(hr))
|
|
{
|
|
if (pwszDisplay)
|
|
CoTaskMemFree (pwszDisplay);
|
|
if (pwszDescription)
|
|
CoTaskMemFree (pwszDescription);
|
|
|
|
if (ppwszDisplayName)
|
|
*ppwszDisplayName = NULL;
|
|
if (ppwszDescription)
|
|
*ppwszDescription = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (ppwszDisplayName)
|
|
*ppwszDisplayName = pwszDisplay;
|
|
if (ppwszDescription)
|
|
*ppwszDescription = pwszDescription;
|
|
}
|
|
|
|
if (ppwszBtnText) // no advanced button text
|
|
*ppwszBtnText = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CSREmptyVolumeCache2::GetSpaceUsed
|
|
//
|
|
// Synopsis: returns how much space can be freed on a volume
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 20-Jul-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSREmptyVolumeCache2::GetSpaceUsed ( DWORDLONG *pdwlSpaceUsed,
|
|
IEmptyVolumeCacheCallBack *picb)
|
|
|
|
{
|
|
return ForAllMountPoints (pdwlSpaceUsed, picb, FALSE);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CSREmptyVolumeCache2::Purge
|
|
//
|
|
// Synopsis: frees the disk space on a volume
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 20-Jul-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSREmptyVolumeCache2::Purge ( DWORDLONG dwlSpaceToFree,
|
|
IEmptyVolumeCacheCallBack *picb)
|
|
{
|
|
return ForAllMountPoints (&dwlSpaceToFree, picb, TRUE);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CSREmptyVolumeCache2::Deactivate
|
|
//
|
|
// Synopsis: signal the disk cleanup plugin to stop processing
|
|
//
|
|
// Arguments:
|
|
//
|
|
// History: 20-Jul-2000 HenryLee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CSREmptyVolumeCache2::Deactivate (DWORD *pdwFlags)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
|
|
if (pdwFlags)
|
|
*pdwFlags = 0; // no flags to be returned
|
|
|
|
_fStop = TRUE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|