////////////////////////////////////////////////////////////////////////////// // // 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 #include #include "VdsClasses.h" #include "ichannel.hxx" #include #define INITGUIDS #include #include #include #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 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 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 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 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 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 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 spOutParamClass; CComPtr 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 spOutParamClass; CComPtr 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 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 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 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 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 spIDefrag; CComPtr 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 spIDefrag; CComPtr 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 spIFormat; CComPtr 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 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 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 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; } } }