Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2697 lines
90 KiB

//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-2004 Microsoft Corporation
//
// Module Name: VdsClasses.cpp
//
// Description:
// Implementation of VDS WMI Provider classes
//
// Author: Jim Benton (jbenton) 15-Jan-2002
//
//////////////////////////////////////////////////////////////////////////////
#include "Pch.h"
#include <winioctl.h>
#include <fmifs.h>
#include "VdsClasses.h"
#include "ichannel.hxx"
#include <ntddvol.h>
#define INITGUIDS
#include <initguid.h>
#include <dfrgifc.h>
#include <dskquota.h>
#include "volutil.h"
#include "cmdproc.h"
// Chkdsk and Format use callbacks which require us to track some data per thread
// These help define the per thread data channel
CRITICAL_SECTION g_csThreadData;
typedef std::map < DWORD, void* > ThreadDataMap;
static ThreadDataMap g_ThreadDataMap;
typedef struct _CHKDSK_THREAD_DATA
{
BOOL fOkToRunAtBootup;
DWORD rcStatus;
} CHKDSK_THREAD_DATA, *PCHKDSK_THREAD_DATA;
void
LoadDefragAnalysis(
IN DEFRAG_REPORT* pDefragReport,
IN OUT IWbemClassObject* pObject);
void
TranslateDefragError(
IN HRESULT hr,
OUT DWORD* pdwError);
void
SetThreadData(
IN DWORD dwThreadID,
IN void* pThreadData)
{
EnterCriticalSection(&g_csThreadData);
g_ThreadDataMap[dwThreadID] = pThreadData;
LeaveCriticalSection(&g_csThreadData);
}
void*
GetThreadData(
IN DWORD dwThreadID)
{
void* pThreadData = 0;
EnterCriticalSection(&g_csThreadData);
pThreadData = g_ThreadDataMap[dwThreadID];
LeaveCriticalSection(&g_csThreadData);
return pThreadData;
}
void
RemoveThreadData(
IN DWORD dwThreadID)
{
EnterCriticalSection(&g_csThreadData);
g_ThreadDataMap.erase(dwThreadID);
LeaveCriticalSection(&g_csThreadData);
}
BOOLEAN ChkdskCallback(
FMIFS_PACKET_TYPE PacketType,
ULONG PacketLength,
PVOID PacketData
)
{
BOOL fFailed = FALSE;
DWORD dwThreadID = GetCurrentThreadId();
CHKDSK_THREAD_DATA* pThreadData = (CHKDSK_THREAD_DATA*) GetThreadData(dwThreadID);
_ASSERTE(pThreadData);
switch (PacketType)
{
case FmIfsTextMessage :
FMIFS_TEXT_MESSAGE *MessageText;
MessageText = (FMIFS_TEXT_MESSAGE*) PacketData;
break;
case FmIfsFinished:
FMIFS_FINISHED_INFORMATION *Finish;
Finish = (FMIFS_FINISHED_INFORMATION*) PacketData;
if ( Finish->Success )
{
pThreadData->rcStatus = CHKDSK_RC_NO_ERROR;
}
else
{
if (pThreadData->rcStatus != CHKDSK_RC_VOLUME_LOCKED)
{
pThreadData->rcStatus = CHKDSK_RC_UNEXPECTED;
}
}
break;
case FmIfsCheckOnReboot:
FMIFS_CHECKONREBOOT_INFORMATION *RebootResult;
pThreadData->rcStatus = CHKDSK_RC_VOLUME_LOCKED;
RebootResult = (FMIFS_CHECKONREBOOT_INFORMATION *) PacketData;
if (pThreadData->fOkToRunAtBootup)
RebootResult->QueryResult = 1;
else
RebootResult->QueryResult = 1;
break;
// although following are the additional message types, callback routine never gets these messages
// hence the detailed code for each of these return type is not written.
/*
case FmIfsIncompatibleFileSystem:
break;
case FmIfsAccessDenied:
break;
case FmIfsBadLabel:
break;
case FmIfsHiddenStatus:
break;
case FmIfsClusterSizeTooSmall:
break;
case FmIfsClusterSizeTooBig:
break;
case FmIfsVolumeTooSmall:
break;
case FmIfsVolumeTooBig:
break;
case FmIfsNoMediaInDevice:
break;
case FmIfsClustersCountBeyond32bits:
break;
case FmIfsIoError:
FMIFS_IO_ERROR_INFORMATION *IoErrorInfo;
IoErrorInfo = ( FMIFS_IO_ERROR_INFORMATION * ) PacketData;
break;
case FmIfsMediaWriteProtected:
break;
case FmIfsIncompatibleMedia:
break;
case FmIfsInsertDisk:
FMIFS_INSERT_DISK_INFORMATION *InsertDiskInfo;
InsertDiskInfo = ( FMIFS_INSERT_DISK_INFORMATION *) PacketData;
unRetVal = 1;
break;
*/
}
return (BOOLEAN) (fFailed == FALSE);
}
//****************************************************************************
//
// CVolume
//
//****************************************************************************
CVolume::CVolume(
IN LPCWSTR pwszName,
IN CWbemServices* pNamespace
)
: CProvBase(pwszName, pNamespace)
{
} //*** CVolume::CVolume()
CProvBase *
CVolume::S_CreateThis(
IN LPCWSTR pwszName,
IN CWbemServices* pNamespace
)
{
HRESULT hr = WBEM_E_FAILED;
CVolume * pObj = NULL;
pObj = new CVolume(pwszName, pNamespace);
if (pObj)
{
hr = pObj->Initialize();
}
else
{
hr = E_OUTOFMEMORY;
}
if (FAILED(hr))
{
delete pObj;
pObj = NULL;
}
return pObj;
} //*** CVolume::S_CreateThis()
HRESULT
CVolume::Initialize()
{
DWORD cchBufLen = MAX_COMPUTERNAME_LENGTH;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::Initialize");
return ft.hr;
}
HRESULT
CVolume::EnumInstance(
IN long lFlags,
IN IWbemContext* pCtx,
IN IWbemObjectSink * pHandler
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::EnumInstance");
CVssAutoPWSZ awszVolume;
try
{
awszVolume.Allocate(MAX_PATH);
CVssVolumeIterator volumeIterator;
while (true)
{
CComPtr<IWbemClassObject> spInstance;
// Get the volume name
if (!volumeIterator.SelectNewVolume(ft, awszVolume, MAX_PATH))
break;
if (VolumeIsValid(awszVolume))
{
ft.hr = m_pClass->SpawnInstance(0, &spInstance);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
LoadInstance(awszVolume, spInstance.p);
ft.hr = pHandler->Indicate(1, &spInstance.p);
}
}
}
catch (HRESULT hrEx)
{
ft.hr = hrEx;
}
return ft.hr;
} //*** CVolume::EnumInstance()
HRESULT
CVolume::GetObject(
IN CObjPath& rObjPath,
IN long lFlags,
IN IWbemContext* pCtx,
IN IWbemObjectSink* pHandler
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::GetObject");
try
{
CComPtr<IWbemClassObject> spInstance;
_bstr_t bstrID;
// Get the Volume GUID name
bstrID = rObjPath.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrID, WBEM_E_INVALID_OBJECT_PATH, L"CVolume::GetObject: volume key property not found")
ft.hr = m_pClass->SpawnInstance(0, &spInstance);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
if (VolumeIsValid((WCHAR*)bstrID))
{
LoadInstance((WCHAR*)bstrID, spInstance.p);
ft.hr = pHandler->Indicate(1, &spInstance.p);
}
else
{
ft.hr = WBEM_E_NOT_SUPPORTED;
ft.Trace(VSSDBG_VSSADMIN, L"Unsupported volume GUID, hr<%lS>", (WCHAR*)bstrID);
}
}
catch (HRESULT hrEx)
{
ft.hr = hrEx;
}
return ft.hr;
} //*** CVolume::GetObject()
void
CVolume:: LoadInstance(
IN WCHAR* pwszVolume,
IN OUT IWbemClassObject* pObject)
{
WCHAR wszDriveLetter[g_cchDriveName];
DWORD cchBuf= MAX_COMPUTERNAME_LENGTH;
WCHAR wszPath[MAX_PATH+1] ;
CVssAutoPWSZ awszVolume;
CVssAutoPWSZ awszComputerName;
CComPtr<IDiskQuotaControl> spIDQC;
IDiskQuotaControl* pIDQC = NULL;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::LoadInstance");
_ASSERTE(pwszVolume != NULL);
_ASSERTE(pObject != NULL);
CWbemClassObject wcoInstance(pObject);
awszVolume.Allocate(MAX_PATH);
// Set the volume GUID name key property
wcoInstance.SetProperty(pwszVolume, PVDR_PROP_DEVICEID);
// Get the computer name
awszComputerName.Allocate(MAX_COMPUTERNAME_LENGTH);
if (!GetComputerName(awszComputerName, &cchBuf))
{
ft.Trace(VSSDBG_VSSADMIN, L"GetComputerName failed %#x", GetLastError());
}
else
{
wcoInstance.SetProperty(awszComputerName, PVDR_PROP_SYSTEMNAME);
}
VssGetVolumeDisplayName(
pwszVolume,
wszPath,
MAX_PATH);
wcoInstance.SetProperty(wszPath, PVDR_PROP_NAME);
wcoInstance.SetProperty(wszPath, PVDR_PROP_CAPTION);
// Don't populate the remaining properties if the volume is tagged no-automount
if (!VolumeIsMountable(pwszVolume))
{
wcoInstance.SetProperty((DWORD)false, PVDR_PROP_MOUNTABLE);
}
else
{
DWORD dwSerialNumber = 0;
DWORD cchMaxFileNameLen = 0;
DWORD dwFileSystemFlags = 0;
DWORD cSectorsPerCluster = 0;
DWORD cBytesPerSector = 0;
DWORD cDontCare = 0;
ULARGE_INTEGER cbCapacity = {0, 0};
ULARGE_INTEGER cbFreeSpace = {0, 0};
ULARGE_INTEGER cbUserFreeSpace = {0, 0};
DWORD dwAttributes = 0;
WCHAR wszLabel[g_cchVolumeLabelMax+1];
WCHAR wszFileSystem[g_cchFileSystemNameMax+1];
wcoInstance.SetProperty((bool)true, PVDR_PROP_MOUNTABLE);
// Set DriveType property
wcoInstance.SetProperty(GetDriveType(pwszVolume), PVDR_PROP_DRIVETYPE);
// Set DriveLetter property
cchBuf = g_cchDriveName;
if (GetVolumeDrive(
pwszVolume,
cchBuf,
wszDriveLetter))
{
wszDriveLetter[wcslen(wszDriveLetter) - 1] = L'\0'; // Remove the trailing '\'
wcoInstance.SetProperty(wszDriveLetter, PVDR_PROP_DRIVELETTER);
}
// Skip remaining properties for drives without media
if (VolumeIsReady(pwszVolume))
{
BOOL fDirty = FALSE;
if (VolumeIsDirty(pwszVolume, &fDirty) == ERROR_SUCCESS)
wcoInstance.SetProperty(fDirty, PVDR_PROP_DIRTYBITSET);
// Set BlockSize property
if (!GetDiskFreeSpace(
pwszVolume,
&cSectorsPerCluster,
&cBytesPerSector,
&cDontCare, // total bytes
&cDontCare)) // total free bytes
{
ft.Trace(VSSDBG_VSSADMIN, L"GetDiskFreeSpace failed for volume %lS, %#x", pwszVolume, GetLastError());
}
else
{
ULONGLONG cbBytesPerCluster = cBytesPerSector * cSectorsPerCluster;
wcoInstance.SetPropertyI64(cbBytesPerCluster, PVDR_PROP_BLOCKSIZE);
}
// Set Label, FileSystem, SerialNumber, MaxFileNameLen,
// SupportsCompression, Compressed, SupportsQuotas properties
if (!GetVolumeInformation(
pwszVolume,
wszLabel,
g_cchVolumeLabelMax,
&dwSerialNumber,
&cchMaxFileNameLen,
&dwFileSystemFlags,
wszFileSystem,
g_cchFileSystemNameMax))
{
ft.Trace(VSSDBG_VSSADMIN, L"GetVolumeInformation failed for volume %lS, %#x", pwszVolume, GetLastError());
}
else
{
if (wszLabel[0] != L'\0')
wcoInstance.SetProperty(wszLabel, PVDR_PROP_LABEL);
wcoInstance.SetProperty(wszFileSystem, PVDR_PROP_FILESYSTEM);
wcoInstance.SetProperty(dwSerialNumber, PVDR_PROP_SERIALNUMBER);
wcoInstance.SetProperty(cchMaxFileNameLen, PVDR_PROP_MAXIMUMFILENAMELENGTH);
wcoInstance.SetProperty(dwFileSystemFlags & FS_VOL_IS_COMPRESSED, PVDR_PROP_COMPRESSED);
wcoInstance.SetProperty(dwFileSystemFlags & FILE_VOLUME_QUOTAS, PVDR_PROP_SUPPORTSDISKQUOTAS);
wcoInstance.SetProperty(dwFileSystemFlags & FS_FILE_COMPRESSION, PVDR_PROP_SUPPORTSFILEBASEDCOMPRESSION);
}
if (!GetDiskFreeSpaceEx(
pwszVolume,
&cbUserFreeSpace,
&cbCapacity,
&cbFreeSpace))
{
ft.Trace(VSSDBG_VSSADMIN, L"GetDiskFreeSpace failed for volume, %lS", pwszVolume);
}
{
ULONGLONG llTmp = 0;
llTmp = cbCapacity.QuadPart;
wcoInstance.SetPropertyI64(llTmp, PVDR_PROP_CAPACITY);
llTmp = cbFreeSpace.QuadPart;
wcoInstance.SetPropertyI64(llTmp, PVDR_PROP_FREESPACE);
}
if (_wcsicmp(wszFileSystem, L"NTFS") == 0)
{
dwAttributes = GetFileAttributes(pwszVolume);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
{
ft.Trace(VSSDBG_VSSADMIN, L"GetFileAttributes failed for volume %lS, %#x", pwszVolume, GetLastError());
}
else
{
BOOL fIndexingEnabled = !(dwAttributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
wcoInstance.SetProperty(fIndexingEnabled, PVDR_PROP_INDEXINGENABLED);
}
}
ft.hr = CoCreateInstance(
CLSID_DiskQuotaControl,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDiskQuotaControl,
(void **)&pIDQC);
if (ft.HrFailed())
{
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"unable to CoCreate IDiskQuotaControl");
}
spIDQC.Attach(pIDQC);
ft.hr = spIDQC->Initialize(pwszVolume, FALSE /* read only */);
if (ft.HrFailed())
{
ft.Trace(VSSDBG_VSSADMIN, L"IDiskQuotaControl::Initialize failed for volume %lS", pwszVolume);
}
else
{
DWORD dwState = 0;
ft.hr = spIDQC->GetQuotaState(&dwState);
if (ft.HrSucceeded())
{
wcoInstance.SetProperty(!(DISKQUOTA_IS_DISABLED(dwState)), PVDR_PROP_QUOTASENABLED);
wcoInstance.SetProperty(DISKQUOTA_FILE_INCOMPLETE(dwState), PVDR_PROP_QUOTASINCOMPLETE);
wcoInstance.SetProperty(DISKQUOTA_FILE_REBUILDING(dwState), PVDR_PROP_QUOTASREBUILDING);
}
}
}
}
}
HRESULT
CVolume::PutInstance(
IN CWbemClassObject& rInstToPut,
IN long lFlag,
IN IWbemContext* pCtx,
IN IWbemObjectSink* pHandler
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::PutInstance");
try
{
_bstr_t bstrVolume;
_bstr_t bstrDriveLetter;
_bstr_t bstrLabel;
BOOL fIndexingEnabled = FALSE;
WCHAR* pwszVolume = NULL;
if ( lFlag & WBEM_FLAG_CREATE_ONLY )
{
return WBEM_E_UNSUPPORTED_PARAMETER ;
}
// Retrieve key properties of the object to be saved.
rInstToPut.GetProperty(bstrVolume, PVDR_PROP_DEVICEID);
if ((WCHAR*)bstrVolume == NULL)
{
ft.hr = WBEM_E_INVALID_OBJECT;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolume::PutInstance: NULL volume name");
}
pwszVolume = (wchar_t*)bstrVolume;
if (VolumeIsValid(pwszVolume) && VolumeIsMountable(pwszVolume))
{
// Retrieve writeable properties of the object to be saved.
rInstToPut.GetProperty(bstrDriveLetter, PVDR_PROP_DRIVELETTER);
rInstToPut.GetProperty(bstrLabel, PVDR_PROP_LABEL);
rInstToPut.GetProperty(&fIndexingEnabled, PVDR_PROP_INDEXINGENABLED);
SetLabel(pwszVolume, bstrLabel);
if (!rInstToPut.IsPropertyNull(PVDR_PROP_INDEXINGENABLED))
SetContentIndexing(pwszVolume, fIndexingEnabled);
SetDriveLetter(pwszVolume, bstrDriveLetter);
}
else
{
ft.hr = WBEM_E_NOT_SUPPORTED;
ft.Trace(VSSDBG_VSSADMIN, L"Attempt to modify an unsupported or unmountedable volume, %lS", pwszVolume);
}
}
catch (HRESULT hrEx)
{
ft.hr = hrEx;
}
return ft.hr;
} //*** CStorage::PutInstance()
void
CVolume::SetDriveLetter(
IN WCHAR* pwszVolume,
IN WCHAR* pwszDrive
)
{
WCHAR wszCurrentDrivePath[g_cchDriveName+1];
BOOL fFoundDrive = FALSE;
BOOL fDeleteDrive = FALSE;
BOOL fAssignDrive = FALSE;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::SetDriveLetter");
_ASSERTE(pwszVolume != NULL)
// Validate drive letter
if (pwszDrive != NULL)
{
ft.hr = WBEM_E_INVALID_PARAMETER;
if (wcslen(pwszDrive) == 2)
{
WCHAR wc = towupper(pwszDrive[0]);
if (wc >= L'A' && wc <= L'Z' && pwszDrive[1] == L':')
ft.hr = S_OK;
}
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetDriveLetter: invalid drive letter, %lS", pwszDrive);
}
// Get the current drive letter if any
fFoundDrive = GetVolumeDrive(
pwszVolume,
g_cchDriveName,
wszCurrentDrivePath);
if (fFoundDrive)
{
if (wszCurrentDrivePath[wcslen(wszCurrentDrivePath) - 1] != L'\\')
{
ft.hr = E_UNEXPECTED;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetDriveLetter: unexpected drive letter format from GetVolumeDrivePath, %lS", wszCurrentDrivePath);
}
}
if (pwszDrive == NULL && fFoundDrive == FALSE)
{
// Do nothing, drive letter already deleted
}
else if (pwszDrive == NULL && fFoundDrive == TRUE)
{
// Delete drive letter
fDeleteDrive = TRUE;
}
else if (pwszDrive != NULL && fFoundDrive == FALSE)
{
// No drive letter currently assigned, assign drive letter
fAssignDrive = TRUE;
}
else if (_wcsnicmp(pwszDrive, wszCurrentDrivePath, 2) != 0)
{
// Requested drive letter is different than currently assigned
// Delete current drive letter
fDeleteDrive = TRUE;
// Assign new drive letter
fAssignDrive = TRUE;
}
else
{
// Do nothing, drive letter not changing
}
if (fAssignDrive)
{
// Verify that the target drive letter is available
// A race condition exists here since the drive letter may be stolen
// after this verification and before the actual assignment
if (!IsDriveLetterAvailable(pwszDrive))
{
if (IsDriveLetterSticky(pwszDrive))
{
ft.hr = VDSWMI_E_DRIVELETTER_IN_USE;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"drive letter is assigned to another volume");
}
else
{
ft.hr = VDSWMI_E_DRIVELETTER_UNAVAIL;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"drive letter is unavailable until reboot");
}
}
}
if (fDeleteDrive)
{
if (!IsBootDrive(wszCurrentDrivePath) &&
!VolumeIsSystem(pwszVolume) &&
!VolumeHoldsPagefile(pwszVolume))
{
// Try to lock the volume and delete the mountpoint.
// If the volume can't be locked, remove the drive letter from the
// volume mgr database only
// Remove any network shares for this drive letter??
DeleteVolumeDriveLetter(pwszVolume, wszCurrentDrivePath);
}
else
{
ft.hr = VDSWMI_E_DRIVELETTER_CANT_DELETE;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Drive letter deletion is blocked for this volume %lS", pwszVolume);
}
}
if (fAssignDrive)
{
// No attempt will be made to roll back a previously deleted drive letter
// if this assignment fails
// SetVolumeMountPoint API requires trailing backslash
WCHAR wszDrivePath[g_cchDriveName], *pwszDrivePath = wszDrivePath;
ft.hr = StringCchPrintf(wszDrivePath, g_cchDriveName, L"%s\\", pwszDrive);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"StringCchPrintf failed %#x", ft.hr);
if (!SetVolumeMountPoint(wszDrivePath, pwszVolume))
{
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetVolumeMountPoint failed, volume<%lS> drivePath<%lS>", pwszVolume, wszDrivePath);
}
}
}
void
CVolume::SetLabel(
IN WCHAR* pwszVolume,
IN WCHAR* pwszLabel
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::SetLabel");
_ASSERTE(pwszVolume != NULL);
if (!SetVolumeLabel(pwszVolume, pwszLabel))
{
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetVolumeLabel failed, volume<%lS> label<%lS>", pwszVolume, pwszLabel);
}
}
void
CVolume::SetContentIndexing(
IN WCHAR* pwszVolume,
IN BOOL fIndexingEnabled
)
{
DWORD dwAttributes;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::SetContentIndexing");
// Get the file attributes which include the content indexing flag
dwAttributes = GetFileAttributes(pwszVolume);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
{
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"GetFileAttributes failed, volume<%lS>", pwszVolume);
}
// Set the indexing flag
if (fIndexingEnabled)
{
// Turn indexing on
dwAttributes &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
}
else
{
// Turn indexing off
dwAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
}
if (!SetFileAttributes(pwszVolume, dwAttributes))
{
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetFileAttributes failed, volume<%lS>", pwszVolume);
}
}
HRESULT
CVolume::ExecuteMethod(
IN BSTR bstrObjPath,
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecuteMethod");
try
{
if (!_wcsicmp(pwszMethodName, PVDR_MTHD_ADDMOUNTPOINT))
{
ft.hr = ExecAddMountPoint(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else if (!_wcsicmp(pwszMethodName, PVDR_MTHD_MOUNT))
{
ft.hr = ExecMount(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else if (!_wcsicmp(pwszMethodName, PVDR_MTHD_DISMOUNT))
{
ft.hr = ExecDismount(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else if (!_wcsicmp(pwszMethodName, PVDR_MTHD_DEFRAG))
{
ft.hr = ExecDefrag(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else if (!_wcsicmp(pwszMethodName, PVDR_MTHD_DEFRAGANALYSIS))
{
ft.hr = ExecDefragAnalysis(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else if (!_wcsicmp(pwszMethodName, PVDR_MTHD_CHKDSK))
{
ft.hr = ExecChkdsk(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else if (!_wcsicmp(pwszMethodName, PVDR_MTHD_SCHEDULECHK))
{
ft.hr = ExecScheduleAutoChk(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else if (!_wcsicmp(pwszMethodName, PVDR_MTHD_EXCLUDECHK))
{
ft.hr = ExecExcludeAutoChk(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else if (!_wcsicmp(pwszMethodName, PVDR_MTHD_FORMAT))
{
ft.hr = ExecFormat(
bstrObjPath,
pwszMethodName,
lFlag,
pParams,
pHandler);
}
else
{
ft.hr = WBEM_E_INVALID_METHOD;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Invalid method called, %lS, hr<%#x>", pwszMethodName, ft.hr);
}
}
catch (HRESULT hrEx)
{
ft.hr = hrEx;
}
return ft.hr;
}
HRESULT
CVolume::ExecAddMountPoint(
IN BSTR bstrObjPath,
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecAddMountPoint");
CComPtr<IWbemClassObject> spOutParamClass;
_bstr_t bstrDirectory;
_bstr_t bstrVolume;
CObjPath objPath;
DWORD rcStatus = ERROR_SUCCESS;
if (pParams == NULL)
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::AddMountPoint called with no parameters, hr<%#x>", ft.hr);
}
objPath.Init(bstrObjPath);
bstrVolume = objPath.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolume, WBEM_E_INVALID_OBJECT_PATH, L"ExecAddMountPoint: volume key property not found")
CWbemClassObject wcoInParam(pParams);
CWbemClassObject wcoOutParam;
if (wcoInParam.data() == NULL)
{
ft.hr = E_OUTOFMEMORY;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::AddMountPoint: out of memory, hr<%#x>", ft.hr);
}
// Gets the Directory name - input param
wcoInParam.GetProperty(bstrDirectory, PVDR_PROP_DIRECTORY);
IF_WSTR_NULL_THROW(bstrDirectory, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecAddMountPoint: Directory param is NULL")
WCHAR* pwszDirectory = bstrDirectory;
if (pwszDirectory[wcslen(pwszDirectory) - 1] != L'\\')
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Invalid mount point directory, %lS, hr<%#x>", pwszDirectory, ft.hr);
}
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_ADDMOUNTPOINT),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"AddMountPoint GetMethod failed, hr<%#x>", ft.hr);
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
rcStatus = AddMountPoint(bstrVolume, bstrDirectory);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
return ft.hr;
}
HRESULT
CVolume::ExecMount(
IN BSTR bstrObjPath,
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecMount");
CComPtr<IWbemClassObject> spOutParamClass;
_bstr_t bstrVolume;
CObjPath objPath;
DWORD rcStatus = ERROR_SUCCESS;
objPath.Init(bstrObjPath);
bstrVolume = objPath.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolume, WBEM_E_INVALID_OBJECT_PATH, L"ExecMount: volume key property not found")
CWbemClassObject wcoOutParam;
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_MOUNT),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Mount GetMethod failed, hr<%#x>", ft.hr);
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
rcStatus = Mount(bstrVolume);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
return ft.hr;
}
HRESULT
CVolume::ExecDismount(
IN BSTR bstrObjPath,
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecDismount");
CComPtr<IWbemClassObject> spOutParamClass;
_bstr_t bstrVolume;
BOOL fForce = FALSE;
BOOL fPermanent = FALSE;
CObjPath objPath;
DWORD rcStatus = ERROR_SUCCESS;
if (pParams == NULL)
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::Dismount called with no parameters, hr<%#x>", ft.hr);
}
objPath.Init(bstrObjPath);
bstrVolume = objPath.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolume, WBEM_E_INVALID_OBJECT_PATH, L"ExecDismount: volume key property not found")
CWbemClassObject wcoInParam(pParams);
CWbemClassObject wcoOutParam;
if (wcoInParam.data() == NULL)
{
ft.hr = E_OUTOFMEMORY;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::Dismount out of memory, hr<%#x>", ft.hr);
}
// Get the Force flag
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_FORCE, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecDismount: Force param is NULL")
wcoInParam.GetProperty(&fForce, PVDR_PROP_FORCE);
// Get the Permanent flag
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_PERMANENT, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecDismount: Permanent param is NULL")
wcoInParam.GetProperty(&fPermanent, PVDR_PROP_PERMANENT);
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_DISMOUNT),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Dismount GetMethod failed, hr<%#x>", ft.hr);
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
rcStatus = Dismount(bstrVolume, fForce, fPermanent);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
return ft.hr;
}
HRESULT
CVolume::ExecDefrag(
IN BSTR bstrObjPath,
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecDefrag");
CComPtr<IWbemClassObject> spOutParamClass;
CComPtr<IWbemClassObject> spObjReport;
_bstr_t bstrVolume;
CObjPath objPath;
DWORD rcStatus = ERROR_SUCCESS;
BOOL fForce = FALSE;
if (pParams == NULL)
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::Defrag called with no parameters, hr<%#x>", ft.hr);
}
objPath.Init(bstrObjPath);
bstrVolume = objPath.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolume, WBEM_E_INVALID_OBJECT_PATH, L"ExecDefrag: volume key property not found")
CWbemClassObject wcoInParam(pParams);
CWbemClassObject wcoOutParam;
// Get the force flag
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_FORCE, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecDefrag: Force param is NULL")
wcoInParam.GetProperty(&fForce, PVDR_PROP_FORCE);
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_DEFRAG),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Defrag GetMethod failed, hr<%#x>", ft.hr);
// Create an out param object
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
// Create a defrag analysis report object
ft.hr = m_pNamespace->GetObject(
_bstr_t(PVDR_CLASS_DEFRAGANALYSIS),
0,
0,
&spObjReport,
NULL);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"DefragAnalysis object creation failed, hr<%#x>", ft.hr);
rcStatus = Defrag(bstrVolume, fForce, pHandler, spObjReport);
ft.hr = wcoOutParam.SetProperty(spObjReport, PVDR_PROP_DEFRAGANALYSIS);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
return ft.hr;
}
HRESULT
CVolume::ExecDefragAnalysis(
IN BSTR bstrObjPath,
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecDefragAnalysis");
CComPtr<IWbemClassObject> spOutParamClass;
CComPtr<IWbemClassObject> spObjReport;
_bstr_t bstrVolume;
CObjPath objPath;
DWORD rcStatus = ERROR_SUCCESS;
BOOL fDefragRecommended = FALSE;
// The DefragAnalysis method has no input parameters
objPath.Init(bstrObjPath);
bstrVolume = objPath.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolume, WBEM_E_INVALID_OBJECT_PATH, L"ExecDefragAnalysis: volume key property not found")
CWbemClassObject wcoOutParam;
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_DEFRAGANALYSIS),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"DefragAnalysis GetMethod failed, hr<%#x>", ft.hr);
// Create an out param object
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
// Create a defrag analysis report object
ft.hr = m_pNamespace->GetObject(
_bstr_t(PVDR_CLASS_DEFRAGANALYSIS),
0,
0,
&spObjReport,
NULL);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"DefragAnalysis object creation failed, hr<%#x>", ft.hr);
rcStatus = DefragAnalysis(bstrVolume, &fDefragRecommended, spObjReport);
ft.hr = wcoOutParam.SetProperty(fDefragRecommended, PVDR_PROP_DEFRAGRECOMMENDED);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = wcoOutParam.SetProperty(spObjReport, PVDR_PROP_DEFRAGANALYSIS);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
return ft.hr;
}
HRESULT
CVolume::ExecChkdsk(
IN BSTR bstrObjPath,
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::Chkdsk");
CComPtr<IWbemClassObject> spOutParamClass;
_bstr_t bstrVolume;
CObjPath objPath;
DWORD rcStatus = ERROR_SUCCESS;
BOOL fFixErrors = FALSE;
BOOL fVigorousIndexCheck = FALSE;
BOOL fSkipFolderCycle = FALSE;
BOOL fForceDismount = FALSE;
BOOL fRecoverBadSectors = FALSE;
BOOL fOkToRunAtBootup = FALSE;
if (pParams == NULL)
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::Chkdsk called with no parameters, hr<%#x>", ft.hr);
}
objPath.Init(bstrObjPath);
bstrVolume = objPath.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolume, WBEM_E_INVALID_OBJECT_PATH, L"ExecChkdsk: volume key property not found")
CWbemClassObject wcoInParam(pParams);
CWbemClassObject wcoOutParam;
// Check the params
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_FIXERRORS, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecChkdsk: FixErrors param is NULL")
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_VIGOROUSINDEXCHECK, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecChkdsk: VigorousCheck param is NULL")
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_SKIPFOLDERCYCLE, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecChkdsk: SkipFolderCycle param is NULL")
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_FORCEDISMOUNT, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecChkdsk: ForceDismount param is NULL")
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_RECOVERBADSECTORS, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecChkdsk: RecoverBadSectors param is NULL")
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_OKTORUNATBOOTUP, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecChkdsk: OkToRunAtBootUp param is NULL")
// Get the params
wcoInParam.GetProperty(&fFixErrors, PVDR_PROP_FIXERRORS);
wcoInParam.GetProperty(&fVigorousIndexCheck, PVDR_PROP_VIGOROUSINDEXCHECK);
wcoInParam.GetProperty(&fSkipFolderCycle, PVDR_PROP_SKIPFOLDERCYCLE);
wcoInParam.GetProperty(&fForceDismount, PVDR_PROP_FORCEDISMOUNT);
wcoInParam.GetProperty(&fRecoverBadSectors, PVDR_PROP_RECOVERBADSECTORS);
wcoInParam.GetProperty(&fOkToRunAtBootup, PVDR_PROP_OKTORUNATBOOTUP);
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_CHKDSK),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Chkdsk GetMethod failed, hr<%#x>", ft.hr);
// Create an out param object
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
rcStatus = Chkdsk(
bstrVolume,
fFixErrors,
fVigorousIndexCheck,
fSkipFolderCycle,
fForceDismount,
fRecoverBadSectors,
fOkToRunAtBootup
);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
return ft.hr;
}
// ScheduleAutoChk is a class static method.
HRESULT
CVolume::ExecScheduleAutoChk(
IN BSTR bstrObjPath, // no object path for static methods
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecScheduleAutoChk");
DWORD rcStatus = ERROR_SUCCESS;
WCHAR* pmszVolumes = NULL;
try
{
DWORD cchVolumes = 0;
CComPtr<IWbemClassObject> spOutParamClass;
CObjPath objPath;
if (pParams == NULL)
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::ExecScheduleAutoChk called with no parameters, hr<%#x>", ft.hr);
}
CWbemClassObject wcoInParam(pParams);
CWbemClassObject wcoOutParam;
if (wcoInParam.data() == NULL)
{
ft.hr = E_OUTOFMEMORY;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::ExecScheduleAutoChk: out of memory, hr<%#x>", ft.hr);
}
// Gets the Volumes
wcoInParam.GetPropertyMultiSz(&cchVolumes, &pmszVolumes, PVDR_PROP_VOLUME);
IF_WSTR_NULL_THROW(pmszVolumes, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecScheduleAutoChk: volume array param is NULL")
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_SCHEDULECHK),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"ExecScheduleAutoChk GetMethod failed, hr<%#x>", ft.hr);
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
rcStatus = AutoChk(g_wszScheduleAutoChkCommand, pmszVolumes);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
}
catch (...)
{
delete [] pmszVolumes;
throw;
}
delete [] pmszVolumes;
return ft.hr;
}
// ExcludeAutoChk is a class static method.
HRESULT
CVolume::ExecExcludeAutoChk(
IN BSTR bstrObjPath, // no object path for static methods
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecExcludeAutoChk");
DWORD rcStatus = ERROR_SUCCESS;
WCHAR* pmszVolumes = NULL;
try
{
DWORD cchVolumes = 0;
CComPtr<IWbemClassObject> spOutParamClass;
CObjPath objPath;
if (pParams == NULL)
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::ExecExcludeAutoChk called with no parameters, hr<%#x>", ft.hr);
}
CWbemClassObject wcoInParam(pParams);
CWbemClassObject wcoOutParam;
if (wcoInParam.data() == NULL)
{
ft.hr = E_OUTOFMEMORY;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::ExecExcludeAutoChk: out of memory, hr<%#x>", ft.hr);
}
// Gets the Volumes
wcoInParam.GetPropertyMultiSz(&cchVolumes, &pmszVolumes, PVDR_PROP_VOLUME);
IF_WSTR_NULL_THROW(pmszVolumes, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecExcludeAutoChk: volume array param is NULL")
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_EXCLUDECHK),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"ExecExcludeAutoChk GetMethod failed, hr<%#x>", ft.hr);
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
rcStatus = AutoChk(g_wszExcludeAutoChkCommand, pmszVolumes);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
}
catch (...)
{
delete [] pmszVolumes;
throw;
}
delete [] pmszVolumes;
return ft.hr;
}
HRESULT
CVolume::ExecFormat(
IN BSTR bstrObjPath,
IN WCHAR* pwszMethodName,
IN long lFlag,
IN IWbemClassObject* pParams,
IN IWbemObjectSink* pHandler)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ExecFormat");
CComPtr<IWbemClassObject> spOutParamClass;
_bstr_t bstrVolume;
CObjPath objPath;
DWORD rcStatus = ERROR_SUCCESS;
_bstr_t bstrFileSystem;
_bstr_t bstrLabel;
BOOL fQuickFormat = FALSE;
BOOL fEnableCompression = FALSE;
DWORD dwClusterSize = 0;
if (pParams == NULL)
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Volume::Format called with no parameters, hr<%#x>", ft.hr);
}
objPath.Init(bstrObjPath);
bstrVolume = objPath.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolume, WBEM_E_INVALID_OBJECT_PATH, L"ExecFormat: volume key property not found")
CWbemClassObject wcoInParam(pParams);
CWbemClassObject wcoOutParam;
// Get the parameters
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_QUICKFORMAT, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecFormat: FileSystem param is NULL")
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_ENABLECOMPRESSION, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecFormat: FileSystem param is NULL")
IF_PROP_NULL_THROW(wcoInParam, PVDR_PROP_CLUSTERSIZE, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecFormat: FileSystem param is NULL")
wcoInParam.GetProperty(bstrFileSystem, PVDR_PROP_FILESYSTEM);
IF_WSTR_NULL_THROW(bstrFileSystem, WBEM_E_INVALID_METHOD_PARAMETERS, L"ExecFormat: FileSystem param is NULL")
wcoInParam.GetProperty(&fQuickFormat, PVDR_PROP_QUICKFORMAT);
wcoInParam.GetProperty(&fEnableCompression, PVDR_PROP_ENABLECOMPRESSION);
wcoInParam.GetProperty(&dwClusterSize, PVDR_PROP_CLUSTERSIZE);
wcoInParam.GetProperty(bstrLabel, PVDR_PROP_LABEL);
if ((WCHAR*)bstrLabel == NULL) // non-NULL zero length label is OK
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"ExecFormat: Label param is NULL");
}
ft.hr = m_pClass->GetMethod(
_bstr_t(PVDR_MTHD_FORMAT),
0,
NULL,
&spOutParamClass
);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Format GetMethod failed, hr<%#x>", ft.hr);
// Create an out param object
ft.hr = spOutParamClass->SpawnInstance(0, &wcoOutParam);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
rcStatus = Format(
bstrVolume,
fQuickFormat,
fEnableCompression,
bstrFileSystem,
dwClusterSize,
bstrLabel,
pHandler
);
ft.hr = wcoOutParam.SetProperty(rcStatus, PVD_WBEM_PROP_RETURNVALUE);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SetProperty failed, hr<%#x>", ft.hr);
ft.hr = pHandler->Indicate( 1, wcoOutParam.dataPtr() );
return ft.hr;
}
DWORD
CVolume::AddMountPoint(
IN WCHAR* pwszVolume,
IN WCHAR* pwszDirectory
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::AddMountPoint");
DWORD rcStatus = MOUNTPOINT_RC_NO_ERROR;
_ASSERTE(pwszVolume != NULL);
_ASSERTE(pwszDirectory != NULL);
if (!SetVolumeMountPoint(pwszDirectory, pwszVolume))
{
switch(GetLastError())
{
case ERROR_FILE_NOT_FOUND:
rcStatus = MOUNTPOINT_RC_FILE_NOT_FOUND;
break;
case ERROR_DIR_NOT_EMPTY:
rcStatus = MOUNTPOINT_RC_DIRECTORY_NOT_EMPTY;
break;
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_NAME:
rcStatus = MOUNTPOINT_RC_INVALID_ARG;
break;
case ERROR_ACCESS_DENIED:
rcStatus = MOUNTPOINT_RC_ACCESS_DENIED;
break;
case ERROR_INVALID_FUNCTION:
rcStatus = MOUNTPOINT_RC_NOT_SUPPORTED;
break;
default:
rcStatus = GetLastError();
ft.Trace(VSSDBG_VSSADMIN, L"CVolume::AddMountPoint: SetVolumeMountPoint failed %#x", rcStatus);
}
}
return rcStatus;
}
DWORD
CVolume::Mount(
IN WCHAR* pwszVolume
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::Mount");
DWORD rcStatus = MOUNT_RC_NO_ERROR;
_ASSERTE(pwszVolume != NULL);
// Issue mount only for offline volumes. System will automount others on next IO
if (!VolumeIsMountable(pwszVolume))
{
DWORD cch;
HANDLE hVol;
BOOL bOnline = FALSE;
DWORD bytes;
cch = wcslen(pwszVolume);
pwszVolume[cch - 1] = 0;
hVol = CreateFile(pwszVolume, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
pwszVolume[cch - 1] = '\\';
if (hVol != INVALID_HANDLE_VALUE)
{
bOnline = DeviceIoControl(hVol, IOCTL_VOLUME_ONLINE, NULL, 0, NULL, 0, &bytes,
NULL);
CloseHandle(hVol);
if (!bOnline)
rcStatus = MOUNT_RC_UNEXPECTED;
}
else
{
switch(GetLastError())
{
case ERROR_FILE_NOT_FOUND:
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_NAME:
ft.hr = WBEM_E_NOT_FOUND;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolume::Mount: CreateFile failed %#x", GetLastError());
break;
case ERROR_ACCESS_DENIED:
rcStatus = MOUNT_RC_ACCESS_DENIED;
break;
default:
rcStatus = GetLastError();
ft.Trace(VSSDBG_VSSADMIN, L"CVolume::Mount: CreateFile failed %#x", rcStatus);
}
}
}
return rcStatus;
}
DWORD
CVolume::Dismount(
IN WCHAR* pwszVolume,
IN BOOL fForce,
IN BOOL fPermanent
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::Dismount");
DWORD rcStatus = DISMOUNT_RC_NO_ERROR;
HANDLE hVol = INVALID_HANDLE_VALUE;
_ASSERTE(pwszVolume != NULL);
try
{
// Issue dismount only for online volumes.
if (VolumeIsMountable(pwszVolume))
{
BOOL bIO = FALSE;
DWORD bytes;
DWORD cch;
cch = wcslen(pwszVolume);
pwszVolume[cch - 1] = 0;
hVol = CreateFile(pwszVolume, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
pwszVolume[cch - 1] = '\\';
if (hVol != INVALID_HANDLE_VALUE)
{
if (fPermanent) // Put the volume in an offline state
{
// Make sure there are no mount points for the volume
if (VolumeHasMountPoints(pwszVolume))
throw DISMOUNT_RC_VOLUME_HAS_MOUNT_POINTS;
// Make sure the volume supports ONLINE/OFFLINE
bIO = DeviceIoControl(hVol, IOCTL_VOLUME_SUPPORTS_ONLINE_OFFLINE, NULL, 0,
NULL, 0, &bytes, NULL);
if (!bIO)
throw DISMOUNT_RC_NOT_SUPPORTED;
// Lock the volume so that apps have a chance to dismount gracefully.
// If the LOCK fails, continue only if Force is specified.
bIO = DeviceIoControl(hVol, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL);
if (!fForce && !bIO)
throw DISMOUNT_RC_FORCE_OPTION_REQUIRED;
// Dismount the volume
bIO = DeviceIoControl(hVol, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytes, NULL);
if (!bIO)
throw DISMOUNT_RC_UNEXPECTED;
// Set the volume offline
bIO = DeviceIoControl(hVol, IOCTL_VOLUME_OFFLINE, NULL, 0, NULL, 0, &bytes, NULL);
if (!bIO)
throw DISMOUNT_RC_UNEXPECTED;
}
else
{
// Lock the volume so that apps have a chance to dismount gracefully.
// If the LOCK fails, continue only if Force is specified.
bIO = DeviceIoControl(hVol, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL);
if (!fForce && !bIO)
throw DISMOUNT_RC_FORCE_OPTION_REQUIRED;
bIO = DeviceIoControl(hVol, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytes, NULL);
if (!bIO)
throw DISMOUNT_RC_UNEXPECTED;
}
}
else
{
switch(GetLastError())
{
case ERROR_FILE_NOT_FOUND:
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_NAME:
ft.hr = WBEM_E_NOT_FOUND;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CVolume::Dismount: CreateFile failed %#x", GetLastError());
break;
case ERROR_ACCESS_DENIED:
rcStatus = DISMOUNT_RC_ACCESS_DENIED;
break;
default:
rcStatus = GetLastError();
ft.Trace(VSSDBG_VSSADMIN, L"CVolume::Dismount: CreateFile failed %#x", rcStatus);
}
}
}
}
catch (DISMOUNT_ERROR rcEx)
{
rcStatus = rcEx;
}
catch (...)
{
if (hVol != INVALID_HANDLE_VALUE)
CloseHandle(hVol);
throw;
}
if (hVol != INVALID_HANDLE_VALUE)
CloseHandle(hVol);
return rcStatus;
}
DWORD
CVolume::Defrag(
IN WCHAR* pwszVolume,
IN BOOL fForce,
IN IWbemObjectSink* pHandler,
IN OUT IWbemClassObject* pObject
)
{
DWORD rcStatus = DEFRAG_RC_NO_ERROR;
CComPtr<IFsuDefrag> spIDefrag;
CComPtr<IFsuAsync> spAsync;
HRESULT hrDefrag = E_FAIL;
DEFRAG_REPORT DefragReport;
BOOL fDirty = FALSE;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::Defrag");
_ASSERTE(pObject != NULL);
if (GetDriveType(pwszVolume) == DRIVE_REMOVABLE && !VolumeIsReady(pwszVolume))
return DEFRAG_RC_NOT_SUPPORTED;
VolumeIsDirty(pwszVolume, &fDirty);
if (fDirty)
return DEFRAG_RC_DIRTY_BIT_SET;
ft.hr = spIDefrag.CoCreateInstance(__uuidof(FsuDefrag));
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuDefrag CoCreateInstance failed, %#x", ft.hr);
ft.hr = spIDefrag->Defrag(
pwszVolume,
fForce,
&spAsync);
if (ft.HrFailed())
ft.Trace(VSSDBG_VSSADMIN, L"IFsuDefrag::Defrag failed, %#x", ft.hr);
hrDefrag = ft.hr;
if (ft.HrSucceeded())
{
do
{
ULONG ulPercentDone = 0;
ft.hr = spAsync->QueryStatus(&hrDefrag, &ulPercentDone);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuAsync::QueryStatus failed, %#x", ft.hr);
ft.hr = pHandler->SetStatus(
WBEM_STATUS_PROGRESS, // progress report
MAKELONG(ulPercentDone, 100), // LOWORD is work done so far, HIWORD is total work
NULL,
NULL);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Defrag: unable to set intermediate status, SetStatus returned %#x", ft.hr);
Sleep(200);
}
while (hrDefrag == E_PENDING);
ft.hr = spAsync->Wait(&hrDefrag);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuAsync::Wait failed, %#x", ft.hr);
}
if(SUCCEEDED(hrDefrag))
{
memset(&DefragReport, 0, sizeof(DefragReport));
ft.hr = spAsync->GetDefragReport(&DefragReport);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuAsync::GetDefragReport failed, %#x", ft.hr);
LoadDefragAnalysis(&DefragReport, pObject);
}
else
{
TranslateDefragError(hrDefrag, &rcStatus);
}
return rcStatus;
}
DWORD
CVolume::DefragAnalysis(
IN WCHAR* pwszVolume,
OUT BOOL* pfDefragRecommended,
IN OUT IWbemClassObject* pObject
)
{
DWORD rcStatus = DEFRAG_RC_NO_ERROR;
CComPtr<IFsuDefrag> spIDefrag;
CComPtr<IFsuAsync> spAsync;
HRESULT hrDefrag = E_FAIL;
DEFRAG_REPORT DefragReport;
BOOL fDirty = FALSE;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::DefragAnalysis");
_ASSERTE(pfDefragRecommended != NULL);
_ASSERTE(pObject != NULL);
*pfDefragRecommended = FALSE;
if (GetDriveType(pwszVolume) == DRIVE_REMOVABLE && !VolumeIsReady(pwszVolume))
return DEFRAG_RC_NOT_SUPPORTED;
VolumeIsDirty(pwszVolume, &fDirty);
if (fDirty)
return DEFRAG_RC_DIRTY_BIT_SET;
ft.hr = spIDefrag.CoCreateInstance(__uuidof(FsuDefrag));
//ft.hr = spIDefrag.CoCreateInstance(CLSID_Defrag);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IDefrag CoCreateInstance failed, %#x", ft.hr);
ft.hr = spIDefrag->DefragAnalysis(
pwszVolume,
&spAsync);
if (ft.HrFailed())
ft.Trace(VSSDBG_VSSADMIN, L"IDefrag::DefragAnalysis failed, %#x", ft.hr);
hrDefrag = ft.hr;
if (ft.HrSucceeded())
{
ft.hr = spAsync->Wait(&hrDefrag);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuAsync::Wait failed, %#x", ft.hr);
}
if(SUCCEEDED(hrDefrag))
{
memset(&DefragReport, 0, sizeof(DefragReport));
ft.hr = spAsync->GetDefragReport(&DefragReport);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuAsync::GetDefragReport failed, %#x", ft.hr);
//If the fragmentation on the disk exceeds 10% fragmentation, then recommend defragging.
if ((DefragReport.PercentDiskFragged + DefragReport.FreeSpaceFragPercent)/2 > 10)
{
*pfDefragRecommended = TRUE;
}
ft.Trace(VSSDBG_VSSADMIN, L"bDefragRecommended<%d>", *pfDefragRecommended);
LoadDefragAnalysis(&DefragReport, pObject);
}
else
{
TranslateDefragError(hrDefrag, &rcStatus);
}
return rcStatus;
}
DWORD
CVolume::Chkdsk(
IN WCHAR* pwszVolume,
IN BOOL fFixErrors,
IN BOOL fVigorousIndexCheck,
IN BOOL fSkipFolderCycle,
IN BOOL fForceDismount,
IN BOOL fRecoverBadSectors,
IN BOOL fOkToRunAtBootup
)
{
DWORD rcStatus = CHKDSK_RC_NO_ERROR;
DWORD dwThreadID = GetCurrentThreadId();
HINSTANCE hDLL = NULL;
CHKDSK_THREAD_DATA threadData;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::Chkdsk");
if (GetDriveType(pwszVolume) == DRIVE_REMOVABLE && !VolumeIsReady(pwszVolume))
return CHKDSK_RC_NO_MEDIA;
threadData.fOkToRunAtBootup = fOkToRunAtBootup;
threadData.rcStatus = rcStatus;
SetThreadData(dwThreadID, &threadData);
try
{
WCHAR wszFileSystem[g_cchFileSystemNameMax+1];
DWORD dwDontCare = 0;
PFMIFS_CHKDSKEX_ROUTINE ChkDskExRoutine = NULL;
FMIFS_CHKDSKEX_PARAM Param;
// Get the file system
if (!GetVolumeInformation(
pwszVolume,
NULL,
0,
&dwDontCare,
&dwDontCare,
&dwDontCare,
wszFileSystem,
g_cchFileSystemNameMax))
{
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"GetVolumeInformation failed for volume %lS, %#x", pwszVolume, GetLastError());
}
if (lstrcmpi(L"FAT", wszFileSystem) != 0 &&
lstrcmpi(L"FAT32", wszFileSystem) != 0 &&
lstrcmpi(L"NTFS", wszFileSystem) != 0)
{
rcStatus = CHKDSK_RC_UNSUPPORTED_FS;
}
else
{
// Load the chkdsk function
hDLL = LoadLibrary(L"fmifs.dll");
if (hDLL == NULL)
{
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Unable to load library fmifs.dll, %#x", GetLastError());
}
ChkDskExRoutine = (PFMIFS_CHKDSKEX_ROUTINE) GetProcAddress(hDLL, "ChkdskEx");
if (ChkDskExRoutine == NULL)
{
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"GetProcAddress failed for ChkdskEx, %#x", GetLastError());
}
Param.Major = 1;
Param.Minor = 0;
Param.Flags = 0; // For the Verbose Flag
Param.Flags |= fRecoverBadSectors ? FMIFS_CHKDSK_RECOVER : 0;
Param.Flags |= fForceDismount ? FMIFS_CHKDSK_FORCE : 0;
Param.Flags |= fVigorousIndexCheck ? FMIFS_CHKDSK_SKIP_INDEX_SCAN : 0;
Param.Flags |= fSkipFolderCycle ? FMIFS_CHKDSK_SKIP_CYCLE_SCAN : 0;
if (fRecoverBadSectors || fForceDismount)
{
fFixErrors = true;
}
// Return value captured in callback routine
ChkDskExRoutine (
pwszVolume,
wszFileSystem,
(BOOLEAN)fFixErrors,
&Param,
ChkdskCallback);
}
rcStatus = threadData.rcStatus;
}
catch (...)
{
RemoveThreadData(dwThreadID);
if (hDLL)
FreeLibrary(hDLL);
throw;
}
RemoveThreadData(dwThreadID);
if (hDLL)
FreeLibrary(hDLL);
return rcStatus;
}
#define VOLUME_GUID_PREFIX L"\\\\?\\Volume"
DWORD
CVolume::AutoChk(
IN const WCHAR* pwszAutoChkCommand,
IN WCHAR* pwmszVolumes
)
{
DWORD rcStatus = AUTOCHK_RC_NO_ERROR;
CCmdProcessor CmdProc;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::ScheduleAutoChk");
WCHAR* pwszCurrentVolume = NULL;
do
{
DWORD dwExecStatus = 0;
DWORD cchVolumes = 0;
// Validate the volumes
pwszCurrentVolume = pwmszVolumes;
while(true)
{
DWORD dwDriveType = 0;
// End of iteration?
LONG lCurrentVolumeLength = (LONG) ::wcslen(pwszCurrentVolume);
if (lCurrentVolumeLength < 1)
break;
WCHAR wcDrive = towupper(pwszCurrentVolume[0]);
// Drive letter, drive path or volume
if (wcslen(pwszCurrentVolume) < 2)
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Invalid volume name, %lS", pwszCurrentVolume);
}
if ((pwszCurrentVolume[1] == L':' && (wcDrive < L'A' || wcDrive > L'Z')) ||
(pwszCurrentVolume[1] != L':' &&_wcsnicmp(pwszCurrentVolume, VOLUME_GUID_PREFIX, wcslen(VOLUME_GUID_PREFIX)) != 0))
{
ft.hr = WBEM_E_INVALID_METHOD_PARAMETERS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Invalid volume name, %lS", pwszCurrentVolume);
}
dwDriveType = GetDriveType(pwszCurrentVolume);
switch (dwDriveType)
{
case DRIVE_REMOTE:
return AUTOCHK_RC_NETWORK_DRIVE;
case DRIVE_CDROM:
case DRIVE_REMOVABLE:
return AUTOCHK_RC_REMOVABLE_DRIVE;
case DRIVE_UNKNOWN:
return AUTOCHK_RC_UNKNOWN_DRIVE;
case DRIVE_NO_ROOT_DIR:
return AUTOCHK_RC_NOT_ROOT_DIRECTORY ;
case DRIVE_FIXED:
break;
default:
return AUTOCHK_RC_UNEXPECTED;
}
// Destroy the multi-sz as we go along, transforming it into the command line
// Last volume will have a trailing space character; the NULL that terminates
// the multi-sz will terminate the string; the calling function throws the multi-sz
// away without re-use anyway.
if (*(pwszCurrentVolume + lCurrentVolumeLength - 1) == L'\\')
*(pwszCurrentVolume + lCurrentVolumeLength - 1) = L' '; // remove trailing '\' if any
*(pwszCurrentVolume + lCurrentVolumeLength) = L' '; // change the intermediate NULL to a space.
cchVolumes += lCurrentVolumeLength + 1; // add one for the space (was term-NULL)
// Go to the next one. Skip the zero character.
pwszCurrentVolume += lCurrentVolumeLength + 1;
}
// Allocate and build the command line
CVssAutoPWSZ awszCommand;
DWORD cchCommand = wcslen(pwszAutoChkCommand) + cchVolumes + 1;
awszCommand.Allocate(cchCommand); // internally accounts for terminating NULL
ft.hr = StringCchPrintf(awszCommand, cchCommand+1, L"%s %s", pwszAutoChkCommand, pwmszVolumes);
ft.hr = CmdProc.InitializeAsClient(L"chkntfs.exe", awszCommand);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CCmdProcessor::InitializeAsClient failed, %#x", ft.hr);
ft.hr = CmdProc.LaunchProcess();
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CCmdProcessor::LaunchProcess failed, %#x", ft.hr);
do
{
ft.hr = CmdProc.Wait(200, &dwExecStatus);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CCmdProcessor::Wait failed, %#x", ft.hr);
} while (dwExecStatus == STILL_ACTIVE);
if (dwExecStatus != ERROR_SUCCESS)
{
rcStatus = AUTOCHK_RC_UNEXPECTED;
}
}
while (false);
return rcStatus;
}
DWORD
CVolume::Format(
IN WCHAR* pwszVolume,
IN BOOL fQuickFormat,
IN BOOL fEnableCompression,
IN WCHAR* pwszFileSystem,
IN DWORD cbClusterSize,
IN WCHAR* pwszLabel,
IN IWbemObjectSink* pHandler
)
{
DWORD rcStatus = FORMAT_RC_NO_ERROR;
HRESULT hrStatus = E_UNEXPECTED;
CComPtr<IFsuFormat> spIFormat;
CComPtr<IFsuAsync> spAsync;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::Format");
_ASSERTE(pwszVolume != NULL);
_ASSERTE(pwszFileSystem != NULL);
_ASSERTE(pwszLabel != NULL);
if (GetDriveType(pwszVolume) == DRIVE_REMOVABLE && !VolumeIsReady(pwszVolume))
return FORMAT_RC_NO_MEDIA;
ft.hr = spIFormat.CoCreateInstance(__uuidof(FsuFormat));
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuFormat CoCreateInstance failed, %#x", ft.hr);
ft.hr = spIFormat->Format(
pwszVolume,
pwszFileSystem,
pwszLabel,
fQuickFormat,
fEnableCompression,
cbClusterSize,
&spAsync);
if (ft.HrFailed())
ft.Trace(VSSDBG_VSSADMIN, L"IFsuFormat::Format failed, %#x", ft.hr);
hrStatus = ft.hr;
if (ft.HrSucceeded())
{
do
{
ULONG ulPercentDone = 0;
ft.hr = spAsync->QueryStatus(&hrStatus, &ulPercentDone);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuAsync::QueryStatus failed, %#x", ft.hr);
ft.hr = pHandler->SetStatus(
WBEM_STATUS_PROGRESS, // progress report
MAKELONG(ulPercentDone, 100), // LOWORD is work done so far, HIWORD is total work
NULL,
NULL);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"Format: unable to set intermediate status, SetStatus returned %#x", ft.hr);
Sleep(200);
}
while (hrStatus == E_PENDING);
ft.hr = spAsync->Wait(&hrStatus);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"IFsuAsync::Wait failed, %#x", ft.hr);
}
switch (hrStatus)
{
case S_OK:
rcStatus = FORMAT_RC_NO_ERROR;
break;
case E_ACCESSDENIED:
rcStatus = FORMAT_RC_ACCESS_DENIED;
break;
case E_ABORT:
rcStatus = FORMAT_RC_CALL_CANCELLED;
break;
case FMT_E_UNSUPPORTED_FS:
rcStatus = FORMAT_RC_UNSUPPORTED_FS;
break;
case FMT_E_CANT_QUICKFORMAT:
rcStatus = FORMAT_RC_CANT_QUICKFORMAT;
break;
case FMT_E_CANCEL_TOO_LATE:
rcStatus = FORMAT_RC_CANCEL_TOO_LATE;
break;
case FMT_E_IO_ERROR:
rcStatus = FORMAT_RC_IO_ERROR;
break;
case FMT_E_BAD_LABEL:
rcStatus = FORMAT_RC_BAD_LABEL;
break;
case FMT_E_INCOMPATIBLE_MEDIA:
rcStatus = FORMAT_RC_INCOMPATIBLE_MEDIA;
break;
case FMT_E_WRITE_PROTECTED:
rcStatus = FORMAT_RC_WRITE_PROTECTED;
break;
case FMT_E_CANT_LOCK:
rcStatus = FORMAT_RC_CANT_LOCK;
break;
case FMT_E_NO_MEDIA:
rcStatus = FORMAT_RC_NO_MEDIA;
break;
case FMT_E_VOLUME_TOO_SMALL:
rcStatus = FORMAT_RC_VOLUME_TOO_SMALL;
break;
case FMT_E_VOLUME_TOO_BIG:
rcStatus = FORMAT_RC_VOLUME_TOO_BIG;
break;
case FMT_E_VOLUME_NOT_MOUNTED:
rcStatus = FORMAT_RC_VOLUME_NOT_MOUNTED;
break;
case FMT_E_CLUSTER_SIZE_TOO_SMALL:
rcStatus = FORMAT_RC_CLUSTER_SIZE_TOO_SMALL;
break;
case FMT_E_CLUSTER_SIZE_TOO_BIG:
rcStatus = FORMAT_RC_CLUSTER_SIZE_TOO_BIG;
break;
case FMT_E_CLUSTER_COUNT_BEYOND_32BITS:
rcStatus = FORMAT_RC_CLUSTER_COUNT_BEYOND_32BITS;
break;
default:
rcStatus = FORMAT_RC_UNEXPECTED;
}
return rcStatus;
}
//****************************************************************************
//
// CMountPoint
//
//****************************************************************************
CMountPoint::CMountPoint(
IN LPCWSTR pwszName,
IN CWbemServices* pNamespace
)
: CProvBase(pwszName, pNamespace)
{
} //*** CMountPoint::CMountPoint()
CProvBase *
CMountPoint::S_CreateThis(
IN LPCWSTR pwszName,
IN CWbemServices* pNamespace
)
{
HRESULT hr = WBEM_E_FAILED;
CMountPoint * pObj= NULL;
pObj = new CMountPoint(pwszName, pNamespace);
if (pObj)
{
hr = pObj->Initialize();
}
else
{
hr = E_OUTOFMEMORY;
}
if (FAILED(hr))
{
delete pObj;
pObj = NULL;
}
return pObj;
} //*** CMountPoint::S_CreateThis()
HRESULT
CMountPoint::Initialize()
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CMountPoint::Initialize");
return ft.hr;
}
HRESULT
CMountPoint::EnumInstance(
IN long lFlags,
IN IWbemContext* pCtx,
IN IWbemObjectSink * pHandler
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CMountPoint::EnumInstance");
CVssAutoPWSZ awszVolume;
try
{
awszVolume.Allocate(MAX_PATH);
CVssVolumeIterator volumeIterator;
while (true)
{
CVssAutoPWSZ awszMountPoints;
WCHAR* pwszCurrentMountPoint = NULL;
// Get the volume name
if (!volumeIterator.SelectNewVolume(ft, awszVolume, MAX_PATH))
break;
// Get the list of all mount points
// Get the length of the multi-string array
DWORD cchVolumesBufferLen = 0;
BOOL bResult = GetVolumePathNamesForVolumeName(awszVolume, NULL, 0, &cchVolumesBufferLen);
if (!bResult && (GetLastError() != ERROR_MORE_DATA))
ft.TranslateGenericError(VSSDBG_VSSADMIN, HRESULT_FROM_WIN32(GetLastError()),
L"GetVolumePathNamesForVolumeName(%s, 0, 0, %p)", (LPWSTR)awszVolume, &cchVolumesBufferLen);
// Allocate the array
awszMountPoints.Allocate(cchVolumesBufferLen);
// Get the mount points
// Note: this API was introduced in WinXP so it will need to be replaced if backported
bResult = GetVolumePathNamesForVolumeName(awszVolume, awszMountPoints, cchVolumesBufferLen, NULL);
if (!bResult)
ft.Throw(VSSDBG_VSSADMIN, HRESULT_FROM_WIN32(GetLastError()),
L"GetVolumePathNamesForVolumeName(%s, %p, %lu, 0)", (LPWSTR)awszVolume, awszMountPoints, cchVolumesBufferLen);
// If the volume has mount points
pwszCurrentMountPoint = awszMountPoints;
if ( pwszCurrentMountPoint[0] )
{
while(true)
{
CComPtr<IWbemClassObject> spInstance;
// End of iteration?
LONG lCurrentMountPointLength = (LONG) ::wcslen(pwszCurrentMountPoint);
if (lCurrentMountPointLength == 0)
break;
ft.hr = m_pClass->SpawnInstance(0, &spInstance);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
// Only a root directory should have a trailing backslash character
if (lCurrentMountPointLength > 2 &&
pwszCurrentMountPoint[lCurrentMountPointLength-1] == L'\\' &&
pwszCurrentMountPoint[lCurrentMountPointLength-2] != L':')
{
pwszCurrentMountPoint[lCurrentMountPointLength-1] = L'\0';
}
LoadInstance(awszVolume, pwszCurrentMountPoint, spInstance.p);
ft.hr = pHandler->Indicate(1, &spInstance.p);
// Go to the next one. Skip the zero character.
pwszCurrentMountPoint += lCurrentMountPointLength + 1;
}
}
}
}
catch (HRESULT hrEx)
{
ft.hr = hrEx;
}
return ft.hr;
} //*** CMountPoint::EnumInstance()
HRESULT
CMountPoint::GetObject(
IN CObjPath& rObjPath,
IN long lFlags,
IN IWbemContext* pCtx,
IN IWbemObjectSink* pHandler
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CMountPoint::GetObject");
try
{
_bstr_t bstrVolumeRef, bstrVolumeName;
_bstr_t bstrDirectoryRef, bstrDirectoryName;
CObjPath objPathVolume;
CObjPath objPathDirectory;
CVssAutoPWSZ awszMountPoints;
WCHAR* pwszCurrentMountPoint = NULL;
BOOL fFound = FALSE;
CComPtr<IWbemClassObject> spInstance;
// Get the Volume reference
bstrVolumeRef = rObjPath.GetStringValueForProperty(PVDR_PROP_VOLUME);
IF_WSTR_NULL_THROW(bstrVolumeRef, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint volume key property not found")
// Get the Directory reference
bstrDirectoryRef = rObjPath.GetStringValueForProperty(PVDR_PROP_DIRECTORY);
IF_WSTR_NULL_THROW(bstrDirectoryRef, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint directory key property not found")
// Extract the Volume and Directory Names
objPathVolume.Init(bstrVolumeRef);
objPathDirectory.Init(bstrDirectoryRef);
bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolumeName, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint volume key property DeviceID not found")
bstrDirectoryName = objPathDirectory.GetStringValueForProperty(PVDR_PROP_NAME);
IF_WSTR_NULL_THROW(bstrDirectoryName, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint directory key property Name not found")
if (VolumeMountPointExists(bstrVolumeName, bstrDirectoryName))
{
CComPtr<IWbemClassObject> spInstance;
ft.hr = m_pClass->SpawnInstance(0, &spInstance);
if (ft.HrFailed())
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"SpawnInstance failed, hr<%#x>", ft.hr);
LoadInstance(bstrVolumeName, bstrDirectoryName, spInstance.p);
ft.hr = pHandler->Indicate(1, &spInstance.p);
}
else
{
ft.hr = WBEM_E_NOT_FOUND;
}
}
catch (HRESULT hrEx)
{
ft.hr = hrEx;
}
return ft.hr;
} //*** CMountPoint::GetObject()
void
CMountPoint:: LoadInstance(
IN WCHAR* pwszVolume,
IN WCHAR* pwszDirectory,
IN OUT IWbemClassObject* pObject)
{
CWbemClassObject wcoInstance(pObject);
CObjPath pathDirectory;
CObjPath pathVolume;
_ASSERTE(pwszVolume != NULL);
_ASSERTE(pwszDirectory != NULL);
// Set the Directory Ref property
pathDirectory.Init(PVDR_CLASS_DIRECTORY);
pathDirectory.AddProperty(PVDR_PROP_NAME, pwszDirectory);
wcoInstance.SetProperty((wchar_t*)pathDirectory.GetObjectPathString(), PVDR_PROP_DIRECTORY);
// Set the Volume Ref property
pathVolume.Init(PVDR_CLASS_VOLUME);
pathVolume.AddProperty(PVDR_PROP_DEVICEID, pwszVolume);
wcoInstance.SetProperty((wchar_t*)pathVolume.GetObjectPathString(), PVDR_PROP_VOLUME);
}
HRESULT
CMountPoint::PutInstance(
IN CWbemClassObject& rInstToPut,
IN long lFlag,
IN IWbemContext* pCtx,
IN IWbemObjectSink* pHandler
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CMountPoint::PutInstance");
try
{
_bstr_t bstrVolumeRef, bstrVolumeName;
_bstr_t bstrDirectoryRef, bstrDirectoryName;
CObjPath objPathVolume;
CObjPath objPathDirectory;
if ( lFlag & WBEM_FLAG_UPDATE_ONLY )
{
return WBEM_E_UNSUPPORTED_PARAMETER ;
}
// Retrieve key properties of the object to be saved.
rInstToPut.GetProperty(bstrVolumeRef, PVDR_PROP_VOLUME);
IF_WSTR_NULL_THROW(bstrVolumeRef, WBEM_E_INVALID_OBJECT, L"MountPoint volume key property not found")
rInstToPut.GetProperty(bstrDirectoryRef, PVDR_PROP_DIRECTORY);
IF_WSTR_NULL_THROW(bstrDirectoryRef, WBEM_E_INVALID_OBJECT, L"MountPoint directory key property not found")
// Extract the Volume and Directory Names
objPathVolume.Init(bstrVolumeRef);
objPathDirectory.Init(bstrDirectoryRef);
bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolumeName, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint volume key property DeviceID not found")
bstrDirectoryName = objPathDirectory.GetStringValueForProperty(PVDR_PROP_NAME);
IF_WSTR_NULL_THROW(bstrDirectoryName, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint directory key property Name not found")
ft.Trace(VSSDBG_VSSADMIN, L"CMountPoint::PutInstance Volume<%lS> Directory<%lS>",
(WCHAR*)bstrVolumeName, (WCHAR*)bstrDirectoryName);
if (VolumeMountPointExists(bstrVolumeName, bstrDirectoryName))
{
ft.hr = WBEM_E_ALREADY_EXISTS;
ft.Throw(VSSDBG_VSSADMIN, ft.hr, L"CMountPoint:PutInstance mount point already exists");
}
// Only root directories have the trailing backslash; fix the others
WCHAR* pwszDirectoryName = bstrDirectoryName;
if (pwszDirectoryName[wcslen(bstrDirectoryName) -1] != L'\\')
bstrDirectoryName += _bstr_t(L"\\");
if (!SetVolumeMountPoint(bstrDirectoryName, bstrVolumeName))
{
switch(GetLastError())
{
case ERROR_FILE_NOT_FOUND:
case ERROR_DIR_NOT_EMPTY:
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_NAME:
ft.hr = WBEM_E_INVALID_PARAMETER;
break;
case ERROR_ACCESS_DENIED:
ft.hr = WBEM_E_ACCESS_DENIED;
break;
case ERROR_INVALID_FUNCTION:
ft.hr = WBEM_E_NOT_SUPPORTED;
break;
default:
ft.hr = HRESULT_FROM_WIN32(GetLastError());
ft.Trace(VSSDBG_VSSADMIN, L"C MountPoint: PutInstance: SetVolumeMountPoint failed %#x", ft.hr);
}
}
}
catch (HRESULT hrEx)
{
ft.hr = hrEx;
}
return ft.hr;
}
HRESULT
CMountPoint::DeleteInstance(
IN CObjPath& rObjPath,
IN long lFlag,
IN IWbemContext* pCtx,
IN IWbemObjectSink* pHandler
)
{
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CMountPoint::DeleteInstance");
try
{
_bstr_t bstrVolumeRef, bstrVolumeName;
_bstr_t bstrDirectoryRef, bstrDirectoryName;
CObjPath objPathVolume;
CObjPath objPathDirectory;
// Get the Volume reference
bstrVolumeRef = rObjPath.GetStringValueForProperty(PVDR_PROP_VOLUME);
IF_WSTR_NULL_THROW(bstrVolumeRef, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint volume key property not found")
// Get the Directory reference
bstrDirectoryRef = rObjPath.GetStringValueForProperty(PVDR_PROP_DIRECTORY);
IF_WSTR_NULL_THROW(bstrDirectoryRef, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint directory key property not found")
// Extract the Volume and Directory Names
objPathVolume.Init(bstrVolumeRef);
objPathDirectory.Init(bstrDirectoryRef);
bstrVolumeName = objPathVolume.GetStringValueForProperty(PVDR_PROP_DEVICEID);
IF_WSTR_NULL_THROW(bstrVolumeName, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint volume key property DeviceID not found")
bstrDirectoryName = objPathDirectory.GetStringValueForProperty(PVDR_PROP_NAME);
IF_WSTR_NULL_THROW(bstrDirectoryName, WBEM_E_INVALID_OBJECT_PATH, L"MountPoint directory key property Name not found")
ft.Trace(VSSDBG_VSSADMIN, L"CMountPoint::DeleteInstance Volume<%lS> Directory<%lS>",
(WCHAR*)bstrVolumeName, (WCHAR*)bstrDirectoryName);
// Only root directories have the trailing backslash; fix the others
WCHAR* pwszDirectoryName = bstrDirectoryName;
if (pwszDirectoryName[wcslen(bstrDirectoryName) -1] != L'\\')
bstrDirectoryName += _bstr_t(L"\\");
if (!DeleteVolumeMountPoint(bstrDirectoryName))
ft.Throw(VSSDBG_VSSADMIN, HRESULT_FROM_WIN32(GetLastError()), L"DeleteVolumeMountPoint failed %#x", GetLastError());
}
catch (HRESULT hrEx)
{
ft.hr = hrEx;
}
return ft.hr;
}
void
LoadDefragAnalysis(
IN DEFRAG_REPORT* pDefragReport,
IN OUT IWbemClassObject* pObject)
{
DWORD dwPercent = 0;
CVssFunctionTracer ft(VSSDBG_VSSADMIN, L"CVolume::LoadDefragAnalysis");
_ASSERTE(pDefragReport != NULL);
_ASSERTE(pObject != NULL);
CWbemClassObject wcoInstance(pObject);
ft.Trace(VSSDBG_VSSADMIN, L"PercentDiskFragged<%d>", pDefragReport->PercentDiskFragged);
ft.Trace(VSSDBG_VSSADMIN, L"FreeSpaceFragPercent<%d>", pDefragReport->FreeSpaceFragPercent);
ft.Trace(VSSDBG_VSSADMIN, L"FreeSpacePercent<%d>", pDefragReport->FreeSpacePercent);
// General volume properties
wcoInstance.SetPropertyI64(pDefragReport->DiskSize, PVDR_PROP_VOLUMESIZE);
wcoInstance.SetPropertyI64(pDefragReport->BytesPerCluster, PVDR_PROP_CLUSTERSIZE);
wcoInstance.SetPropertyI64(pDefragReport->UsedSpace, PVDR_PROP_USEDSPACE);
wcoInstance.SetPropertyI64(pDefragReport->FreeSpace, PVDR_PROP_FREESPACE);
wcoInstance.SetProperty(pDefragReport->FreeSpacePercent, PVDR_PROP_FRAGFREEPCT);
// Volume fragmentation
dwPercent = ((pDefragReport->PercentDiskFragged + pDefragReport->FreeSpaceFragPercent)/2);
wcoInstance.SetProperty(dwPercent, PVDR_PROP_FRAGTOTALPCT);
wcoInstance.SetProperty(pDefragReport->PercentDiskFragged, PVDR_PROP_FILESFRAGPCT);
wcoInstance.SetProperty(pDefragReport->FreeSpaceFragPercent, PVDR_PROP_FREEFRAGPCT);
// File fragmentation
wcoInstance.SetPropertyI64(pDefragReport->TotalFiles, PVDR_PROP_FILESTOTAL);
wcoInstance.SetPropertyI64(pDefragReport->AvgFileSize, PVDR_PROP_FILESIZEAVG);
wcoInstance.SetPropertyI64(pDefragReport->NumFraggedFiles, PVDR_PROP_FILESFRAGTOTAL);
wcoInstance.SetPropertyI64(pDefragReport->NumExcessFrags, PVDR_PROP_EXCESSFRAGTOTAL);
// IDefrag interface currently reports this statistic per 100 files
double dblAvgFragsPerFile = (double)(pDefragReport->AvgFragsPerFile)/100.0;
wcoInstance.SetPropertyR64(dblAvgFragsPerFile, PVDR_PROP_FILESFRAGAVG);
// Pagefile fragmentation
wcoInstance.SetPropertyI64(pDefragReport->PagefileBytes, PVDR_PROP_PAGEFILESIZE);
wcoInstance.SetPropertyI64(pDefragReport->PagefileFrags, PVDR_PROP_PAGEFILEFRAG);
// Folder fragmentation
wcoInstance.SetPropertyI64(pDefragReport->TotalDirectories, PVDR_PROP_FOLDERSTOTAL);
wcoInstance.SetPropertyI64(pDefragReport->FragmentedDirectories, PVDR_PROP_FOLDERSFRAG);
wcoInstance.SetPropertyI64(pDefragReport->ExcessDirFrags, PVDR_PROP_FOLDERSFRAGEXCESS);
// Master File Table fragmentation
wcoInstance.SetPropertyI64(pDefragReport->MFTBytes, PVDR_PROP_MFTSIZE);
wcoInstance.SetPropertyI64(pDefragReport->InUseMFTRecords, PVDR_PROP_MFTRECORDS);
dwPercent = pDefragReport->TotalMFTRecords?(100*pDefragReport->InUseMFTRecords/pDefragReport->TotalMFTRecords):0;
wcoInstance.SetProperty(dwPercent, PVDR_PROP_MFTINUSEPCT);
wcoInstance.SetPropertyI64(pDefragReport->MFTExtents, PVDR_PROP_MFTFRAGTOTAL);
}
void
TranslateDefragError(
IN HRESULT hr,
OUT DWORD* pdwError)
{
_ASSERTE(pdwError != NULL);
if (hr == HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED))
*pdwError = DEFRAG_RC_NOT_SUPPORTED;
else
{
switch (hr)
{
case DFRG_E_LOW_FREESPACE:
*pdwError = DEFRAG_RC_LOW_FREESPACE;
break;
case DFRG_E_CORRUPT_MFT:
*pdwError = DEFRAG_RC_CORRUPT_MFT;
break;
case E_ABORT:
*pdwError = DEFRAG_RC_CALL_CANCELLED;
break;
case DFRG_E_CANCEL_TOO_LATE:
*pdwError = DEFRAG_RC_CANCEL_TOO_LATE;
break;
case DFRG_E_ALREADY_RUNNING:
*pdwError = DEFRAG_RC_ALREADY_RUNNING;
break;
case DFRG_E_ENGINE_CONNECT:
*pdwError = DEFRAG_RC_ENGINE_CONNECT;
break;
case DFRG_E_ENGINE_ERROR:
*pdwError = DEFRAG_RC_ENGINE_ERROR;
break;
default:
*pdwError = DEFRAG_RC_UNEXPECTED;
}
}
}