|
|
/******************************************************************************
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
|