501 lines
12 KiB
C++
501 lines
12 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1998 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
FTMan
|
||
|
|
||
|
File Name:
|
||
|
|
||
|
LogVol.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Implementation of the CLogicalVolumeData class. The class who stores all properties of a logical volume
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Cristian Teodorescu October 20, 1998
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#include "DiskMap.h"
|
||
|
#include "FTUtil.h"
|
||
|
#include "Global.h"
|
||
|
#include "LogVol.h"
|
||
|
#include "MainFrm.h"
|
||
|
#include "PhPart.h"
|
||
|
#include "Resource.h"
|
||
|
|
||
|
// Because ftapi library is written in C the header must be included with extern "C".
|
||
|
// Otherwise it can't be linked
|
||
|
extern "C"
|
||
|
{
|
||
|
#include <FTAPI.h>
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// CLogicalVolumeData
|
||
|
|
||
|
// Constructor
|
||
|
CLogicalVolumeData::CLogicalVolumeData(
|
||
|
FT_LOGICAL_DISK_ID llVolID,
|
||
|
CItemData* pParentData /* = NULL */,
|
||
|
BOOL bIsRootVolume /* = FALSE */,
|
||
|
USHORT unMemberIndex /* = MAXWORD */,
|
||
|
FT_MEMBER_STATE nMemberStatus /* = FtMemberHealthy */ ) :
|
||
|
CItemData( IT_LogicalVolume, pParentData, bIsRootVolume ), m_llVolID(llVolID), m_unMemberIndex(unMemberIndex)
|
||
|
{
|
||
|
m_nMemberStatus = nMemberStatus;
|
||
|
if( bIsRootVolume )
|
||
|
{
|
||
|
ASSERT( unMemberIndex == MAXWORD );
|
||
|
ASSERT( nMemberStatus == FtMemberHealthy );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy constructor
|
||
|
CLogicalVolumeData::CLogicalVolumeData( CLogicalVolumeData& rData )
|
||
|
: CItemData(rData),
|
||
|
m_llVolID(rData.m_llVolID), m_llVolSize(rData.m_llVolSize), m_nVolType(rData.m_nVolType),
|
||
|
m_unMemberIndex(rData.m_unMemberIndex)
|
||
|
{
|
||
|
memcpy(&m_ConfigInfo, &(rData.m_ConfigInfo), sizeof(m_ConfigInfo));
|
||
|
memcpy(&m_StateInfo, &(rData.m_StateInfo), sizeof(m_StateInfo));
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Public methods
|
||
|
|
||
|
BOOL CLogicalVolumeData::ReadItemInfo( CString& strErrors )
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
m_bValid = TRUE;
|
||
|
strErrors = _T("");
|
||
|
|
||
|
m_ulNumMembers = 0;
|
||
|
|
||
|
if( !ReadFTInfo( strErrors ) )
|
||
|
{
|
||
|
m_bValid = FALSE;
|
||
|
// this is a serious error so return immediately
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if( m_nVolType == FtPartition )
|
||
|
{
|
||
|
// I need some extra information for FtPartitions
|
||
|
PARTITION_INFORMATION partInfo;
|
||
|
PARTITION_TYPE wPartitionType;
|
||
|
CString strMemberErrors;
|
||
|
BOOL bMissingDisk;
|
||
|
|
||
|
CDiskMap diskMap( m_ConfigInfo.partConfig.Config.DiskNumber );
|
||
|
if( diskMap.ReadPartitionInformation( m_ConfigInfo.partConfig.Config.ByteOffset,
|
||
|
partInfo,
|
||
|
wPartitionType,
|
||
|
strMemberErrors,
|
||
|
bMissingDisk) )
|
||
|
{
|
||
|
m_ConfigInfo.partConfig.dwPartitionNumber = partInfo.PartitionNumber;
|
||
|
m_ConfigInfo.partConfig.wPartitionType = wPartitionType;
|
||
|
}
|
||
|
strErrors += strMemberErrors;
|
||
|
}
|
||
|
|
||
|
// Read the drive letter, volume name and mount paths ( if any )
|
||
|
if( !ReadDriveLetterAndVolumeName() )
|
||
|
{
|
||
|
//AddError( strErrors, IDS_ERR_READ_DRIVE_LETTER_AND_VOLUME_NAME, FALSE );
|
||
|
m_bValid = FALSE;
|
||
|
}
|
||
|
|
||
|
// The mount paths will be retrieved later together with all other siblings mount paths ( for performance reason )
|
||
|
m_arrMountPaths.RemoveAll();
|
||
|
|
||
|
// Retrieve all disks used by this volume
|
||
|
if( !RetrieveDisksSet() )
|
||
|
{
|
||
|
AddError( strErrors, IDS_ERR_RETRIEVE_DISKS_SET, FALSE );
|
||
|
m_bValid = FALSE;
|
||
|
}
|
||
|
|
||
|
if( !FTChkIO( m_llVolID, &m_bIoOK) )
|
||
|
{
|
||
|
AddError( strErrors, IDS_ERR_FTCHKIO, TRUE );
|
||
|
m_bValid = FALSE;
|
||
|
}
|
||
|
|
||
|
m_iImage = ComputeImageIndex();
|
||
|
|
||
|
return m_bValid;
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|
||
|
BOOL CLogicalVolumeData::ReadFTInfo( CString& strErrors )
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
strErrors = _T("");
|
||
|
|
||
|
USHORT numMembers;
|
||
|
FT_LOGICAL_DISK_ID members[100];
|
||
|
|
||
|
// Read all information related to this logical volume
|
||
|
if( ! FtQueryLogicalDiskInformation ( m_llVolID,
|
||
|
&m_nVolType,
|
||
|
&m_llVolSize,
|
||
|
100,
|
||
|
members,
|
||
|
&numMembers,
|
||
|
sizeof(m_ConfigInfo),
|
||
|
&m_ConfigInfo,
|
||
|
sizeof(m_StateInfo),
|
||
|
&m_StateInfo ) )
|
||
|
{
|
||
|
AddError( strErrors, IDS_ERR_RETRIEVING_VOL_INFO, TRUE );
|
||
|
m_bValid = FALSE;
|
||
|
// this is a serious error so return immediately
|
||
|
return FALSE;
|
||
|
}
|
||
|
m_ulNumMembers = (ULONG)numMembers;
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|
||
|
BOOL CLogicalVolumeData::ReadMembers( CObArray& arrMembersData, CString& strErrors )
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
arrMembersData.RemoveAll();
|
||
|
strErrors = _T("");
|
||
|
m_ulNumMembers = 0;
|
||
|
|
||
|
USHORT numMembers;
|
||
|
FT_LOGICAL_DISK_ID members[100];
|
||
|
|
||
|
// Read all information related to this logical volume
|
||
|
if( !FtQueryLogicalDiskInformation ( m_llVolID,
|
||
|
&m_nVolType,
|
||
|
&m_llVolSize,
|
||
|
100,
|
||
|
members,
|
||
|
&numMembers,
|
||
|
sizeof(m_ConfigInfo),
|
||
|
&m_ConfigInfo,
|
||
|
sizeof(m_StateInfo),
|
||
|
&m_StateInfo ) )
|
||
|
{
|
||
|
AddError( strErrors, IDS_ERR_RETRIEVING_VOL_INFO, TRUE );
|
||
|
return FALSE;
|
||
|
}
|
||
|
m_ulNumMembers = (ULONG)numMembers;
|
||
|
|
||
|
for( USHORT i = 0; i < m_ulNumMembers; i++ )
|
||
|
{
|
||
|
// Get the status of the member
|
||
|
FT_MEMBER_STATE nMemberStatus;
|
||
|
nMemberStatus = FtMemberHealthy;
|
||
|
if( ( m_nVolType == FtMirrorSet ) ||
|
||
|
( m_nVolType == FtStripeSetWithParity ) )
|
||
|
{
|
||
|
if( ( m_StateInfo.stripeState.UnhealthyMemberState != FtMemberHealthy ) &&
|
||
|
( m_StateInfo.stripeState.UnhealthyMemberNumber == i ) )
|
||
|
nMemberStatus = m_StateInfo.stripeState.UnhealthyMemberState;
|
||
|
}
|
||
|
|
||
|
// Create the logical volume item data
|
||
|
CLogicalVolumeData* pData = new CLogicalVolumeData( members[i], this, FALSE, i, nMemberStatus );
|
||
|
// Read logical volume info and collect errors ( if any )
|
||
|
CString strMemberErrors;
|
||
|
pData->ReadItemInfo( strMemberErrors);
|
||
|
strErrors += strMemberErrors;
|
||
|
// Add the structure to the members' data array
|
||
|
arrMembersData.Add(pData);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|
||
|
int CLogicalVolumeData::ComputeImageIndex() const
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
// Is it necessary to display the error image?
|
||
|
BOOL bError = FALSE;
|
||
|
// Is it necessary to display the warning image?
|
||
|
BOOL bWarning = FALSE;
|
||
|
|
||
|
// The error image should be displayed in three situations:
|
||
|
// 1. The item is not valid. That means that not all information about the volume was successfully read,
|
||
|
// so the volume cannot be used in actions
|
||
|
// 2. The check IO test failed. The volume cannot be used for IO operations
|
||
|
// 3. The volume is an orphan member of a mirror set or of a stripe set with parity.
|
||
|
bError = !m_bValid || !m_bIoOK || ( m_nMemberStatus == FtMemberOrphaned );
|
||
|
|
||
|
if( !bError )
|
||
|
{
|
||
|
// The warning image should be displayed in four situations:
|
||
|
// 1. The volume is a regenerating member of a mirror set or stripe set with parity
|
||
|
// 2. The volume is a member of a stripe set with parity who is initializing
|
||
|
// 3. The volume is a stripe set with parity initializing
|
||
|
// 4. The volume is a mirror set or a stripe set with parity containing a not healthy member.
|
||
|
// Situations 1,2 are general and could happen to all logical volumes
|
||
|
// Situations 3,4 are particular for mirrors and swp's so they will be treated in the main switch at
|
||
|
// the end of the method
|
||
|
|
||
|
|
||
|
if( m_nMemberStatus == FtMemberRegenerating )
|
||
|
bWarning = TRUE;
|
||
|
else if( ( m_pParentData != NULL ) && ( m_pParentData->GetItemType() == IT_LogicalVolume ) )
|
||
|
{
|
||
|
CLogicalVolumeData* pParentData = (CLogicalVolumeData*)m_pParentData;
|
||
|
if( ( pParentData->m_nVolType == FtStripeSetWithParity ) &&
|
||
|
( pParentData->m_StateInfo.stripeState.IsInitializing ) )
|
||
|
bWarning = TRUE;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch( m_nVolType )
|
||
|
{
|
||
|
case FtPartition:
|
||
|
if( bError )
|
||
|
return II_PhysicalPartition_Error; //II_FTPartition; The user shouldn't know about the existence of FTPartitions
|
||
|
else if( bWarning )
|
||
|
return II_PhysicalPartition_Warning;
|
||
|
else
|
||
|
return II_PhysicalPartition;
|
||
|
|
||
|
case FtVolumeSet:
|
||
|
if( bError )
|
||
|
return II_VolumeSet_Error;
|
||
|
else if( bWarning )
|
||
|
return II_VolumeSet_Warning;
|
||
|
else
|
||
|
return II_VolumeSet;
|
||
|
|
||
|
case FtStripeSet:
|
||
|
if( bError )
|
||
|
return II_StripeSet_Error;
|
||
|
else if( bWarning )
|
||
|
return II_StripeSet_Warning;
|
||
|
else
|
||
|
return II_StripeSet;
|
||
|
|
||
|
case FtMirrorSet:
|
||
|
if( bError )
|
||
|
return II_MirrorSet_Error;
|
||
|
else if( bWarning || ( m_StateInfo.stripeState.UnhealthyMemberState != FtMemberHealthy ) )
|
||
|
return II_MirrorSet_Warning;
|
||
|
else
|
||
|
return II_MirrorSet;
|
||
|
|
||
|
case FtStripeSetWithParity:
|
||
|
if( bError )
|
||
|
return II_StripeSetWithParity_Error;
|
||
|
else if( bWarning || ( m_StateInfo.stripeState.UnhealthyMemberState != FtMemberHealthy ) ||
|
||
|
( m_StateInfo.stripeState.IsInitializing ) )
|
||
|
return II_StripeSetWithParity_Warning;
|
||
|
else
|
||
|
return II_StripeSetWithParity;
|
||
|
|
||
|
case FtRedistribution:
|
||
|
// I don't have yet a bitmap for redistributions
|
||
|
ASSERT(FALSE);
|
||
|
if( bError )
|
||
|
return II_PhysicalPartition_Error;
|
||
|
else if( bWarning )
|
||
|
return II_PhysicalPartition_Warning;
|
||
|
else
|
||
|
return II_PhysicalPartition;
|
||
|
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
return II_PhysicalPartition_Error;
|
||
|
}
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|
||
|
BOOL CLogicalVolumeData::operator==(CItemData& rData) const
|
||
|
{
|
||
|
if( rData.GetItemType() != IT_LogicalVolume )
|
||
|
return FALSE;
|
||
|
|
||
|
CLogicalVolumeData* pLogVolData = (CLogicalVolumeData*)(&rData);
|
||
|
|
||
|
return( m_llVolID == pLogVolData->m_llVolID );
|
||
|
}
|
||
|
|
||
|
void CLogicalVolumeData::GetDisplayName( CString& strDisplay ) const
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
strDisplay = _T("");
|
||
|
for( int i = 0; i < m_arrMountPaths.GetSize(); i++ )
|
||
|
{
|
||
|
if( i != 0 )
|
||
|
strDisplay += _T("; ");
|
||
|
strDisplay += m_arrMountPaths[i];
|
||
|
}
|
||
|
|
||
|
if( strDisplay.IsEmpty() )
|
||
|
{
|
||
|
if( m_cDriveLetter )
|
||
|
strDisplay.Format(_T("%c:"), m_cDriveLetter );
|
||
|
/*
|
||
|
else
|
||
|
strDisplay.Format(_T("%I64X"), m_llVolID );
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
if( m_nVolType == FtPartition )
|
||
|
{
|
||
|
CString str;
|
||
|
str.Format( IDS_STR_PHYSICAL_PARTITION_NAME,
|
||
|
m_ConfigInfo.partConfig.Config.DiskNumber, m_ConfigInfo.partConfig.dwPartitionNumber );
|
||
|
if( !strDisplay.IsEmpty() )
|
||
|
strDisplay += _T(" ");
|
||
|
strDisplay += str;
|
||
|
}
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|
||
|
void CLogicalVolumeData::GetDisplayType( CString& strDisplay ) const
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
switch( m_nVolType )
|
||
|
{
|
||
|
case FtPartition:
|
||
|
//strDisplay.LoadString(IDS_TYPE_FTPARTITION);
|
||
|
switch( m_ConfigInfo.partConfig.wPartitionType )
|
||
|
{
|
||
|
case PT_Primary:
|
||
|
strDisplay.LoadString( IDS_TYPE_PRIMARY_PARTITION);
|
||
|
break;
|
||
|
case PT_InExtendedPartition:
|
||
|
strDisplay.LoadString( IDS_TYPE_PARTITION_IN_EXTENDED_PARTITION);
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
break;
|
||
|
case FtVolumeSet:
|
||
|
strDisplay.LoadString(IDS_TYPE_FTVOLUMESET);
|
||
|
break;
|
||
|
case FtStripeSet:
|
||
|
strDisplay.LoadString(IDS_TYPE_FTSTRIPESET);
|
||
|
break;
|
||
|
case FtMirrorSet:
|
||
|
strDisplay.LoadString(IDS_TYPE_FTMIRRORSET);
|
||
|
break;
|
||
|
case FtStripeSetWithParity:
|
||
|
strDisplay.LoadString(IDS_TYPE_FTSTRIPESETWITHPARITY);
|
||
|
break;
|
||
|
case FtRedistribution:
|
||
|
strDisplay.LoadString(IDS_TYPE_FTREDISTRIBUTION);
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
strDisplay = _T("");
|
||
|
}
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|
||
|
void CLogicalVolumeData::GetDisplayExtendedName( CString& strDisplay ) const
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
GetDisplayName( strDisplay );
|
||
|
|
||
|
if( m_nVolType != FtPartition )
|
||
|
{
|
||
|
CString strType;
|
||
|
GetDisplayType( strType );
|
||
|
if( !strDisplay.IsEmpty() )
|
||
|
strDisplay += _T(" ");
|
||
|
strDisplay += strType;
|
||
|
}
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CLogicalVolumeData::GetVolumeID( FT_LOGICAL_DISK_ID& llVolID ) const
|
||
|
{
|
||
|
llVolID = m_llVolID;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL CLogicalVolumeData::GetSize( LONGLONG& llSize ) const
|
||
|
{
|
||
|
llSize = m_llVolSize;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL CLogicalVolumeData::GetDiskNumber( ULONG& ulDiskNumber ) const
|
||
|
{
|
||
|
if( m_nVolType == FtPartition )
|
||
|
{
|
||
|
ulDiskNumber = m_ConfigInfo.partConfig.Config.DiskNumber;
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CLogicalVolumeData::GetOffset( LONGLONG& llOffset) const
|
||
|
{
|
||
|
if( m_nVolType == FtPartition )
|
||
|
{
|
||
|
llOffset = m_ConfigInfo.partConfig.Config.ByteOffset;
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Protected methods
|
||
|
|
||
|
|
||
|
BOOL CLogicalVolumeData::RetrieveNTName( CString& strNTName ) const
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
return FTQueryNTDeviceName( m_llVolID, strNTName );
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|
||
|
BOOL CLogicalVolumeData::RetrieveDisksSet()
|
||
|
{
|
||
|
MY_TRY
|
||
|
|
||
|
return FTGetDisksSet( m_llVolID, m_setDisks );
|
||
|
|
||
|
MY_CATCH_AND_THROW
|
||
|
}
|
||
|
|