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
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|