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.
860 lines
24 KiB
860 lines
24 KiB
/******************************************************************************
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
api.cpp
|
|
|
|
Abstract:
|
|
This file contains the top level APIs, InitiateRestore and ResumeRestore.
|
|
|
|
Revision History:
|
|
Seong Kook Khang (SKKhang) 06/20/00
|
|
created
|
|
|
|
******************************************************************************/
|
|
|
|
#include "stdwin.h"
|
|
#include "rstrcore.h"
|
|
#include "resource.h"
|
|
extern CSRClientLoader g_CSRClientLoader;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnsureTrace
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//static BOOL s_fTraceEnabled = FALSE;
|
|
static DWORD s_dwTraceCount = 0;
|
|
|
|
void EnsureTrace()
|
|
{
|
|
if ( s_dwTraceCount++ == 0 )
|
|
{
|
|
::InitAsyncTrace();
|
|
}
|
|
}
|
|
|
|
void ReleaseTrace()
|
|
{
|
|
if ( --s_dwTraceCount == 0 )
|
|
{
|
|
::TermAsyncTrace();
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CRestoreContext
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CRestoreContext : public IRestoreContext
|
|
{
|
|
public:
|
|
CRestoreContext();
|
|
|
|
protected:
|
|
~CRestoreContext();
|
|
|
|
// operations - IRestoreContext methods
|
|
public:
|
|
BOOL IsAnyDriveOfflineOrDisabled( LPWSTR szOffline );
|
|
void SetSilent();
|
|
void SetUndo();
|
|
BOOL Release();
|
|
|
|
// attributes
|
|
public:
|
|
int m_nRP;
|
|
CRDIArray m_aryDrv;
|
|
BOOL m_fSilent;
|
|
BOOL m_fUndo;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRestoreContext - construction / destruction
|
|
|
|
CRestoreContext::CRestoreContext()
|
|
{
|
|
m_nRP = -1;
|
|
m_fSilent = FALSE;
|
|
m_fUndo = FALSE;
|
|
}
|
|
|
|
CRestoreContext::~CRestoreContext()
|
|
{
|
|
m_aryDrv.DeleteAll();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRestoreContext - IRestoreContext methods
|
|
|
|
BOOL
|
|
CRestoreContext::IsAnyDriveOfflineOrDisabled( LPWSTR szOffline )
|
|
{
|
|
TraceFunctEnter("CRestoreContext::IsAnyDriveOffline");
|
|
BOOL fRet = FALSE;
|
|
|
|
szOffline[0] = L'\0';
|
|
|
|
for ( int i = m_aryDrv.GetUpperBound(); i >= 0; i-- )
|
|
{
|
|
if ( m_aryDrv[i]->IsOffline() || m_aryDrv[i]->IsExcluded())
|
|
{
|
|
::lstrcat( szOffline, L" " );
|
|
::lstrcat( szOffline, m_aryDrv[i]->GetMount() );
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return( fRet );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
CRestoreContext::SetSilent()
|
|
{
|
|
TraceFunctEnter("CRestoreContext::SetSilent");
|
|
m_fSilent = TRUE;
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
CRestoreContext::SetUndo()
|
|
{
|
|
TraceFunctEnter("CRestoreContext::SetUndo");
|
|
m_fUndo = TRUE;
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
CRestoreContext::Release()
|
|
{
|
|
TraceFunctEnter("CRestoreContext::Release");
|
|
delete this;
|
|
TraceFunctLeave();
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Helper Functions
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
IsAdminUser()
|
|
{
|
|
TraceFunctEnter("IsAdminUser");
|
|
BOOL fRet = FALSE;
|
|
LPCWSTR cszErr;
|
|
PSID pSidAdmin = NULL;
|
|
SID_IDENTIFIER_AUTHORITY cSIA = SECURITY_NT_AUTHORITY;
|
|
BOOL fRes;
|
|
|
|
if ( !::AllocateAndInitializeSid( &cSIA, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0, &pSidAdmin ) )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::AllocateAndInitializeSid failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( !::CheckTokenMembership( NULL, pSidAdmin, &fRes ) )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::CheckMembership failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
|
|
DebugTrace(0, "IsAdminUser = %d", fRes);
|
|
|
|
fRet = fRes;
|
|
Exit:
|
|
if ( pSidAdmin != NULL )
|
|
::FreeSid( pSidAdmin );
|
|
TraceFunctLeave();
|
|
return( fRet );
|
|
}
|
|
|
|
//
|
|
// NOTE: 7/28/00 - skkhang
|
|
// Behavior of AdjustTokenPrivilege is a little bit confusing.
|
|
// It returns TRUE if given privilege does not exist at all, so you need to
|
|
// call GetLastError to see if it's ERROR_SUCCESS or ERROR_NOT_ALL_ASSIGNED
|
|
// (meaning the privilege does not exist.)
|
|
// Also, if the privilege was already enabled, tpOld will be empty. You
|
|
// don't need to restore the privilege in that case.
|
|
//
|
|
BOOL
|
|
CheckPrivilege( LPCWSTR szPriv, BOOL fCheckOnly )
|
|
{
|
|
TraceFunctEnter("CheckPrivilege");
|
|
BOOL fRet = FALSE;
|
|
LPCWSTR cszErr;
|
|
HANDLE hToken = NULL;
|
|
LUID luid;
|
|
TOKEN_PRIVILEGES tpNew;
|
|
TOKEN_PRIVILEGES tpOld;
|
|
DWORD dwRes;
|
|
|
|
// Prepare Process Token
|
|
if ( !::OpenProcessToken( ::GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&hToken ) )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::OpenProcessToken failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
|
|
// Get Luid
|
|
if ( !::LookupPrivilegeValue( NULL, szPriv, &luid ) )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::LookupPrivilegeValue failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
|
|
// Try to enable the privilege
|
|
tpNew.PrivilegeCount = 1;
|
|
tpNew.Privileges[0].Luid = luid;
|
|
tpNew.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
if ( !::AdjustTokenPrivileges( hToken, FALSE, &tpNew, sizeof(tpNew), &tpOld, &dwRes ) )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::AdjustTokenPrivileges(ENABLE) failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( ::GetLastError() == ERROR_NOT_ALL_ASSIGNED )
|
|
{
|
|
// This means process does not even have the privilege so
|
|
// AdjustTokenPrivilege simply ignored the request.
|
|
ErrorTrace(0, "Privilege '%ls' does not exist, probably user is not an admin.", szPriv);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( fCheckOnly )
|
|
{
|
|
// Restore the privilege if it was not enabled
|
|
if ( tpOld.PrivilegeCount > 0 )
|
|
{
|
|
if ( !::AdjustTokenPrivileges( hToken, FALSE, &tpOld, sizeof(tpOld), NULL, NULL ) )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::AdjustTokenPrivileges(RESTORE) failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
if ( hToken != NULL )
|
|
::CloseHandle( hToken );
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IsSRFrozen
|
|
//
|
|
// This routine checks if SR is frozen. If any error happens during Drive
|
|
// Table creation or System Drive does not exist (broken drive table???),
|
|
// return value is FALSE.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL APIENTRY
|
|
IsSRFrozen()
|
|
{
|
|
EnsureTrace();
|
|
TraceFunctEnter("IsSRFrozen");
|
|
BOOL fRet = FALSE;
|
|
CRDIArray aryDrv;
|
|
int i;
|
|
|
|
// Load SRClient
|
|
g_CSRClientLoader.LoadSrClient();
|
|
|
|
if ( !::CreateDriveList( 0, aryDrv, TRUE ) )
|
|
goto Exit;
|
|
|
|
for ( i = aryDrv.GetUpperBound(); i >= 0; i-- )
|
|
{
|
|
if ( aryDrv[i]->IsSystem() )
|
|
{
|
|
fRet = aryDrv[i]->IsFrozen();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
TraceFunctLeave();
|
|
ReleaseTrace();
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CheckPrivilegesForRestore
|
|
//
|
|
// This routine checks if necessary privileges can be set, to verify if
|
|
// logon user has necessary credential (Administrators or Backup Operators.)
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL APIENTRY
|
|
CheckPrivilegesForRestore()
|
|
{
|
|
EnsureTrace();
|
|
TraceFunctEnter("CheckPrivilegesForRestore");
|
|
BOOL fRet = FALSE;
|
|
|
|
// Load SRClient
|
|
g_CSRClientLoader.LoadSrClient();
|
|
|
|
// NOTE: 8/17/00 - skkhang
|
|
//
|
|
// Backup operator does not have below two privileges... SE_SECURITY_NAME
|
|
// is enabled by default for SYSTEM so probably can simply removed, but
|
|
// SE_TAKE_OWNERSHIP is off for SYSTEM and needs to be turned on. To solve
|
|
// the problem, this routine should accept parameter to distinguish
|
|
// "Check"(from UI) and "Set"(from ResumeRestore.)
|
|
//
|
|
if ( !::CheckPrivilege( SE_SECURITY_NAME, FALSE ) )
|
|
{
|
|
ErrorTrace(0, "Cannot enable SE_SECURITY_NAME privilege...");
|
|
goto Exit;
|
|
}
|
|
if ( !::CheckPrivilege( SE_TAKE_OWNERSHIP_NAME, FALSE ) )
|
|
{
|
|
ErrorTrace(0, "Cannot enable SE_SHUTDOWN_NAME privilege...");
|
|
goto Exit;
|
|
}
|
|
|
|
if ( !::CheckPrivilege( SE_BACKUP_NAME, FALSE ) )
|
|
{
|
|
ErrorTrace(0, "Cannot enable SE_BACKUP_NAME privilege...");
|
|
goto Exit;
|
|
}
|
|
if ( !::CheckPrivilege( SE_RESTORE_NAME, FALSE ) )
|
|
{
|
|
ErrorTrace(0, "Cannot enable SE_RESTORE_NAME privilege...");
|
|
goto Exit;
|
|
}
|
|
if ( !::CheckPrivilege( SE_SHUTDOWN_NAME, FALSE ) )
|
|
{
|
|
ErrorTrace(0, "Cannot enable SE_SHUTDOWN_NAME privilege...");
|
|
goto Exit;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
TraceFunctLeave();
|
|
ReleaseTrace();
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InvokeDiskCleanup
|
|
//
|
|
// This routine invokes Disk Cleanup Utility. A specific drive can be
|
|
// provided.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LPCWSTR s_cszDCUPath = L"%windir%\\system32\\cleanmgr.exe";
|
|
static LPCWSTR s_cszDCUName = L"cleanmgr.exe";
|
|
static LPCWSTR s_cszDCUOptDrv = L" /d ";
|
|
|
|
BOOL APIENTRY
|
|
InvokeDiskCleanup( LPCWSTR cszDrive )
|
|
{
|
|
TraceFunctEnter("InvokeDiskCleanup");
|
|
|
|
// Load SRClient
|
|
g_CSRClientLoader.LoadSrClient();
|
|
|
|
BOOL fRet = FALSE;
|
|
LPCWSTR cszErr;
|
|
WCHAR szCmdLine[MAX_PATH];
|
|
STARTUPINFO sSI;
|
|
PROCESS_INFORMATION sPI;
|
|
|
|
if ( ::ExpandEnvironmentStrings( s_cszDCUPath, szCmdLine, MAX_PATH ) == 0 )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::GetFullPathName failed - %ls", cszErr);
|
|
::lstrcpy( szCmdLine, s_cszDCUName );
|
|
}
|
|
|
|
if ( cszDrive != NULL && cszDrive[0] != L'\0' )
|
|
{
|
|
::lstrcat( szCmdLine, s_cszDCUOptDrv );
|
|
::lstrcat( szCmdLine, cszDrive );
|
|
}
|
|
|
|
DebugTrace(0, "szCmdLine='%s'", szCmdLine);
|
|
::ZeroMemory( &sSI, sizeof(sSI ) );
|
|
sSI.cb = sizeof(sSI);
|
|
if ( !::CreateProcess( NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &sSI, &sPI ) )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::CreateProcess failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
::CloseHandle( sPI.hThread );
|
|
::CloseHandle( sPI.hProcess );
|
|
|
|
// Should I wait for DCU to finish???
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
TraceFunctLeave();
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
#ifdef DBG
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TestRestore
|
|
//
|
|
// This routine performs core restoration functionality, without reboot or
|
|
// snapshot restoration.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
extern "C" __declspec(dllexport)
|
|
BOOL APIENTRY
|
|
TestRestore( int nRP )
|
|
{
|
|
EnsureTrace();
|
|
TraceFunctEnter("TestRestore");
|
|
BOOL fRet = FALSE;
|
|
CRDIArray aryDrv;
|
|
RESTOREPOINTINFO sRPI;
|
|
STATEMGRSTATUS sStatus;
|
|
SRstrLogHdrV3 sLogHdr;
|
|
CRestoreOperationManager *pROMgr = NULL;
|
|
|
|
// Load SRClient
|
|
g_CSRClientLoader.LoadSrClient();
|
|
|
|
if ( !::CheckPrivilegesForRestore() )
|
|
goto Exit;
|
|
|
|
// Create Drive Table
|
|
if ( !::CreateDriveList( nRP, aryDrv, FALSE ) )
|
|
goto Exit;
|
|
|
|
// Create Restore Point
|
|
sRPI.dwEventType = BEGIN_SYSTEM_CHANGE;
|
|
sRPI.dwRestorePtType = RESTORE;
|
|
sRPI.llSequenceNumber = 0;
|
|
::LoadString( g_hInst, IDS_RESTORE_POINT_TEXT, sRPI.szDescription, MAX_DESC );
|
|
if ( !::SRSetRestorePoint( &sRPI, &sStatus ) )
|
|
{
|
|
ErrorTrace(0, "::SRSetRestorePoint failed, nStatus=%d", sStatus.nStatus);
|
|
goto Exit;
|
|
}
|
|
|
|
// Create the log file
|
|
sLogHdr.dwRPNum = nRP;
|
|
sLogHdr.dwRPNew = sStatus.llSequenceNumber;
|
|
sLogHdr.dwDrives = aryDrv.GetSize();
|
|
if ( !::CreateRestoreLogFile( &sLogHdr, aryDrv ) )
|
|
goto Exit;
|
|
|
|
|
|
// also call TS folks to get them to preserve RA keys on restore
|
|
_VERIFY(TRUE==RemoteAssistancePrepareSystemRestore(SERVERNAME_CURRENT));
|
|
|
|
// Create CRestoreOperationManager object
|
|
if ( !::CreateRestoreOperationManager( &pROMgr ) )
|
|
goto Exit;
|
|
|
|
// Perform the Restore Operation.
|
|
if ( !pROMgr->Run( FALSE ) )
|
|
goto Exit;
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
SAFE_RELEASE(pROMgr);
|
|
TraceFunctLeave();
|
|
ReleaseTrace();
|
|
return( fRet );
|
|
}
|
|
#endif
|
|
|
|
#ifdef DBG
|
|
#define TIMEOUT_PROGRESSTHREAD 5000
|
|
|
|
#define TESTPROG_COUNT_CHGLOG 300
|
|
#define TESTPROG_TIME_PREPARE 1
|
|
#define TESTPROG_COUNT_RESTORE 100
|
|
#define TESTPROG_TIME_RESTORE 1
|
|
#define TESTPROG_TIME_SNAPSHOT 2000
|
|
|
|
DWORD WINAPI
|
|
TestProgressWindowThreadProc( LPVOID lpParam )
|
|
{
|
|
CRestoreProgressWindow *pProgress = (CRestoreProgressWindow*)lpParam;
|
|
int i, j;
|
|
|
|
// Stage 1. Prepare (change log enumeration)
|
|
pProgress->SetStage( RPS_PREPARE, 0 );
|
|
for ( i = 0; i < TESTPROG_COUNT_CHGLOG; i++ )
|
|
{
|
|
::Sleep( TESTPROG_TIME_PREPARE );
|
|
for ( j = 0; j < 10; j++ )
|
|
pProgress->Increment();
|
|
}
|
|
|
|
// Stage 2. Restore
|
|
pProgress->SetStage( RPS_RESTORE, TESTPROG_COUNT_RESTORE );
|
|
for ( i = 0; i < TESTPROG_COUNT_RESTORE; i++ )
|
|
{
|
|
::Sleep( TESTPROG_TIME_RESTORE );
|
|
pProgress->Increment();
|
|
}
|
|
|
|
// Stage 3. Snapshot
|
|
pProgress->SetStage( RPS_SNAPSHOT, 0 );
|
|
::Sleep( TESTPROG_TIME_SNAPSHOT );
|
|
|
|
pProgress->Close();
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TestProgressWindow
|
|
//
|
|
// This routine invokes Progress Window and simulates progress change
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
extern "C" __declspec(dllexport)
|
|
BOOL APIENTRY
|
|
TestProgressWindow()
|
|
{
|
|
EnsureTrace();
|
|
TraceFunctEnter("TestProgressWindow");
|
|
BOOL fRet = FALSE;
|
|
CRestoreProgressWindow *pProgress = NULL;
|
|
HANDLE hThread = NULL;
|
|
DWORD dwRet;
|
|
|
|
// Load SRClient
|
|
g_CSRClientLoader.LoadSrClient();
|
|
|
|
// Create progress window object
|
|
if ( !::CreateRestoreProgressWindow( &pProgress ) )
|
|
goto Exit;
|
|
|
|
// Create progress window
|
|
if ( !pProgress->Create() )
|
|
goto Exit;
|
|
|
|
// Create secondary thread for main restore operation
|
|
hThread = ::CreateThread( NULL, 0, TestProgressWindowThreadProc, pProgress, 0, NULL );
|
|
if ( hThread == NULL )
|
|
{
|
|
LPCWSTR cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::CreateThread failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
|
|
// Message loop, wait until restore thread closes progress window
|
|
if ( !pProgress->Run() )
|
|
goto Exit;
|
|
|
|
// Double check if thread has been terminated
|
|
dwRet = ::WaitForSingleObject( hThread, TIMEOUT_PROGRESSTHREAD );
|
|
if ( dwRet == WAIT_FAILED )
|
|
{
|
|
LPCWSTR cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::WaitForSingleObject failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
else if ( dwRet == WAIT_TIMEOUT )
|
|
{
|
|
ErrorTrace(0, "Timeout while waiting for the restore thread finishes...");
|
|
goto Exit;
|
|
}
|
|
|
|
pProgress->Close();
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
if ( hThread != NULL )
|
|
::CloseHandle( hThread );
|
|
SAFE_RELEASE(pProgress);
|
|
TraceFunctLeave();
|
|
ReleaseTrace();
|
|
return( fRet );
|
|
}
|
|
#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PrepareRestore
|
|
//
|
|
// This routine creates a IRestoreContext for use by InitiateRestore.
|
|
// IRestoreContext contains chosen restore point ID, drive list, etc.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL APIENTRY
|
|
PrepareRestore( int nRP, IRestoreContext **ppCtx )
|
|
{
|
|
EnsureTrace();
|
|
TraceFunctEnter("PrepareRestore");
|
|
BOOL fRet = FALSE;
|
|
CRestoreContext *pRC = NULL;
|
|
|
|
// Load SRClient
|
|
g_CSRClientLoader.LoadSrClient();
|
|
|
|
if ( ppCtx == NULL )
|
|
{
|
|
ErrorTrace(0, "Invalid parameter, ppCtx is NULL.");
|
|
goto Exit;
|
|
}
|
|
*ppCtx = NULL;
|
|
|
|
if ( !::IsAdminUser() )
|
|
{
|
|
ErrorTrace(0, "Not an admin user");
|
|
goto Exit;
|
|
}
|
|
|
|
pRC = new CRestoreContext;
|
|
if ( pRC == NULL )
|
|
{
|
|
ErrorTrace(0, "Insufficient memory...");
|
|
goto Exit;
|
|
}
|
|
|
|
pRC->m_nRP = nRP;
|
|
if ( !::CreateDriveList( nRP, pRC->m_aryDrv, FALSE ) )
|
|
{
|
|
ErrorTrace(0, "Creating drive list failed");
|
|
goto Exit;
|
|
}
|
|
|
|
*ppCtx = pRC;
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
if ( !fRet )
|
|
SAFE_RELEASE(pRC);
|
|
TraceFunctLeave();
|
|
ReleaseTrace();
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InitiateRestore
|
|
//
|
|
// This routine creates a temporary persistent storage with informations
|
|
// like restore point ID. The storage will be used by ResumeRestore later.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LPCWSTR s_cszRunOnceValueName = L"*Restore";
|
|
static LPCWSTR s_cszRestoreUIPath = L"%SystemRoot%\\system32\\restore\\rstrui.exe";
|
|
static LPCWSTR s_cszRunOnceOptInterrupted = L" -i";
|
|
|
|
BOOL APIENTRY
|
|
InitiateRestore( IRestoreContext *pCtx, DWORD *pdwNewRP )
|
|
{
|
|
EnsureTrace();
|
|
TraceFunctEnter("InitiateRestore");
|
|
|
|
// Load SRClient
|
|
g_CSRClientLoader.LoadSrClient();
|
|
|
|
BOOL fRet = FALSE;
|
|
HCURSOR hCursor = NULL;
|
|
RESTOREPOINTINFO sRPI;
|
|
STATEMGRSTATUS sStatus;
|
|
SRstrLogHdrV3 sLogHdr;
|
|
CRestoreContext *pRC;
|
|
DWORD dwVal;
|
|
WCHAR szUIPath[MAX_PATH];
|
|
BOOL fCreatedRp = FALSE;
|
|
|
|
if ( !::IsAdminUser() )
|
|
goto Exit;
|
|
|
|
// Set RunOnce key for interrupted case...
|
|
// Doing this here before anything else so result screen would appear.
|
|
::ExpandEnvironmentStrings( s_cszRestoreUIPath, szUIPath, MAX_PATH );
|
|
::lstrcat( szUIPath, s_cszRunOnceOptInterrupted );
|
|
if ( !::SRSetRegStr( HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, s_cszRunOnceValueName, szUIPath ) )
|
|
goto Exit;
|
|
|
|
// similarly, set RestoreStatus key in SystemRestore
|
|
// so that test tools can know status of silent restores
|
|
// set this to indicate interrrupted status
|
|
// if restore succeeds or reverts, this value will be updated
|
|
if ( !::SRSetRegDword( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszRestoreStatus, 2 ) )
|
|
goto Exit;
|
|
|
|
|
|
// Create Restore Point
|
|
hCursor = ::SetCursor( ::LoadCursor( NULL, IDC_WAIT ) );
|
|
|
|
// make this a nested restore point so that
|
|
// no other app can create a restore point between here and a reboot
|
|
sRPI.dwEventType = BEGIN_NESTED_SYSTEM_CHANGE;
|
|
|
|
if (0 != GetSystemMetrics(SM_CLEANBOOT)) // safe mode
|
|
{
|
|
sRPI.dwRestorePtType = CANCELLED_OPERATION;
|
|
}
|
|
else // normal mode
|
|
{
|
|
sRPI.dwRestorePtType = RESTORE;
|
|
}
|
|
|
|
sRPI.llSequenceNumber = 0;
|
|
::LoadString( g_hInst, IDS_RESTORE_POINT_TEXT, sRPI.szDescription, MAX_DESC );
|
|
if ( !::SRSetRestorePoint( &sRPI, &sStatus ) )
|
|
{
|
|
ErrorTrace(0, "::SRSetRestorePoint failed, nStatus=%d", sStatus.nStatus);
|
|
goto Exit;
|
|
}
|
|
if ( pdwNewRP != NULL )
|
|
*pdwNewRP = sStatus.llSequenceNumber;
|
|
|
|
fCreatedRp = TRUE;
|
|
|
|
// Create the log file
|
|
pRC = (CRestoreContext*)pCtx;
|
|
sLogHdr.dwFlags = pRC->m_fSilent ? RLHF_SILENT : 0;
|
|
sLogHdr.dwFlags |= pRC->m_fUndo ? RLHF_UNDO : 0;
|
|
sLogHdr.dwRPNum = pRC->m_nRP;
|
|
sLogHdr.dwRPNew = sStatus.llSequenceNumber;
|
|
sLogHdr.dwDrives = pRC->m_aryDrv.GetSize();
|
|
if ( !::CreateRestoreLogFile( &sLogHdr, pRC->m_aryDrv ) )
|
|
goto Exit;
|
|
|
|
// also call TS folks to get them to preserve RA keys on restore
|
|
_VERIFY(TRUE==RemoteAssistancePrepareSystemRestore(SERVERNAME_CURRENT));
|
|
|
|
// Set RestoreInProgress registry key so winlogon would invoke us
|
|
if ( !::SRSetRegDword( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszRestoreInProgress, 1 ) )
|
|
goto Exit;
|
|
|
|
fRet = TRUE;
|
|
|
|
Exit:
|
|
if (fRet == FALSE)
|
|
{
|
|
// if something failed and we had set a nested restore point,
|
|
// end the nesting now
|
|
|
|
if (fCreatedRp == TRUE)
|
|
{
|
|
sRPI.dwRestorePtType = RESTORE;
|
|
sRPI.dwEventType = END_NESTED_SYSTEM_CHANGE;
|
|
SRSetRestorePoint( &sRPI, &sStatus );
|
|
}
|
|
|
|
// delete the runonce key
|
|
SHDeleteValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, s_cszRunOnceValueName);
|
|
}
|
|
|
|
if ( hCursor != NULL )
|
|
::SetCursor( hCursor );
|
|
TraceFunctLeave();
|
|
ReleaseTrace();
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ResumeRestore
|
|
//
|
|
// This routine is the main routine to run the restore operation.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL APIENTRY
|
|
ResumeRestore()
|
|
{
|
|
EnsureTrace();
|
|
TraceFunctEnter("ResumeRestore");
|
|
|
|
// Load SRClient
|
|
g_CSRClientLoader.LoadSrClient();
|
|
|
|
BOOL fRet = FALSE;
|
|
LPCWSTR cszErr;
|
|
DWORD dwInRestore, dwType, dwSize, dwRes;
|
|
CRestoreOperationManager *pROMgr = NULL;
|
|
|
|
if ( !::CheckPrivilegesForRestore() )
|
|
goto Exit;
|
|
|
|
// 1. Even though winlogon would check the registry before calling this
|
|
// API, double check the registry key and then delete it.
|
|
dwType = REG_DWORD;
|
|
dwSize = sizeof(DWORD);
|
|
dwRes = ::SHGetValue( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszRestoreInProgress, &dwType, &dwInRestore, &dwSize );
|
|
if ( dwRes != ERROR_SUCCESS )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
DebugTrace(0, "::SHGetValue failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
dwRes = ::SHDeleteValue( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszRestoreInProgress );
|
|
if ( dwRes != ERROR_SUCCESS )
|
|
{
|
|
cszErr = ::GetSysErrStr();
|
|
ErrorTrace(0, "::SHDeleteValue failed - %ls", cszErr);
|
|
goto Exit;
|
|
}
|
|
if ( dwInRestore == 0 )
|
|
{
|
|
DebugTrace(0, "RestoreInProgress is 0");
|
|
goto Exit;
|
|
}
|
|
|
|
// 1. Create CRestoreOperationManager object.
|
|
if ( !::CreateRestoreOperationManager( &pROMgr ) )
|
|
goto Exit;
|
|
|
|
// 2. Perform the Restore Operation.
|
|
if ( !pROMgr->Run( TRUE ) )
|
|
goto Exit;
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
SAFE_RELEASE(pROMgr);
|
|
TraceFunctLeave();
|
|
ReleaseTrace();
|
|
return( fRet );
|
|
}
|
|
|
|
|
|
// end of file
|