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

1208 lines
34 KiB

/******************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name:
drvtable.cpp
Abstract:
This file contains CRstrDriveInfo class and CreateDriveList function.
Revision History:
Seong Kook Khang (SKKhang) 07/20/00
created
******************************************************************************/
#include "stdwin.h"
#include "rstrcore.h"
#include "resource.h"
#include "..\shell\resource.h"
static LPCWSTR s_cszEmpty = L"";
WCHAR s_szSysDrv[MAX_PATH];
/////////////////////////////////////////////////////////////////////////////
//
// CRstrDriveInfo class
//
/////////////////////////////////////////////////////////////////////////////
//
// NOTE - 7/26/00 - skkhang
// CSRStr has one issue -- NULL return in case of memory failure. Even though
// the behavior is just same with regular C language pointer, many codes are
// blindly passing it to some external functions (e.g. strcmp) which does not
// gracefully handle NULL pointer. Ideally and eventually all of code should
// prevent any possible NULL pointers from getting passed to such functions,
// but for now, I'm using an alternative workaround -- GetID, GetMount, and
// GetLabel returns a static empty string instead of NULL pointer.
//
/////////////////////////////////////////////////////////////////////////////
// CRstrDriveInfo construction / destruction
CRstrDriveInfo::CRstrDriveInfo()
{
m_dwFlags = 0;
m_hIcon[0] = NULL;
m_hIcon[1] = NULL;
m_llDSMin = SR_DEFAULT_DSMIN * MEGABYTE;
m_llDSMax = SR_DEFAULT_DSMAX * MEGABYTE;
m_uDSUsage = 0;
m_fCfgExcluded = FALSE;
m_uCfgDSUsage = 0;
m_ulTotalBytes.QuadPart = 0;
}
CRstrDriveInfo::~CRstrDriveInfo()
{
if ( m_hIcon[0] != NULL )
::DestroyIcon( m_hIcon[0] );
if ( m_hIcon[1] != NULL )
::DestroyIcon( m_hIcon[1] );
}
BOOL CRstrDriveInfo::InitUsage (LPCWSTR cszID, INT64 llDSUsage)
{
TraceFunctEnter("CRstrDriveInfo::InitUsage");
//
// calculate max datastore size - max (12% of disk, 400mb)
//
// read % from registry
HKEY hKey = NULL;
DWORD dwPercent = SR_DEFAULT_DISK_PERCENT;
DWORD dwDSMax = SR_DEFAULT_DSMAX;
DWORD dwDSMin = IsSystem() ? SR_DEFAULT_DSMIN : SR_DEFAULT_DSMIN_NONSYSTEM;
ULARGE_INTEGER ulDummy;
DWORD dwRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
s_cszSRRegKey, 0, KEY_READ, &hKey);
if (ERROR_SUCCESS == dwRes)
{
RegReadDWORD(hKey, s_cszDiskPercent, &dwPercent);
RegReadDWORD(hKey, s_cszDSMax, &dwDSMax);
if (IsSystem())
RegReadDWORD(hKey, s_cszDSMin, &dwDSMin);
RegCloseKey(hKey);
}
else
{
ErrorTrace(0, "! RegOpenKeyEx : %ld", dwRes);
}
// BUGBUG - this call may not always give total disk space (per-user quota)
ulDummy.QuadPart = 0;
if (FALSE == GetDiskFreeSpaceEx (cszID, &ulDummy, &m_ulTotalBytes, NULL))
{
ErrorTrace(0, "! GetDiskFreeSpaceEx : %ld", GetLastError());
goto done;
}
m_llDSMin = min(m_ulTotalBytes.QuadPart, (INT64) dwDSMin * MEGABYTE);
m_llDSMax = min(m_ulTotalBytes.QuadPart,
max( (INT64) dwDSMax * MEGABYTE,
(INT64) dwPercent * m_ulTotalBytes.QuadPart / 100 ));
if (m_llDSMax < m_llDSMin)
m_llDSMax = m_llDSMin;
//
// take floor of this value
//
m_llDSMax = ((INT64) (m_llDSMax / (INT64) MEGABYTE)) * (INT64) MEGABYTE;
DebugTrace(0, "m_llDSMax: %I64d, Size: %I64d", m_llDSMax, llDSUsage);
if ( ( llDSUsage == 0) || (llDSUsage > m_llDSMax) )
// not initialized, assume maximum
{
llDSUsage = m_llDSMax;
}
if ( ( llDSUsage - m_llDSMin > 0) && ( m_llDSMax - m_llDSMin > 0))
{
// + ((llDSUsage - m_llDSMin)/2) is to ensure that correct
// rounding off happens here
m_uDSUsage =( ((llDSUsage - m_llDSMin) * DSUSAGE_SLIDER_FREQ)
+ ((m_llDSMax - m_llDSMin)/2))/( m_llDSMax - m_llDSMin);
}
else
m_uDSUsage = 0;
m_uCfgDSUsage = m_uDSUsage;
done:
TraceFunctLeave();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CRstrDriveInfo operations
BOOL
CRstrDriveInfo::Init( LPCWSTR cszID, DWORD dwFlags, INT64 llDSUsage, LPCWSTR cszMount, LPCWSTR cszLabel )
{
TraceFunctEnter("CRstrDriveInfo::Init");
BOOL fRet = FALSE;
LPCWSTR cszErr;
DWORD dwRes;
WCHAR szMount[MAX_PATH];
WCHAR szLabel[MAX_PATH];
m_dwFlags = dwFlags;
m_strID = cszID;
if ( !IsOffline() )
{
// Get Mount Point (drive letter or root directory path) from Unique Volume ID
//
if ( !::GetVolumePathNamesForVolumeName( cszID, szMount, MAX_PATH, &dwRes ) && GetLastError() != ERROR_MORE_DATA)
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::GetVolumePathNamesForVolumeName failed - %ls", cszErr);
// Instead of fail, use cszMount even if it may not accurate
::lstrcpy( szMount, cszMount );
}
else
{
szMount[MAX_PATH-1] = L'\0';
if (lstrlenW (szMount) > MAX_MOUNTPOINT_PATH)
{
// Instead of fail, use cszMount even if it may not accurate
::lstrcpy( szMount, cszMount );
}
}
// Get Volume Label from Mount Point
//
if ( !::GetVolumeInformation( cszID, szLabel, MAX_PATH, NULL, NULL, NULL, NULL, 0 ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::GetVolumeInformation failed - %ls", cszErr);
// Instead of fail, use cszLabel even if it may not accurate
::lstrcpy( szLabel, cszLabel );
}
}
if ( ( szMount[1] == L':' ) && ( szMount[2] == L'\\' ) && ( szMount[3] == L'\0' ) )
szMount[2] = L'\0';
m_strMount = szMount;
m_strLabel = szLabel;
InitUsage (cszID, llDSUsage);
m_fCfgExcluded = IsExcluded();
fRet = TRUE;
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::Init( LPCWSTR cszID, CDataStore *pDS, BOOL fOffline )
{
TraceFunctEnter("CRstrDriveInfo::Init");
BOOL fRet = FALSE;
LPCWSTR cszErr;
DWORD dwRes;
WCHAR szMount[MAX_PATH];
WCHAR szLabel[MAX_PATH];
m_strID = cszID;
UpdateStatus( pDS->GetFlags(), fOffline );
if ( !fOffline )
{
// Get Mount Point (drive letter or root directory path) from Unique Volume ID
//
if ( !::GetVolumePathNamesForVolumeName( cszID, szMount, MAX_PATH, &dwRes ) && GetLastError() != ERROR_MORE_DATA )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::GetVolumePathNamesForVolumeName failed - %ls", cszErr);
goto Exit;
}
else
{
szMount[MAX_PATH-1] = L'\0';
if (lstrlenW (szMount) > MAX_MOUNTPOINT_PATH)
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "mount point too long %ls", cszErr);
goto Exit;
}
}
// Get Volume Label from Mount Point
//
if ( !::GetVolumeInformation( cszID, szLabel, MAX_PATH, NULL, NULL, NULL, NULL, 0 ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::GetVolumeInformation failed - %ls", cszErr);
// this is not a fatal error - this can happen if the
// volume is being formatted for example. assume that the
// label is empty
szLabel[0]= L'\0';
}
}
else
{
::lstrcpyW (szMount, pDS->GetDrive());
::lstrcpyW (szLabel, pDS->GetLabel());
}
if ( ( szMount[1] == L':' ) && ( szMount[2] == L'\\' ) && ( szMount[3] == L'\0' ) )
szMount[2] = L'\0';
m_strMount = szMount;
m_strLabel = szLabel;
InitUsage (cszID, pDS->GetSizeLimit());
m_fCfgExcluded = IsExcluded();
fRet = TRUE;
Exit:
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::LoadFromLog( HANDLE hfLog )
{
TraceFunctEnter("CRstrDriveInfo::LoadFromLog");
BOOL fRet = FALSE;
DWORD dwRes;
WCHAR szBuf[MAX_PATH];
// Read m_dwFlags
READFILE_AND_VALIDATE( hfLog, &m_dwFlags, sizeof(DWORD), dwRes, Exit );
// Read m_strID
if ( !::ReadStrAlign4( hfLog, szBuf ) )
{
ErrorTrace(0, "Cannot read drive ID...");
goto Exit;
}
if ( szBuf[0] == L'\0' )
{
ErrorTrace(0, "Drive Guid is empty...");
goto Exit;
}
m_strID = szBuf;
// Read m_strMount
if ( !::ReadStrAlign4( hfLog, szBuf ) )
{
ErrorTrace(0, "Cannot read drive mount point...");
goto Exit;
}
m_strMount = szBuf;
// Read m_strLabel
if ( !::ReadStrAlign4( hfLog, szBuf ) )
{
ErrorTrace(0, "Cannot read drive mount point...");
goto Exit;
}
m_strLabel = szBuf;
m_fCfgExcluded = IsExcluded();
// m_nCfgMaxSize = ...
fRet = TRUE;
Exit:
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
void
CRstrDriveInfo::UpdateStatus( DWORD dwFlags, BOOL fOffline )
{
TraceFunctEnter("CRstrDriveInfo::UpdateStatus");
m_dwFlags = 0;
if ( fOffline )
{
m_dwFlags |= RDIF_OFFLINE;
}
else
{
// check if frozen
if ( ( dwFlags & SR_DRIVE_FROZEN ) != 0 )
m_dwFlags |= RDIF_FROZEN;
// check if system drive
if ( ( dwFlags & SR_DRIVE_SYSTEM ) != 0 )
{
m_dwFlags |= RDIF_SYSTEM;
}
else
{
// if not system drive, simply use MONITORED flag of drive table
if ( ( dwFlags & SR_DRIVE_MONITORED ) == 0 )
m_dwFlags |= RDIF_EXCLUDED;
}
}
DebugTrace(0, "Status has been updated, m_dwFlags=%08X", m_dwFlags);
TraceFunctLeave();
}
/////////////////////////////////////////////////////////////////////////////
// CRstrDriveInfo - methods
DWORD
CRstrDriveInfo::GetFlags()
{
return( m_dwFlags );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::IsExcluded()
{
return( ( m_dwFlags & RDIF_EXCLUDED ) != 0 );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::IsFrozen()
{
return( ( m_dwFlags & RDIF_FROZEN ) != 0 );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::IsOffline()
{
return( ( m_dwFlags & RDIF_OFFLINE ) != 0 );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::IsSystem()
{
return( ( m_dwFlags & RDIF_SYSTEM ) != 0 );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::RefreshStatus()
{
TraceFunctEnter("CRstrDriveInfo::RefreshStatus");
BOOL fRet = FALSE;
LPCWSTR cszErr;
WCHAR szDTFile[MAX_PATH];
DWORD dwRes;
CDriveTable cDrvTable;
CDataStore *pDS;
::MakeRestorePath( szDTFile, s_szSysDrv, NULL );
::PathAppend( szDTFile, s_cszDriveTable );
DebugTrace(0, "Loading drive table - %ls", szDTFile);
dwRes = cDrvTable.LoadDriveTable( szDTFile );
if ( dwRes != ERROR_SUCCESS )
{
cszErr = ::GetSysErrStr( dwRes );
ErrorTrace(0, "Cannot load a drive table - %ls", cszErr);
ErrorTrace(0, " szDTFile: '%ls'", szDTFile);
goto Exit;
}
dwRes = cDrvTable.RemoveDrivesFromTable();
if ( dwRes != ERROR_SUCCESS )
{
cszErr = ::GetSysErrStr( dwRes );
ErrorTrace(0, "CDriveTable::RemoveDrivesFromTable failed - %ls", cszErr);
// ignore error
}
pDS = cDrvTable.FindGuidInTable( (LPWSTR)GetID() );
if ( pDS == NULL )
UpdateStatus( 0, TRUE );
else
UpdateStatus( pDS->GetFlags(), FALSE );
fRet = TRUE;
Exit:
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
LPCWSTR
CRstrDriveInfo::GetID()
{
return( ( m_strID.Length() > 0 ) ? m_strID : s_cszEmpty );
}
/////////////////////////////////////////////////////////////////////////////
LPCWSTR
CRstrDriveInfo::GetMount()
{
return( ( m_strMount.Length() > 0 ) ? m_strMount : s_cszEmpty );
}
/////////////////////////////////////////////////////////////////////////////
LPCWSTR
CRstrDriveInfo::GetLabel()
{
return( ( m_strLabel.Length() > 0 ) ? m_strLabel : s_cszEmpty );
}
/////////////////////////////////////////////////////////////////////////////
void
CRstrDriveInfo::SetMountAndLabel( LPCWSTR cszMount, LPCWSTR cszLabel )
{
TraceFunctEnter("CRstrDriveInfo::SetMountAndLabel");
m_strMount = cszMount;
m_strLabel = cszLabel;
TraceFunctLeave();
}
/////////////////////////////////////////////////////////////////////////////
HICON
CRstrDriveInfo::GetIcon( BOOL fSmall )
{
TraceFunctEnter("CRstrDriveInfo::GetIcon");
LPCWSTR cszErr;
int nIdx = fSmall ? 0 : 1;
int cxIcon, cyIcon;
HICON hIcon;
if ( m_hIcon[nIdx] != NULL )
goto Exit;
cxIcon = ::GetSystemMetrics( fSmall ? SM_CXSMICON : SM_CXICON );
cyIcon = ::GetSystemMetrics( fSmall ? SM_CYSMICON : SM_CYICON );
hIcon = (HICON)::LoadImage( g_hInst, MAKEINTRESOURCE(IDI_DRIVE_FIXED),
IMAGE_ICON, cxIcon, cyIcon, LR_DEFAULTCOLOR );
if ( hIcon == NULL )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::LoadImage failed - %ls", cszErr);
goto Exit;
}
m_hIcon[nIdx] = hIcon;
Exit:
TraceFunctLeave();
return( m_hIcon[nIdx] );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::SaveToLog( HANDLE hfLog )
{
TraceFunctEnter("CRstrDriveInfo::SaveToLog");
BOOL fRet = FALSE;
BYTE pbBuf[7*MAX_PATH];
DWORD dwSize = 0;
DWORD dwRes;
*((DWORD*)pbBuf) = m_dwFlags;
dwSize += sizeof(DWORD);
dwSize += ::StrCpyAlign4( pbBuf+dwSize, m_strID );
dwSize += ::StrCpyAlign4( pbBuf+dwSize, m_strMount );
dwSize += ::StrCpyAlign4( pbBuf+dwSize, m_strLabel );
WRITEFILE_AND_VALIDATE( hfLog, pbBuf, dwSize, dwRes, Exit );
fRet = TRUE;
Exit:
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
UINT
CRstrDriveInfo::GetDSUsage()
{
TraceFunctEnter("CRstrDriveInfo::GetDSUsage");
TraceFunctLeave();
return( m_uDSUsage );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::GetUsageText( LPWSTR szUsage )
{
TraceFunctEnter("CRstrDriveInfo::GetUsageText");
INT64 llUsage;
int nPercent;
int nUsage;
if (m_llDSMax - m_llDSMin > 0)
llUsage = m_llDSMin + ( m_llDSMax - m_llDSMin ) * m_uCfgDSUsage / DSUSAGE_SLIDER_FREQ;
else
llUsage = m_llDSMin;
if (m_ulTotalBytes.QuadPart != 0)
{
// the m_ulTotalBytes.QuadPart/200 addition is to ensure that
// the correct round off happens
nPercent = (llUsage + (m_ulTotalBytes.QuadPart/200)) * 100/
m_ulTotalBytes.QuadPart;
}
else nPercent = 0;
nUsage = llUsage / ( 1024 * 1024 );
::wsprintf( szUsage, L"%d%% (%d MB)", nPercent, nUsage );
TraceFunctLeave();
return( TRUE );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::GetCfgExcluded( BOOL *pfExcluded )
{
TraceFunctEnter("CRstrDriveInfo::GetCfgExcluded");
BOOL fRet = FALSE;
if ( m_fCfgExcluded != IsExcluded() )
{
*pfExcluded = m_fCfgExcluded;
fRet = TRUE;
}
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
void
CRstrDriveInfo::SetCfgExcluded( BOOL fExcluded )
{
TraceFunctEnter("CRstrDriveInfo::SetCfgExcluded");
m_fCfgExcluded = fExcluded;
TraceFunctLeave();
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::GetCfgDSUsage( UINT *puPos )
{
TraceFunctEnter("CRstrDriveInfo::GetCfgDSUsage");
BOOL fRet = FALSE;
if ( m_uCfgDSUsage != m_uDSUsage )
{
*puPos = m_uCfgDSUsage;
fRet = TRUE;
}
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
void
CRstrDriveInfo::SetCfgDSUsage( UINT uPos )
{
TraceFunctEnter("CRstrDriveInfo::SetCfgDSUsage");
m_uCfgDSUsage = uPos;
TraceFunctLeave();
}
/////////////////////////////////////////////////////////////////////////////
void
CloseRestoreUI()
{
WCHAR szPath[MAX_PATH], szTitle[MAX_PATH] = L"";
if (ExpandEnvironmentStrings(L"%windir%\\system32\\restore\\rstrui.exe", szPath, MAX_PATH))
{
if (ERROR_SUCCESS == SRLoadString(szPath, IDS_RESTOREUI_TITLE, szTitle, MAX_PATH))
{
HWND hWnd = FindWindow(CLSNAME_RSTRSHELL, szTitle);
if (hWnd != NULL)
PostMessage(hWnd, WM_CLOSE, 0, 0);
}
}
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::ApplyConfig( HWND hWnd )
{
TraceFunctEnter("CRstrDriveInfo::ApplyConfig");
BOOL fRet = FALSE;
LPCWSTR cszErr;
INT64 llUsage;
DWORD dwRes;
if ( m_fCfgExcluded != IsExcluded() )
{
if ( m_fCfgExcluded )
{
WCHAR szTitle[MAX_STR];
WCHAR szMsg[MAX_STR+2*MAX_PATH];
// Confirm if it's ok to turn drive or SR off.
::LoadString( g_hInst, IDS_SYSTEMRESTORE, szTitle,
sizeof(szTitle)/sizeof(WCHAR) );
if ( IsSystem() )
::LoadString( g_hInst, IDS_CONFIRM_TURN_SR_OFF, szMsg,
sizeof(szMsg)/sizeof(WCHAR) );
else
{
::SRFormatMessage( szMsg, IDS_CONFIRM_TURN_DRV_OFF, GetLabel() ? GetLabel() : L"", GetMount() );
}
if ( ::MessageBox( hWnd, szMsg, szTitle, MB_YESNO ) == IDNO )
{
m_fCfgExcluded = IsExcluded();
goto Exit;
}
//
// if disabling all of SR, close the wizard if open
//
if (IsSystem())
{
CloseRestoreUI();
}
dwRes = ::DisableSR( m_strID );
if ( dwRes != ERROR_SUCCESS )
{
ShowSRErrDlg (IDS_ERR_SR_ON_OFF);
cszErr = ::GetSysErrStr( dwRes );
ErrorTrace(0, "::DisableSR failed - %ls", cszErr);
goto Exit;
}
m_dwFlags |= RDIF_EXCLUDED;
}
else
{
//
// make a synchronous call to enable sr
// this will block till the firstrun checkpoint is created
// and the service is fully initialized
//
dwRes = ::EnableSREx( m_strID, TRUE );
if ( dwRes != ERROR_SUCCESS )
{
ShowSRErrDlg (IDS_ERR_SR_ON_OFF);
cszErr = ::GetSysErrStr( dwRes );
ErrorTrace(0, "::EnableSR failed - %ls", cszErr);
goto Exit;
}
m_dwFlags &= ~RDIF_EXCLUDED;
}
}
if ( m_uCfgDSUsage != m_uDSUsage )
{
if (m_llDSMax - m_llDSMin > 0)
llUsage = m_llDSMin + (m_llDSMax - m_llDSMin)* m_uCfgDSUsage /DSUSAGE_SLIDER_FREQ;
else
llUsage = m_llDSMin;
dwRes = ::SRUpdateDSSize( m_strID, llUsage );
if ( dwRes != ERROR_SUCCESS )
{
LPCWSTR cszErr = ::GetSysErrStr( dwRes );
ErrorTrace(0, "::SRUpdateDriveTable failed - %ls", cszErr);
goto Exit;
}
m_uDSUsage = m_uCfgDSUsage;
}
fRet = TRUE;
Exit:
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRstrDriveInfo::Release()
{
TraceFunctEnter("CRstrDriveInfo::Release");
delete this;
TraceFunctLeave();
return( TRUE );
}
/////////////////////////////////////////////////////////////////////////////
//
// Helper Function
//
/////////////////////////////////////////////////////////////////////////////
//
// Enumerate Volumes without Drive Table if SR is disabled and DS not exists.
//
BOOL
EnumVolumes( CRDIArray &aryDrv )
{
TraceFunctEnter("EnumVolumes");
BOOL fRet = FALSE;
LPCWSTR cszErr;
HANDLE hEnumVol = INVALID_HANDLE_VALUE;
WCHAR szVolume[MAX_PATH];
WCHAR szMount[MAX_PATH];
DWORD cbMount;
CRstrDriveInfo *pDrv = NULL;
DWORD dwFlags;
hEnumVol = ::FindFirstVolume( szVolume, MAX_PATH );
if ( hEnumVol == INVALID_HANDLE_VALUE )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::FindFirstVolume failed - %ls", cszErr);
goto Exit;
}
// dummy space for system drive
if ( !aryDrv.AddItem( NULL ) )
goto Exit;
do
{
HANDLE hfDrv;
DebugTrace(0, "Guid=%ls", szVolume);
if ( !::GetVolumePathNamesForVolumeName( szVolume, szMount, MAX_PATH, &cbMount ) && GetLastError() != ERROR_MORE_DATA)
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::GetVolumePathNamesForVolumeName failed - %ls", cszErr);
continue;
}
else
{
szMount[MAX_PATH-1] = L'\0';
if (lstrlenW (szMount) > MAX_MOUNTPOINT_PATH)
continue;
}
DebugTrace(0, " Mount=%ls", szMount);
if ( ::GetDriveType( szMount ) != DRIVE_FIXED )
{
DebugTrace(0, "Non-fixed drive");
// includes only the fixed drives.
continue;
}
hfDrv = ::CreateFile( szVolume, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
if ( hfDrv == INVALID_HANDLE_VALUE )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::CreateFile(volume) failed - %ls", cszErr);
// probably an unformatted drive.
continue;
}
::CloseHandle( hfDrv );
pDrv = new CRstrDriveInfo;
if ( pDrv == NULL )
{
FatalTrace(0, "Insufficient memory...");
goto Exit;
}
dwFlags = RDIF_EXCLUDED;
if ( ::IsSystemDrive( szVolume ) )
{
dwFlags |= RDIF_SYSTEM;
if ( !aryDrv.SetItem( 0, pDrv ) )
goto Exit;
}
else
{
if ( !aryDrv.AddItem( pDrv ) )
goto Exit;
}
if ( !pDrv->Init( szVolume, dwFlags, 0, szMount, NULL ) )
goto Exit;
pDrv = NULL;
}
while ( ::FindNextVolume( hEnumVol, szVolume, MAX_PATH ) );
fRet = TRUE;
Exit:
if ( pDrv != NULL )
if ( hEnumVol != INVALID_HANDLE_VALUE )
::FindVolumeClose( hEnumVol );
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
LoadDriveTable( LPCWSTR cszRPDir, CRDIArray &aryDrv, BOOL fRemoveDrives)
{
TraceFunctEnter("LoadDriveTable");
BOOL fRet = FALSE;
LPCWSTR cszErr;
WCHAR szDTFile[MAX_PATH];
DWORD dwRes;
CDriveTable cDrvTable;
SDriveTableEnumContext sDTEnum = { NULL, 0 };
CDataStore *pDS;
CRstrDriveInfo *pDrv = NULL;
BOOL fOffline;
::MakeRestorePath( szDTFile, s_szSysDrv, cszRPDir );
::PathAppend( szDTFile, s_cszDriveTable );
DebugTrace(0, "Loading drive table - %ls", szDTFile);
dwRes = cDrvTable.LoadDriveTable( szDTFile );
if ( dwRes != ERROR_SUCCESS )
{
cszErr = ::GetSysErrStr( dwRes );
ErrorTrace(0, "Cannot load a drive table - %ls", cszErr);
ErrorTrace(0, " szDTFile: '%ls'", szDTFile);
goto Exit;
}
// If this is for the current drive table, try to update information
// about removed volumes.
if ( cszRPDir == NULL )
{
if (fRemoveDrives)
cDrvTable.RemoveDrivesFromTable();
else
{
sDTEnum.Reset();
pDS = cDrvTable.FindFirstDrive (sDTEnum);
while (pDS != NULL)
{
pDS->IsVolumeDeleted(); // mark deleted volumes as inactive
pDS = cDrvTable.FindNextDrive( sDTEnum );
}
}
}
sDTEnum.Reset();
pDS = cDrvTable.FindFirstDrive( sDTEnum );
while ( pDS != NULL )
{
int i;
LPCWSTR cszGuid = pDS->GetGuid();
DebugTrace(0, "Drive: %ls %ls", pDS->GetDrive(), cszGuid);
if ( cszRPDir != NULL ) // not the current restore point
{
for ( i = aryDrv.GetUpperBound(); i >= 0; i-- )
{
CRstrDriveInfo *pExist = aryDrv.GetItem( i );
if ( ::lstrcmpi( cszGuid, pExist->GetID() ) == 0 )
{
// Match has been found. Check if it's offline, in which
// case mount point and volume label should be updated to the
// latest ones.
if ( pExist->IsOffline() )
pExist->SetMountAndLabel( pDS->GetDrive(), pDS->GetLabel() );
break;
}
pDrv = NULL;
}
if ( i >= 0 )
goto NextDrv;
}
pDrv = new CRstrDriveInfo;
if ( pDrv == NULL )
{
FatalTrace(0, "Insufficient memory...");
goto Exit;
}
//
// mark a drive as offline if it's not in the current restore point
// or it's inactive in the current restore point
//
fOffline = (cszRPDir != NULL) || !(pDS->GetFlags() & SR_DRIVE_ACTIVE);
if ( !pDrv->Init( cszGuid, pDS, fOffline ) )
goto Exit;
if (( pDrv->GetMount() == NULL ) || ( (pDrv->GetMount())[0] == L'\0' ))
{
pDrv->Release();
goto NextDrv;
}
if ( pDrv->IsSystem() )
{
if ( !aryDrv.SetItem( 0, pDrv ) )
goto Exit;
}
else
{
if ( !aryDrv.AddItem( pDrv ) )
goto Exit;
}
pDrv = NULL;
NextDrv:
pDS = cDrvTable.FindNextDrive( sDTEnum );
}
fRet = TRUE;
Exit:
if ( !fRet )
SAFE_RELEASE(pDrv);
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
BOOL
UpdateDriveList( CRDIArray &aryDrv )
{
TraceFunctEnter("UpdateDriveTable");
BOOL fRet = FALSE;
LPCWSTR cszErr;
DWORD dwDisable = 0;
WCHAR szDTFile[MAX_PATH];
DWORD dwRes;
CDriveTable cDrvTable;
CDataStore *pDS;
CRstrDriveInfo *pDrv;
int i;
// Check if SR is disabled
if ( ::SRGetRegDword( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszDisableSR, &dwDisable ) )
if ( dwDisable != 0 )
{
for ( i = aryDrv.GetUpperBound(); i >= 0; i-- )
{
pDrv = (CRstrDriveInfo*)aryDrv[i];
pDrv->UpdateStatus( SR_DRIVE_FROZEN, FALSE );
}
goto Done;
}
::MakeRestorePath( szDTFile, s_szSysDrv, NULL );
::PathAppend( szDTFile, s_cszDriveTable );
DebugTrace(0, "Loading drive table - %ls", szDTFile);
dwRes = cDrvTable.LoadDriveTable( szDTFile );
if ( dwRes != ERROR_SUCCESS )
{
cszErr = ::GetSysErrStr( dwRes );
ErrorTrace(0, "Cannot load a drive table - %ls", cszErr);
ErrorTrace(0, " szDTFile: '%ls'", szDTFile);
goto Exit;
}
dwRes = cDrvTable.RemoveDrivesFromTable();
if ( dwRes != ERROR_SUCCESS )
{
cszErr = ::GetSysErrStr( dwRes );
ErrorTrace(0, "CDriveTable::RemoveDrivesFromTable failed - %ls", cszErr);
// ignore error
}
for ( i = aryDrv.GetUpperBound(); i >= 0; i-- )
{
pDrv = (CRstrDriveInfo*)aryDrv[i];
pDS = cDrvTable.FindGuidInTable( (LPWSTR)pDrv->GetID() );
if ( ( pDS == NULL ) || ( pDS->GetDrive() == NULL ) || ( (pDS->GetDrive())[0] == L'\0' ) )
pDrv->UpdateStatus( 0, TRUE );
else
pDrv->UpdateStatus( pDS->GetFlags(), FALSE );
}
Done:
fRet = TRUE;
Exit:
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
//
// CreateAndLoadDriveInfoInstance
//
// This routine creates a CRstrDriveInfo class instance and load the content
// from a log file.
//
/////////////////////////////////////////////////////////////////////////////
BOOL
CreateAndLoadDriveInfoInstance( HANDLE hfLog, CRstrDriveInfo **ppRDI )
{
TraceFunctEnter("CreateAndLoadDriveInfoInstance");
BOOL fRet = FALSE;
CRstrDriveInfo *pRDI=NULL;
if ( ppRDI == NULL )
{
ErrorTrace(0, "Invalid parameter, ppRDI is NULL.");
goto Exit;
}
*ppRDI = NULL;
pRDI = new CRstrDriveInfo;
if ( pRDI == NULL )
{
ErrorTrace(0, "Insufficient memory...");
goto Exit;
}
if ( !pRDI->LoadFromLog( hfLog ) )
goto Exit;
*ppRDI = pRDI;
fRet = TRUE;
Exit:
if ( !fRet )
SAFE_RELEASE(pRDI);
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
//
// CreateDriveList
//
// This routine creates a drive list consists of CDriveInfo class instances.
//
/////////////////////////////////////////////////////////////////////////////
BOOL
CreateDriveList( int nRP, CRDIArray &aryDrv, BOOL fRemoveDrives )
{
TraceFunctEnter("CreateDriveList");
BOOL fRet = FALSE;
LPCWSTR cszErr;
DWORD fDisable;
if ( !::GetSystemDrive( s_szSysDrv ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "Cannot get system drive - %ls", cszErr);
goto Exit;
}
DebugTrace(0, "SystemDrive=%ls", s_szSysDrv);
// Check if SR is disabled
if ( !::SRGetRegDword( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszDisableSR, &fDisable ) )
{
DebugTrace(0, "Cannot get disable reg key");
goto Exit;
}
if ( fDisable )
{
DebugTrace(0, "SR is DISABLED!!!");
// Enumerate instead of reading drive table...
if ( !EnumVolumes( aryDrv ) )
goto Exit;
}
else
{
// dummy space for system drive
if ( !aryDrv.AddItem( NULL ) )
goto Exit;
// process the current drive table...
if ( !LoadDriveTable( NULL, aryDrv, fRemoveDrives ) )
{
DebugTrace(0, "Loading current drive table failed");
goto Exit;
}
if ( nRP > 0 )
{
CRestorePointEnum cEnum( s_szSysDrv, FALSE, FALSE );
CRestorePoint cRP;
DWORD dwRes;
dwRes = cEnum.FindFirstRestorePoint( cRP );
if ( dwRes != ERROR_SUCCESS && dwRes != ERROR_FILE_NOT_FOUND )
{
cszErr = ::GetSysErrStr(dwRes);
ErrorTrace(0, "CRestorePointEnum::FindFirstRestorePoint failed - %ls", cszErr);
goto Exit;
}
while ( (dwRes == ERROR_SUCCESS || dwRes == ERROR_FILE_NOT_FOUND) && ( cRP.GetNum() >= nRP ))
{
dwRes = cEnum.FindNextRestorePoint( cRP );
if ( dwRes == ERROR_NO_MORE_ITEMS )
break;
if ( dwRes != ERROR_SUCCESS && dwRes != ERROR_FILE_NOT_FOUND )
{
cszErr = ::GetSysErrStr(dwRes);
ErrorTrace(0, "CRestorePointEnum::FindNextRestorePoint failed - %ls", cszErr);
goto Exit;
}
DebugTrace(0, "RPNum=%d", cRP.GetNum());
if ( cRP.GetNum() >= nRP )
{
// process drive table of each RP...
if ( !LoadDriveTable( cRP.GetDir(), aryDrv, fRemoveDrives))
{
// The last restore point does not have drive table...
// simply ignore it.
}
}
}
}
}
fRet = TRUE;
Exit:
TraceFunctLeave();
return( fRet );
}
// end of file