windows-nt/Source/XPSP1/NT/base/fs/hsm/cli/clivol.cpp
2020-09-26 16:20:57 +08:00

1722 lines
55 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
clivol.cpp
Abstract:
Implements CLI VOLUME sub-interface
Author:
Ran Kalach [rankala] 3-March-2000
Revision History:
--*/
#include "stdafx.h"
#include "HsmConn.h"
#include "fsa.h"
#include "job.h"
static GUID g_nullGuid = GUID_NULL;
// Internal utilities and classes for VOLUME interface
HRESULT SetResourceParams(IN IFsaResource *pResource, IN DWORD dwDfs, IN DWORD dwSize, IN DWORD dwAccess,
IN LPWSTR pRulePath, IN LPWSTR pRuleFileSpec, IN BOOL bInclude, IN BOOL bRecursive,
IN BOOL bSetDefaults);
HRESULT ShowResourceParams(IN IFsaResource *pResource, IN BOOL bDfs, IN BOOL bSize,
IN BOOL bAccess, IN BOOL bRules, IN BOOL bStatistics);
HRESULT FindAndDeleteRule(IN IFsaResource *pResource, IN LPWSTR pRulePath, IN LPWSTR pRuleFileSpec, IN BOOL bDelete);
HRESULT StartJob(IN IFsaResource *pResource, IN HSM_JOB_TYPE Job, IN BOOL bWait);
HRESULT CancelJob(IN IFsaResource *pResource, IN HSM_JOB_TYPE Job);
HRESULT QuickUnmanage(IN IFsaResource *pResource);
HRESULT CreateJobName(IN HSM_JOB_TYPE Job, IN IFsaResource *pResource, OUT WCHAR **pJobName);
#define CVOL_INVALID_INDEX (-1)
class CVolumeEnum
{
// Constructors
public:
CVolumeEnum(IN LPWSTR *pVolumes, IN DWORD dwNumberOfVolumes, IN BOOL bSkipUnavailable = TRUE);
// Public methods
public:
HRESULT First(OUT IFsaResource **ppResource);
HRESULT Next(OUT IFsaResource **ppResource);
HRESULT ErrorVolume(OUT int *pIndex);
// Private data
protected:
LPWSTR *m_pVolumes;
DWORD m_dwNumberOfVolumes;
// If * enumeration or not
BOOL m_bAllVols;
CComPtr<IWsbEnum> m_pEnumResources;
// Used only when m_bAllVols == FALSE
int m_nCurrent;
BOOL m_bInvalidVol;
// Used only when m_bAllVols == TRUE
BOOL m_bSkipUnavailable;
};
inline
HRESULT CVolumeEnum::ErrorVolume(OUT int *pIndex)
{
HRESULT hr = S_FALSE;
if (m_bInvalidVol) {
// There was an error with last volume
hr = S_OK;
}
*pIndex = m_nCurrent;
return(hr);
}
//
// VOLUME inetrafce implementors
//
HRESULT
VolumeManage(
IN LPWSTR *Volumes,
IN DWORD NumberOfVolumes,
IN DWORD Dfs,
IN DWORD Size,
IN DWORD Access,
IN LPWSTR RulePath,
IN LPWSTR RuleFileSpec,
IN BOOL Include,
IN BOOL Recursive
)
/*++
Routine Description:
Sets volume(s) to be managed by HSM
Arguments:
Volumes - List of volumes to manage
NumberOfVolumes - List size
Dfs - Desired free space
Size - Minimal size to manage
Access - Minimal not-accessed time (in days)
RulePath - Path for the rule
RuleFileSpec - File specification for the rule
Include - Is this an include or exclude rule
Recursive - Is the rule recursive or not
Return Value:
S_OK - If all the volumes are added to the managed list
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("VolumeManage"), OLESTR(""));
try {
CComPtr<IFsaResource> pResource;
CWsbStringPtr param;
CComPtr<IHsmServer> pHsm;
CComPtr<IWsbCreateLocalObject> pCreateObj;
CComPtr<IWsbIndexedCollection> pMRCollection;
// Verify that input parameters are valid
if (0 == NumberOfVolumes) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(E_INVALIDARG);
}
WsbAffirmHr(ValidateLimitsArg(Dfs, IDS_DFS, HSMADMIN_MIN_FREESPACE, HSMADMIN_MAX_FREESPACE));
WsbAffirmHr(ValidateLimitsArg(Size, IDS_MIN_SIZE, HSMADMIN_MIN_MINSIZE, HSMADMIN_MAX_MINSIZE));
WsbAffirmHr(ValidateLimitsArg(Access, IDS_NOT_ACCESSED, HSMADMIN_MIN_INACTIVITY, HSMADMIN_MAX_INACTIVITY));
if (INVALID_POINTER_ARG != RuleFileSpec) {
// Must have a rule path then
if (INVALID_POINTER_ARG == RulePath) {
WsbTraceAndPrint(CLI_MESSAGE_INVALID_RULE, NULL);
WsbThrow(E_INVALIDARG);
}
}
// Get necessary objects
WsbAffirmHr(HsmConnectFromId(HSMCONN_TYPE_HSM, g_nullGuid, IID_IHsmServer, (void**)&pHsm));
WsbAffirmHr(pHsm->QueryInterface(IID_IWsbCreateLocalObject, (void**) &pCreateObj));
WsbAffirmHr(pHsm->GetManagedResources(&pMRCollection));
// Initialize an enumerator object
CVolumeEnum volEnum(Volumes, NumberOfVolumes);
hr = volEnum.First(&pResource);
if (WSB_E_NOTFOUND == hr) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(hr);
} else if (S_OK != hr) {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
while(S_OK == hr) {
CComPtr<IHsmManagedResource> pManagedResource;
CComPtr<IHsmManagedResource> pFoundResource;
// Find out if the volume is the Engine's managed resources list, if not - add it
WsbAffirmHr(pCreateObj->CreateInstance(CLSID_CHsmManagedResource, IID_IHsmManagedResource, (void**) &pManagedResource));
WsbAffirmHr(pManagedResource->InitFromFsaResource(pResource));
hr = pMRCollection->Find(pManagedResource, IID_IHsmManagedResource, (void**) &pFoundResource);
if (WSB_E_NOTFOUND == hr) {
// Add it
WsbAffirmHr(pMRCollection->Add(pManagedResource));
} else {
// Verify no other error
WsbAffirmHr(hr);
// No other error: notify the user that parameters will still be set for the already managed volume
CWsbStringPtr volName;
WsbAffirmHr(CliGetVolumeDisplayName(pResource, &volName));
WsbTraceAndPrint(CLI_MESSAGE_ONLY_SET, (WCHAR *)volName, NULL);
}
// Set the parameters (whether it was managed before or not)
WsbAffirmHr(SetResourceParams(pResource, Dfs, Size, Access, RulePath,
RuleFileSpec, Include, Recursive, TRUE));
pManagedResource = 0;
pFoundResource = 0;
pResource = 0;
hr = volEnum.Next(&pResource);
}
if (WSB_E_NOTFOUND == hr) {
hr = S_OK;
} else {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbAssert(CVOL_INVALID_INDEX != index, E_UNEXPECTED);
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("VolumeManage"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return hr;
}
HRESULT
VolumeUnmanage(
IN LPWSTR *Volumes,
IN DWORD NumberOfVolumes,
IN BOOL Full
)
/*++
Routine Description:
Unmanage volume(s)
Arguments:
Volumes - List of volumes to manage
NumberOfVolumes - List size
Full - If TRUE, run unmanage job which recalls all the files back
- If FALSE, just remove volume from the managed volumes list.
Return Value:
S_OK - If all the volumes are unmanaged successfully
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("VolumeUnmanage"), OLESTR(""));
try {
CComPtr<IFsaResource> pResource;
// Verify that input parameters are valid
if (0 == NumberOfVolumes) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(E_INVALIDARG);
}
// Initialize an enumerator object
// Eumerate also unavailable volumes
CVolumeEnum volEnum(Volumes, NumberOfVolumes, FALSE);
hr = volEnum.First(&pResource);
if (WSB_E_NOTFOUND == hr) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(hr);
} else if (S_OK != hr) {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
while(S_OK == hr) {
if (pResource->IsManaged() == S_OK) {
BOOL bForceQuick = FALSE;
// If it is an unavailable volume, must set a quick unmanage
if (S_OK != pResource->IsAvailable()) {
bForceQuick = TRUE;
}
// Unmanage the volume
if (Full && (! bForceQuick)) {
WsbAffirmHr(StartJob(pResource, Unmanage, FALSE));
} else {
WsbAffirmHr(QuickUnmanage(pResource));
}
} else {
int index;
volEnum.ErrorVolume(&index);
if (CVOL_INVALID_INDEX != index) {
// invalid input from user
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
WsbThrow(E_INVALIDARG);
} else {
// just skip the volume...
}
}
pResource = 0;
hr = volEnum.Next(&pResource);
}
if (WSB_E_NOTFOUND == hr) {
hr = S_OK;
} else {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("VolumeUnmanage"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return hr;
}
HRESULT
VolumeSet(
IN LPWSTR *Volumes,
IN DWORD NumberOfVolumes,
IN DWORD Dfs,
IN DWORD Size,
IN DWORD Access,
IN LPWSTR RulePath,
IN LPWSTR RuleFileSpec,
IN BOOL Include,
IN BOOL Recursive
)
/*++
Routine Description:
Sets parameters for volume(s) which are already managed by HSM
Arguments:
Volumes - List of volumes to manage
NumberOfVolumes - List size
Dfs - Desired free space
Size - Minimal size to manage
Access - Minimal not-accessed time (in days)
RulePath - Path for the rule
RuleFileSpec - File specification for the rule
Include - Is this an include or exclude rule
Recursive - Is the rule recursive or not
Return Value:
S_OK - If all the parameters are set for all the volumes
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("VolumeSet"), OLESTR(""));
try {
CComPtr<IFsaResource> pResource;
CWsbStringPtr param;
// Verify that input parameters are valid
if (0 == NumberOfVolumes) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(E_INVALIDARG);
}
WsbAffirmHr(ValidateLimitsArg(Dfs, IDS_DFS, HSMADMIN_MIN_FREESPACE, HSMADMIN_MAX_FREESPACE));
WsbAffirmHr(ValidateLimitsArg(Size, IDS_MIN_SIZE, HSMADMIN_MIN_MINSIZE, HSMADMIN_MAX_MINSIZE));
WsbAffirmHr(ValidateLimitsArg(Access, IDS_NOT_ACCESSED, HSMADMIN_MIN_INACTIVITY, HSMADMIN_MAX_INACTIVITY));
if (INVALID_POINTER_ARG != RuleFileSpec) {
// Must have a rule path then
if (INVALID_POINTER_ARG == RulePath) {
WsbTraceAndPrint(CLI_MESSAGE_INVALID_RULE, NULL);
WsbThrow(E_INVALIDARG);
}
}
// Initialize an enumerator object
CVolumeEnum volEnum(Volumes, NumberOfVolumes);
hr = volEnum.First(&pResource);
if (WSB_E_NOTFOUND == hr) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(hr);
} else if (S_OK != hr) {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
while(S_OK == hr) {
// Set the parameters (only if the volume is managed)
if (pResource->IsManaged() == S_OK) {
WsbAffirmHr(SetResourceParams(pResource, Dfs, Size, Access, RulePath,
RuleFileSpec, Include, Recursive, FALSE));
} else {
int index;
volEnum.ErrorVolume(&index);
if (CVOL_INVALID_INDEX != index) {
// invalid input from user
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
WsbThrow(E_INVALIDARG);
} else {
// just skip the volume...
}
}
pResource = 0;
hr = volEnum.Next(&pResource);
}
if (WSB_E_NOTFOUND == hr) {
hr = S_OK;
} else {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("VolumeSet"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return hr;
}
HRESULT
VolumeShow(
IN LPWSTR *Volumes,
IN DWORD NumberOfVolumes,
IN BOOL Dfs,
IN BOOL Size,
IN BOOL Access,
IN BOOL Rules,
IN BOOL Statistics
)
/*++
Routine Description:
Shows (prints) parameters for the given volume(s)
Arguments:
Volumes -
NumberOfVolumes -
Dfs -
Size -
Access -
Rules -
Statistics -
Return Value:
S_OK - If all the parameters could be retrieved for all volumes
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("VolumeShow"), OLESTR(""));
try {
CComPtr<IFsaResource> pResource;
// Initialize an enumerator object
CVolumeEnum volEnum(Volumes, NumberOfVolumes);
hr = volEnum.First(&pResource);
if (WSB_E_NOTFOUND == hr) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(hr);
} else if (S_OK != hr) {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
while(S_OK == hr) {
// Show the parameters (only if the volume is managed)
if (pResource->IsManaged() == S_OK) {
// Show volume settings
WsbAffirmHr(ShowResourceParams(pResource, Dfs, Size, Access, Rules, Statistics));
} else {
int index;
volEnum.ErrorVolume(&index);
if (CVOL_INVALID_INDEX != index) {
// invalid input from user
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
WsbThrow(E_INVALIDARG);
} else {
// just skip the volume...
}
}
pResource = 0;
hr = volEnum.Next(&pResource);
}
if (WSB_E_NOTFOUND == hr) {
hr = S_OK;
} else {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("VolumeShow"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return hr;
}
HRESULT
VolumeDeleteRule(
IN LPWSTR *Volumes,
IN DWORD NumberOfVolumes,
IN LPWSTR RulePath,
IN LPWSTR RuleFileSpec
)
/*++
Routine Description:
Deletes a specific rule from all of the given volumes
Arguments:
Volumes -
NumberOfVolumes -
RulePath -
RuleFileSpec -
Return Value:
S_OK - If the rule is found and deleted successfully for all volumes
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("VolumeDeleteRule"), OLESTR(""));
try {
CComPtr<IFsaResource> pResource;
// Verify that input parameters are valid
if (0 == NumberOfVolumes) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(E_INVALIDARG);
}
if (INVALID_POINTER_ARG != RuleFileSpec) {
// Must have a rule path then
if (INVALID_POINTER_ARG == RulePath) {
WsbTraceAndPrint(CLI_MESSAGE_INVALID_RULE, NULL);
WsbThrow(E_INVALIDARG);
}
}
// Initialize an enumerator object
CVolumeEnum volEnum(Volumes, NumberOfVolumes);
hr = volEnum.First(&pResource);
if (WSB_E_NOTFOUND == hr) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(hr);
} else if (S_OK != hr) {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
while(S_OK == hr) {
// Delete rules only if the volume is managed
if (pResource->IsManaged() == S_OK) {
// Delete the rule
hr = FindAndDeleteRule(pResource, RulePath, RuleFileSpec, TRUE);
if (WSB_E_NOTFOUND == hr) {
CWsbStringPtr volName;
WsbAffirmHr(CliGetVolumeDisplayName(pResource, &volName));
WsbTraceAndPrint(CLI_MESSAGE_RULE_NOT_FOUND, RulePath, RuleFileSpec, (WCHAR *)volName, NULL);
}
WsbAffirmHr(hr);
} else {
int index;
volEnum.ErrorVolume(&index);
if (CVOL_INVALID_INDEX != index) {
// invalid input from user
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
WsbThrow(E_INVALIDARG);
} else {
// just skip the volume...
}
}
pResource = 0;
hr = volEnum.Next(&pResource);
}
if (WSB_E_NOTFOUND == hr) {
hr = S_OK;
} else {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("VolumeDeleteRule"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return hr;
}
HRESULT
VolumeJob(
IN LPWSTR *Volumes,
IN DWORD NumberOfVolumes,
IN HSM_JOB_TYPE Job,
IN BOOL RunOrCancel,
IN BOOL Synchronous
)
/*++
Routine Description:
Runs the specified job on the given volume(s)
Arguments:
Volumes -
NumberOfVolumes -
Job -
RunOrCancel -
Synchronous -
Return Value:
S_OK - If the job is started successfully for all volumes
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("VolumeJob"), OLESTR(""));
try {
CComPtr<IFsaResource> pResource;
// Verify that input parameters are valid
if (0 == NumberOfVolumes) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(E_INVALIDARG);
}
if ((! RunOrCancel) && Synchronous) {
// Wait is available only with Run
WsbTraceAndPrint(CLI_MESSAGE_WAIT_FOR_CANCEL, NULL);
WsbThrow(E_INVALIDARG);
}
// Initialize an enumerator object
CVolumeEnum volEnum(Volumes, NumberOfVolumes);
hr = volEnum.First(&pResource);
if (WSB_E_NOTFOUND == hr) {
WsbTraceAndPrint(CLI_MESSAGE_NO_VOLUMES, NULL);
WsbThrow(hr);
} else if (S_OK != hr) {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
while(S_OK == hr) {
if (pResource->IsManaged() == S_OK) {
// Run or Cancel a job
if (RunOrCancel) {
WsbAffirmHr(StartJob(pResource, Job, Synchronous));
} else {
WsbAffirmHr(CancelJob(pResource, Job));
}
} else {
int index;
volEnum.ErrorVolume(&index);
if (CVOL_INVALID_INDEX != index) {
// invalid input from user
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
WsbThrow(E_INVALIDARG);
} else {
// just skip the volume...
}
}
pResource = 0;
hr = volEnum.Next(&pResource);
}
if (WSB_E_NOTFOUND == hr) {
hr = S_OK;
} else {
int index;
if (S_OK == volEnum.ErrorVolume(&index)) {
// Problem with a specific input volume
WsbTraceAndPrint(CLI_MESSAGE_INVALID_VOLUME, Volumes[index], NULL);
}
WsbThrow(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("VolumeJob"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return hr;
}
//
// Internal utilities
//
HRESULT SetResourceParams(IN IFsaResource *pResource, IN DWORD dwDfs, IN DWORD dwSize, IN DWORD dwAccess,
IN LPWSTR pRulePath, IN LPWSTR pRuleFileSpec, IN BOOL bInclude, IN BOOL bRecursive,
IN BOOL bSetDefaults)
/*++
Routine Description:
Sets parameters for a specific volume
Arguments:
pResourse - A resource object to set parameters for
... (see above)
Return Value:
S_OK - If all the parameters are set succeessfully for the volume
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("SetResourceParams"), OLESTR(""));
try {
// DFS
if (INVALID_DWORD_ARG != dwDfs) {
WsbAffirmHr(pResource->SetHsmLevel((ULONG)(dwDfs * FSA_HSMLEVEL_1)));
} else if (bSetDefaults) {
dwDfs = HSMADMIN_DEFAULT_FREESPACE;
WsbAffirmHr(pResource->SetHsmLevel((ULONG)(dwDfs * FSA_HSMLEVEL_1)));
}
// Min size
if (INVALID_DWORD_ARG != dwSize) {
WsbAffirmHr(pResource->SetManageableItemLogicalSize(dwSize * 1024));
} else if (bSetDefaults) {
dwSize = HSMADMIN_DEFAULT_MINSIZE;
WsbAffirmHr(pResource->SetManageableItemLogicalSize(dwSize * 1024));
}
// Not Accessed
if (INVALID_DWORD_ARG != dwAccess) {
FILETIME ftAccess = WsbLLtoFT(((LONGLONG)dwAccess) * WSB_FT_TICKS_PER_DAY);
WsbAffirmHr(pResource->SetManageableItemAccessTime(TRUE, ftAccess));
} else if (bSetDefaults) {
FILETIME ftAccess = WsbLLtoFT(((LONGLONG)HSMADMIN_DEFAULT_INACTIVITY) * WSB_FT_TICKS_PER_DAY);
WsbAffirmHr(pResource->SetManageableItemAccessTime(TRUE, ftAccess));
}
// Rules
if (INVALID_POINTER_ARG != pRulePath) {
// Verify that Rule does not exist
hr = FindAndDeleteRule(pResource, pRulePath, pRuleFileSpec, FALSE);
if (S_OK == hr) {
// Rule is already there - print a warning message and ignore it
CWsbStringPtr volName;
WsbAffirmHr(CliGetVolumeDisplayName(pResource, &volName));
WsbTraceAndPrint(CLI_MESSAGE_RULE_ALREADY_EXIST, pRulePath, pRuleFileSpec, (WCHAR *)volName, NULL);
pRulePath = INVALID_POINTER_ARG;
}
else if (WSB_E_NOTFOUND == hr) {
// Rule is not there yet
hr = S_OK;
} else {
// unexpected error - abort
WsbAffirmHr(hr);
}
}
if (INVALID_POINTER_ARG != pRulePath) {
CComPtr<IFsaServer> pFsa;
CComPtr<IWsbCreateLocalObject> pCreateObj;
CComPtr<IWsbCollection> pDefaultRules;
CComPtr<IWsbIndexedCollection> pRulesIndexedCollection;
CComPtr<IHsmRule> pRule;
CComPtr<IWsbCollection> pCriteriaCollection;
CComPtr<IHsmCriteria> pCriteria;
// Get Fsa server for creating objects in Fsa scope
WsbAffirmHr(HsmConnectFromId(HSMCONN_TYPE_FSA, g_nullGuid, IID_IFsaServer, (void**)&pFsa));
WsbAffirmHr(pFsa->QueryInterface(IID_IWsbCreateLocalObject, (void **)&pCreateObj));
// get rules collection as an indexed collection
WsbAffirmHr(pResource->GetDefaultRules(&pDefaultRules));
WsbAffirmHr(pDefaultRules->QueryInterface (IID_IWsbIndexedCollection, (void **) &pRulesIndexedCollection));
// Create a rule and set parameters
WsbAffirmHr(pCreateObj->CreateInstance(CLSID_CHsmRule, IID_IHsmRule, (void**) &pRule));
WsbAffirmHr(pRule->SetPath(pRulePath));
if (INVALID_POINTER_ARG != pRuleFileSpec) {
WsbAffirmHr(pRule->SetName(pRuleFileSpec));
} else {
WsbAffirmHr(pRule->SetName(OLESTR("*")));
}
WsbAffirmHr(pRule->SetIsInclude(bInclude));
WsbAffirmHr(pRule->SetIsUsedInSubDirs(bRecursive));
WsbAffirmHr(pRule->SetIsUserDefined(TRUE));
// Set the criteria appropriately, depending on whether it is an include or exclude rule.
WsbAssertHr(pRule->Criteria(&pCriteriaCollection));
if (bInclude) {
WsbAffirmHr(pCreateObj->CreateInstance(CLSID_CHsmCritManageable, IID_IHsmCriteria, (void**) &pCriteria));
} else {
WsbAffirmHr(pCreateObj->CreateInstance(CLSID_CHsmCritAlways, IID_IHsmCriteria, (void**) &pCriteria));
}
WsbAssertHr(pCriteria->SetIsNegated(FALSE));
WsbAssertHr(pCriteriaCollection->Add(pCriteria));
// Now that the rule has been set up properly, add it to the default rules collection.
WsbAffirmHr(pRulesIndexedCollection->Append(pRule));
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("SetResourceParams"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return (hr);
}
HRESULT ShowResourceParams(IN IFsaResource *pResource, IN BOOL bDfs, IN BOOL bSize,
IN BOOL bAccess, IN BOOL bRules, IN BOOL bStatistics)
/*++
Routine Description:
Get and display parameters for a specific volume
Arguments:
pResourse - A resource object to get parameters for
... (see above)
Return Value:
S_OK - If all the parameters are retrieved succeessfully for the volume
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("ShowResourceParams"), OLESTR(""));
try {
CWsbStringPtr volName;
CWsbStringPtr param, param2;
WCHAR longData[100];
WsbAffirmHr(CliGetVolumeDisplayName(pResource, &volName));
WsbTraceAndPrint(CLI_MESSAGE_VOLUME_PARAMS, (WCHAR *)volName, NULL);
// Dfs
if (bDfs) {
ULONG hsmLevel;
WsbAffirmHr(pResource->GetHsmLevel(&hsmLevel));
hsmLevel = hsmLevel / FSA_HSMLEVEL_1;
WsbAffirmHr(param.LoadFromRsc(g_hInstance, IDS_DFS));
WsbAffirmHr(param2.LoadFromRsc(g_hInstance, IDS_PERCENT_SUFFIX));
swprintf(longData, OLESTR("%lu"), hsmLevel);
WsbTraceAndPrint(CLI_MESSAGE_PARAM_DISPLAY2, (WCHAR *)param, longData, (WCHAR *)param2, NULL);
}
// Min size
if (bSize) {
LONGLONG fileSize;
ULONG fileSizeKb;
WsbAffirmHr(pResource->GetManageableItemLogicalSize(&fileSize));
fileSizeKb = (ULONG)(fileSize / 1024); // Show KBytes
WsbAffirmHr(param.LoadFromRsc(g_hInstance, IDS_MIN_SIZE));
WsbAffirmHr(param2.LoadFromRsc(g_hInstance, IDS_KB_SUFFIX));
swprintf(longData, OLESTR("%lu"), fileSizeKb);
WsbTraceAndPrint(CLI_MESSAGE_PARAM_DISPLAY2, (WCHAR *)param, longData, (WCHAR *)param2, NULL);
}
// Not accessed
if (bAccess) {
FILETIME accessTime;
ULONG accessTimeDays;
BOOL dummy;
WsbAffirmHr(pResource->GetManageableItemAccessTime(&dummy, &accessTime));
accessTimeDays = (ULONG)(WsbFTtoLL(accessTime) / WSB_FT_TICKS_PER_DAY);
WsbAffirmHr(param.LoadFromRsc(g_hInstance, IDS_NOT_ACCESSED));
WsbAffirmHr(param2.LoadFromRsc(g_hInstance, IDS_DAYS_SUFFIX));
swprintf(longData, OLESTR("%lu"), accessTimeDays);
WsbTraceAndPrint(CLI_MESSAGE_PARAM_DISPLAY2, (WCHAR *)param, longData, (WCHAR *)param2, NULL);
}
//Statistics
if (bStatistics) {
LONGLONG total;
LONGLONG free;
LONGLONG premigrated;
LONGLONG truncated;
LONGLONG hsmData;
LONGLONG notHsmData;
WCHAR pctData[10];
int freePct;
int premigratedPct;
int notHsmDataPct;
// Get and calculate sizes
WsbAffirmHr(pResource->GetSizes(&total, &free, &premigrated, &truncated));
hsmData = premigrated + truncated;
notHsmData = max((total - free - premigrated ), 0);
freePct = (int)((free * 100) / total);
premigratedPct = (int)((premigrated * 100) / total);
notHsmDataPct = (int)((notHsmData * 100) / total);
// Print statistics
WsbAffirmHr(param.LoadFromRsc(g_hInstance, IDS_VOL_CAPACITY));
WsbAffirmHr(ShortSizeFormat64(total, longData));
WsbTraceAndPrint(CLI_MESSAGE_PARAM_DISPLAY, (WCHAR *)param, longData, NULL);
WsbAffirmHr(param.LoadFromRsc(g_hInstance, IDS_VOL_FREE_SPACE));
WsbAffirmHr(ShortSizeFormat64(free, longData));
swprintf(pctData, OLESTR(" (%d%%%%)"), freePct);
WsbTraceAndPrint(CLI_MESSAGE_PARAM_DISPLAY2, (WCHAR *)param, longData, pctData, NULL);
WsbAffirmHr(param.LoadFromRsc(g_hInstance, IDS_VOL_NOT_RSS_DATA));
WsbAffirmHr(ShortSizeFormat64(notHsmData, longData));
swprintf(pctData, OLESTR(" (%d%%%%)"), notHsmDataPct);
WsbTraceAndPrint(CLI_MESSAGE_PARAM_DISPLAY2, (WCHAR *)param, longData, pctData, NULL);
WsbAffirmHr(param.LoadFromRsc(g_hInstance, IDS_VOL_CACHED_DATA));
WsbAffirmHr(ShortSizeFormat64(premigrated, longData));
swprintf(pctData, OLESTR(" (%d%%%%)"), premigratedPct);
WsbTraceAndPrint(CLI_MESSAGE_PARAM_DISPLAY2, (WCHAR *)param, longData, pctData, NULL);
WsbAffirmHr(param.LoadFromRsc(g_hInstance, IDS_VOL_RSS_DATA));
WsbAffirmHr(ShortSizeFormat64(hsmData, longData));
WsbTraceAndPrint(CLI_MESSAGE_PARAM_DISPLAY, (WCHAR *)param, longData, NULL);
}
// Rules
if (bRules) {
CComPtr<IWsbCollection> pDefaultRules;
CComPtr<IWsbIndexedCollection> pRulesIndexedCollection;
CComPtr<IHsmRule> pHsmRule;
CWsbStringPtr rulePath;
CWsbStringPtr ruleFileSpec;
BOOL include;
CWsbStringPtr includeStr;
BOOL recursive;
CWsbStringPtr recursiveStr;
ULONG count;
WsbTraceAndPrint(CLI_MESSAGE_RULES_LIST, NULL);
// Get the rules collection
WsbAffirmHr(pResource->GetDefaultRules(&pDefaultRules));
WsbAffirmHr(pDefaultRules->QueryInterface(IID_IWsbIndexedCollection, (void **)&pRulesIndexedCollection));
// Itterate through the indexed collection
WsbAffirmHr(pRulesIndexedCollection->GetEntries(&count));
for (int i = 0; i < (int) count; i++) {
// Get rule and rule parameters
WsbAffirmHr(pRulesIndexedCollection->At(i, IID_IHsmRule, (void**) &pHsmRule));
WsbAffirmHr(pHsmRule->GetPath(&rulePath, 0));
WsbAffirmHr(pHsmRule->GetName(&ruleFileSpec, 0));
include = (S_OK == pHsmRule->IsInclude()) ? TRUE : FALSE;
recursive = (S_OK == pHsmRule->IsUsedInSubDirs()) ? TRUE : FALSE;
// Print rule
if (include) {
WsbAffirmHr(includeStr.LoadFromRsc(g_hInstance, IDS_INCLUDE_RULE));
} else {
WsbAffirmHr(includeStr.LoadFromRsc(g_hInstance, IDS_EXCLUDE_RULE));
}
if (recursive) {
WsbAffirmHr(recursiveStr.LoadFromRsc(g_hInstance, IDS_RECURSIVE_RULE));
} else {
WsbAffirmHr(recursiveStr.LoadFromRsc(g_hInstance, IDS_NON_RECURSIVE_RULE));
}
WsbTraceAndPrint(CLI_MESSAGE_RULE_SPEC, (WCHAR *)rulePath, (WCHAR *)ruleFileSpec,
(WCHAR *)includeStr, (WCHAR *)recursiveStr, NULL);
// Free resources before next iteration
pHsmRule = 0;
rulePath.Free();
ruleFileSpec.Free();
includeStr.Free();
recursiveStr.Free();
}
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("ShowResourceParams"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return (hr);
}
HRESULT FindAndDeleteRule(IN IFsaResource *pResource, IN LPWSTR pRulePath, IN LPWSTR pRuleFileSpec, IN BOOL bDelete)
/*++
Routine Description:
Deletes a rule that match the given path & file specification from a specific volume
If more than one exists, the first one found is deleted
Arguments:
bDelete - A flag of whether to delete or just find the rule
pResourse - A resource object to delete rule from
... (see above)
Return Value:
S_OK - If the rule is found and deleted (deleted only if bDelete is TRUE)
WSB_E_NOTFOUND - If the rule could not be found
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("DeleteRule"), OLESTR(""));
try {
CComPtr<IWsbCollection> pDefaultRules;
CComPtr<IWsbIndexedCollection> pRulesIndexedCollection;
CComPtr<IHsmRule> pHsmRule;
ULONG count;
SHORT dummy;
// Get the default rules collection
WsbAffirmHr(pResource->GetDefaultRules(&pDefaultRules));
WsbAffirmHr(pDefaultRules->QueryInterface(IID_IWsbIndexedCollection, (void **) &pRulesIndexedCollection));
// Itterate through the indexed collection
hr = WSB_E_NOTFOUND;
WsbAffirmHr(pRulesIndexedCollection->GetEntries(&count));
for (int i = 0; i < (int)count; i++) {
WsbAffirmHr(pRulesIndexedCollection->At(i, IID_IHsmRule, (void**)&pHsmRule));
if (pHsmRule->CompareToPathAndName(pRulePath, pRuleFileSpec, &dummy) == S_OK) {
if (bDelete) {
pHsmRule = 0;
WsbAffirmHr(pRulesIndexedCollection->RemoveAt(i, IID_IHsmRule, (void**) &pHsmRule));
}
hr = S_OK;
break;
}
// Release before continuing loop
pHsmRule = 0;
}
// If we got to the end of the for loop without a match, hr stays WSB_E_NOTFOUND
} WsbCatch(hr);
WsbTraceOut(OLESTR("DeleteRule"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return (hr);
}
HRESULT QuickUnmanage(IN IFsaResource *pResource)
/*++
Routine Description:
Remove a volume from the set of managed volumes
Arguments:
pResourse - A resource object to unmanage
Return Value:
S_OK - If the volume is removed from the list of managed volumes successfully
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("QuickUnmanage"), OLESTR(""));
try {
CComPtr<IHsmServer> pHsm;
CComPtr<IWsbCreateLocalObject> pCreateObj;
CComPtr<IHsmManagedResource> pManagedResource;
CComPtr<IWsbIndexedCollection> pMRCollection;
// Get Hsm (Engine) server
WsbAffirmHr(HsmConnectFromId(HSMCONN_TYPE_HSM, g_nullGuid, IID_IHsmServer, (void**)&pHsm));
WsbAffirmHr(pHsm->QueryInterface(IID_IWsbCreateLocalObject, (void**) &pCreateObj));
// Create an object to remove
WsbAffirmHr(pCreateObj->CreateInstance(CLSID_CHsmManagedResource, IID_IHsmManagedResource, (void**) &pManagedResource));
WsbAffirmHr(pManagedResource->InitFromFsaResource(pResource));
// Remove from the collection
WsbAffirmHr(pHsm->GetManagedResources(&pMRCollection));
WsbAffirmHr(pMRCollection->RemoveAndRelease(pManagedResource));
// TEMPORARY: Should we call now SaveServersPersistData to flush changes into
// servers persistency files ?! What about Manage, Set, ... ?
} WsbCatch(hr);
WsbTraceOut(OLESTR("QuickUnmanage"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return (hr);
}
HRESULT StartJob(IN IFsaResource *pResource, IN HSM_JOB_TYPE Job, IN BOOL bWait)
/*++
Routine Description:
Start a job of the specified type
Arguments:
pResourse - A resource object to start a job on
Job - The job type
bWait - If TRUE, wait until the job is done
If FALSE, return immediately after starting the job
Return Value:
S_OK - If the job is started successfully
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("StartJob"), OLESTR(""));
try {
CComPtr<IHsmServer> pHsm;
CComPtr<IHsmJob> pJob;
CWsbStringPtr jobName;
HSM_JOB_DEF_TYPE jobType;
// Set job type
switch (Job) {
case CopyFiles:
jobType = HSM_JOB_DEF_TYPE_MANAGE;
break;
case CreateFreeSpace:
jobType = HSM_JOB_DEF_TYPE_TRUNCATE;
break;
case Validate:
jobType = HSM_JOB_DEF_TYPE_VALIDATE;
break;
case Unmanage:
jobType = HSM_JOB_DEF_TYPE_FULL_UNMANAGE;
break;
default:
WsbThrow(E_INVALIDARG);
}
// Create job name
// TEMPORARY: Should the job name and job object match those that are created by the GUI ?!
// If so, RsCreateJobName (rsadutil.cpp) + all the resource strings that it uses,
// should be moved from HsmAdmin DLL to RsCommon DLL
WsbAffirmHr(CreateJobName(Job, pResource, &jobName));
// If job exists - use it, otherwize, craete and add an appropriate job object
WsbAffirmHr(HsmConnectFromId(HSMCONN_TYPE_HSM, g_nullGuid, IID_IHsmServer, (void**)&pHsm));
hr = pHsm->FindJobByName(jobName, &pJob);
if (S_OK == hr) {
// Job already exists
} else if (WSB_E_NOTFOUND == hr) {
// No such job yet
CComPtr<IWsbCreateLocalObject> pCreateObj;
CComPtr<IWsbIndexedCollection> pJobs;
CComPtr<IWsbIndexedCollection> pCollection;
CComPtr<IHsmStoragePool> pStoragePool;
GUID poolId;
ULONG count;
hr = S_OK;
pJob = 0;
// Create and add the job
WsbAffirmHr(pHsm->QueryInterface(IID_IWsbCreateLocalObject, (void**) &pCreateObj));
WsbAffirmHr(pCreateObj->CreateInstance(CLSID_CHsmJob, IID_IHsmJob, (void**) &pJob));
WsbAffirmHr(pHsm->GetStoragePools(&pCollection));
WsbAffirmHr(pCollection->GetEntries(&count));
WsbAffirm(1 == count, E_FAIL);
WsbAffirmHr(pCollection->At(0, IID_IHsmStoragePool, (void **)&pStoragePool));
WsbAffirmHr(pStoragePool->GetId(&poolId));
WsbAffirmHr(pJob->InitAs(jobName, NULL, jobType, poolId, pHsm, TRUE, pResource));
WsbAffirmHr(pHsm->GetJobs(&pJobs));
WsbAffirmHr(pJobs->Add(pJob));
} else {
// Other error - abort
WsbThrow(hr);
}
// Start the job
WsbAffirmHr(pJob->Start());
// Wait if required
if (bWait) {
WsbAffirmHr(pJob->WaitUntilDone());
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("StartJob"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return (hr);
}
HRESULT CancelJob(IN IFsaResource *pResource, IN HSM_JOB_TYPE Job)
/*++
Routine Description:
Cancel a job on the volume
Arguments:
pResourse - A resource object to cancel a job for
Job - The job type
Return Value:
S_OK - If the job is canceled
Notes:
1) The function just issue the cancellation, it does not wait for it to finish
2) If the job is not found or not started, it is not considered as an error
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CancelJob"), OLESTR(""));
try {
CComPtr<IHsmServer> pHsm;
CComPtr<IHsmJob> pJob;
CWsbStringPtr jobName;
HSM_JOB_DEF_TYPE jobType;
// Set job type
switch (Job) {
case CopyFiles:
jobType = HSM_JOB_DEF_TYPE_MANAGE;
break;
case CreateFreeSpace:
jobType = HSM_JOB_DEF_TYPE_TRUNCATE;
break;
case Validate:
jobType = HSM_JOB_DEF_TYPE_VALIDATE;
break;
case Unmanage:
jobType = HSM_JOB_DEF_TYPE_FULL_UNMANAGE;
break;
default:
WsbThrow(E_INVALIDARG);
}
// Create job name
WsbAffirmHr(CreateJobName(Job, pResource, &jobName));
// If job exists, try to cancel it
WsbAffirmHr(HsmConnectFromId(HSMCONN_TYPE_HSM, g_nullGuid, IID_IHsmServer, (void**)&pHsm));
hr = pHsm->FindJobByName(jobName, &pJob);
if (S_OK == hr) {
// Cancel (we don't care if it's actually running or not)
WsbAffirmHr(pJob->Cancel(HSM_JOB_PHASE_ALL));
} else if (WSB_E_NOTFOUND == hr) {
// No such job, for sure it is not running...
hr = S_OK;
} else {
// Other error - abort
WsbThrow(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("CancelJob"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return (hr);
}
HRESULT
CreateJobName(IN HSM_JOB_TYPE Job, IN IFsaResource *pResource, OUT WCHAR **ppJobName)
/*++
Routine Description:
Create a job name based on its type and the volume properties
Arguments:
Job - The job type
pResource - Fsa resource that the job is created for
ppJobName - The job name
Return Value:
S_OK - The job name is created successfully
Notes:
This utility uses similar algorithm to RsCreateJobName (rsadutil.cpp).
Howevere, since RsCreateJobName uses internal HsmAdmin resource strings, the final
name might be different than the GUI name, especially in a localaized system.
Therefore, I use here different strings for CLI jobs to ensure consistent behavior.
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CreateJobName"), OLESTR(""));
try {
CWsbStringPtr jobPrefix;
CWsbStringPtr jobTypeString;
CWsbStringPtr volumeName;
CWsbStringPtr volumeString;
// Type string
switch (Job) {
case CopyFiles:
WsbAffirmHr(jobTypeString.LoadFromRsc(g_hInstance, IDS_JOB_MANAGE));
break;
case CreateFreeSpace:
WsbAffirmHr(jobTypeString.LoadFromRsc(g_hInstance, IDS_JOB_TRUNCATE));
break;
case Validate:
WsbAffirmHr(jobTypeString.LoadFromRsc(g_hInstance, IDS_JOB_VALIDATE));
break;
case Unmanage:
WsbAffirmHr(jobTypeString.LoadFromRsc(g_hInstance, IDS_JOB_FULL_UNMANAGE));
break;
default:
WsbThrow(E_INVALIDARG);
}
WsbAffirmHr(pResource->GetUserFriendlyName(&volumeName, 0));
// For now, ignore the user-name if it's not a drive letter
size_t nameLen = wcslen(volumeName);
if ((nameLen != 3) || (volumeName[1] != L':')) {
volumeName = L"";
}
if (volumeName.IsEqual(L"")) {
// No drive letter - use the volume name and serial number instead
ULONG serial;
CWsbStringPtr name;
WsbAffirmHr(pResource->GetName(&name, 0 ));
WsbAffirmHr(pResource->GetSerial(&serial));
if (name == L"" ) {
// No name, no drive letter - just have serial number
WsbAffirmHr(volumeString.Alloc(40));
swprintf(volumeString, L"%8.8lx", serial);
} else {
// Use name and serial
WsbAffirmHr(volumeString.Alloc(40 + wcslen(name)));
swprintf(volumeString, L"%ls-%8.8lx", (WCHAR *)name, serial);
}
} else {
// Use drive letter
WsbAffirmHr(volumeString.Alloc(1));
volumeString[0] = volumeName[0];
volumeString[1] = L'\0';
}
// Create job name
WsbAffirmHr(jobPrefix.LoadFromRsc(g_hInstance, IDS_JOB_NAME_PREFIX));
int allocLen = wcslen(jobPrefix) + wcslen(jobTypeString) + wcslen(volumeString) + 40;
WCHAR* tmpString = (WCHAR*)WsbRealloc(*ppJobName, allocLen * sizeof(WCHAR));
WsbAffirm(0 != tmpString, E_OUTOFMEMORY);
*ppJobName = tmpString;
swprintf(*ppJobName, jobPrefix, (WCHAR *)jobTypeString, (WCHAR *)volumeString);
} WsbCatch(hr);
WsbTraceOut(OLESTR("CreateJobName"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return (hr);
}
//
// Enumerator class methods
//
CVolumeEnum::CVolumeEnum(IN LPWSTR *pVolumes, IN DWORD dwNumberOfVolumes, IN BOOL bSkipUnavailable)
/*++
Routine Description:
Constructor
Arguments:
pVolumes - Volumes to enumerate
dwNumberOfVolumes - Number of volumes
Return Value:
None
Notes:
There are two kinds of enumerations:
1) If * is specified, the base for the enumeration is the FSA resource collection
In that case, there could be no error in the input volumes themselves
2) If a list of volumes is given, the base for the enumeration is this list. This is
less efficient that using the FSA collection, but it keeps the order of volumes
according to the input list. If a volume from the list is not valid, the invalid flag is set.
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CVolumeEnum::CVolumeEnum"), OLESTR(""));
try {
m_pVolumes = pVolumes;
m_dwNumberOfVolumes = dwNumberOfVolumes;
m_nCurrent = CVOL_INVALID_INDEX;
m_bInvalidVol = FALSE;
m_bAllVols = FALSE;
m_bSkipUnavailable = bSkipUnavailable;
// Check mode of enumeration
WsbAssert(m_dwNumberOfVolumes > 0, E_INVALIDARG);
if ((1 == m_dwNumberOfVolumes) && (0 == wcscmp(m_pVolumes[0], CLI_ALL_STR))) {
// * enumeration
m_bAllVols = TRUE;
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("CVolumeEnum::CVolumeEnum"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
}
HRESULT CVolumeEnum::First(OUT IFsaResource **ppResource)
/*++
Routine Description:
Gets first volume
Arguments:
ppResourse - First resource to get
Return Value:
S_OK - If first volume is retrieved
WSB_E_NOTFOUND - If no more volumes to enumerate
E_INVALIDARG - If volume given by the user is not found
(Only on a non * enumeration, m_bInvalidVol is set)
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CVolumeEnum::First"), OLESTR(""));
try {
// Get FSA resources collection (only once during the object life time)
if (!m_pEnumResources) {
CComPtr<IFsaServer> pFsa;
WsbAffirmHr(HsmConnectFromId(HSMCONN_TYPE_FSA, g_nullGuid, IID_IFsaServer, (void**)&pFsa));
WsbAffirmHr(pFsa->EnumResources(&m_pEnumResources));
}
if (m_bAllVols) {
if (m_bSkipUnavailable) {
// Get first volume, skip unavailable resources
CComPtr<IFsaResource> pFindResource;
hr = m_pEnumResources->First(IID_IFsaResource, (void**)&pFindResource);
while (S_OK == hr) {
if (S_OK == pFindResource->IsAvailable()) {
// Found one
*ppResource = pFindResource;
(*ppResource)->AddRef();
break;
} else {
// Skip it
pFindResource = 0;
}
hr = m_pEnumResources->Next(IID_IFsaResource, (void**)&pFindResource);
}
WsbAffirmHr(hr);
} else {
// Get first volume
hr = m_pEnumResources->First(IID_IFsaResource, (void**)ppResource);
WsbAffirmHr(hr);
}
} else {
CWsbStringPtr volName;
CWsbStringPtr findName;
CComPtr<IFsaResource> pFindResource;
// Enumerate user collection and try to find it in FSA
m_nCurrent = 0;
if (m_nCurrent >= (int)m_dwNumberOfVolumes) {
WsbThrow(WSB_E_NOTFOUND);
}
// Validate current name and add trailing backslash if missing
volName = m_pVolumes[m_nCurrent];
WsbAssert (NULL != (WCHAR *)volName, E_UNEXPECTED);
int len = wcslen(volName);
WsbAssert (0 != len, E_UNEXPECTED);
if (volName[len-1] != L'\\') {
volName.Append(OLESTR("\\"));
}
// Find it
hr = m_pEnumResources->First(IID_IFsaResource, (void**)&pFindResource);
while(S_OK == hr) {
WsbAffirmHr(pFindResource->GetUserFriendlyName(&findName, 0));
if (_wcsicmp(volName, findName) == 0) {
// Fount it !!
*ppResource = pFindResource;
(*ppResource)->AddRef();
break;
}
findName.Free();
pFindResource = 0;
hr = m_pEnumResources->Next(IID_IFsaResource, (void**)&pFindResource);
}
if (WSB_E_NOTFOUND == hr) {
// Volume given by user not found
m_bInvalidVol = TRUE;
hr = E_INVALIDARG;
}
WsbAffirmHr(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("CVolumeEnum::First"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return hr;
}
HRESULT CVolumeEnum::Next(OUT IFsaResource **ppResource)
/*++
Routine Description:
Gets next volume
Arguments:
ppResourse - Next resource to get
Return Value:
S_OK - If next volume is retrieved
WSB_E_NOTFOUND - If no more volumes to enumerate
E_INVALIDARG - If volume given by the user is not found
(Only on a non * enumeration, m_bInvalidVol is set)
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CVolumeEnum::Next"), OLESTR(""));
try {
if (m_bAllVols) {
if (m_bSkipUnavailable) {
// Get next volume, skip unavailable resources
CComPtr<IFsaResource> pFindResource;
hr = m_pEnumResources->Next(IID_IFsaResource, (void**)&pFindResource);
while (S_OK == hr) {
if (S_OK == pFindResource->IsAvailable()) {
// Found one
*ppResource = pFindResource;
(*ppResource)->AddRef();
break;
} else {
// Skip it
pFindResource = 0;
}
hr = m_pEnumResources->Next(IID_IFsaResource, (void**)&pFindResource);
}
WsbAffirmHr(hr);
} else {
// Get next volume
hr = m_pEnumResources->Next(IID_IFsaResource, (void**)ppResource);
WsbAffirmHr(hr);
}
} else {
CWsbStringPtr volName;
CWsbStringPtr findName;
CComPtr<IFsaResource> pFindResource;
// Enumerate user collection and try to find it in FSA
m_nCurrent++;
if (m_nCurrent >= (int)m_dwNumberOfVolumes) {
WsbThrow(WSB_E_NOTFOUND);
}
// Validate current name and add trailing backslash if missing
volName = m_pVolumes[m_nCurrent];
WsbAssert (NULL != (WCHAR *)volName, E_UNEXPECTED);
int len = wcslen(volName);
WsbAssert (0 != len, E_UNEXPECTED);
if (volName[len-1] != L'\\') {
volName.Append(OLESTR("\\"));
}
// Find it
hr = m_pEnumResources->First(IID_IFsaResource, (void**)&pFindResource);
while(S_OK == hr) {
WsbAffirmHr(pFindResource->GetUserFriendlyName(&findName, 0));
if (_wcsicmp(volName, findName) == 0) {
// Fount it !!
*ppResource = pFindResource;
(*ppResource)->AddRef();
break;
}
findName.Free();
pFindResource = 0;
hr = m_pEnumResources->Next( IID_IFsaResource, (void**)&pFindResource );
}
if (WSB_E_NOTFOUND == hr) {
// Volume given by user not found
m_bInvalidVol = TRUE;
hr = E_INVALIDARG;
}
WsbAffirmHr(hr);
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("CVolumeEnum::Next"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return hr;
}