// Copyright (C) 1997-2000 Microsoft Corporation // // install replica from media page // // 7 Feb 2000 sburns #include "headers.hxx" #include "resource.h" #include "common.hpp" #include "page.hpp" #include "ReplicateFromMediaPage.hpp" #include "state.hpp" #include "SyskeyDiskDialog.hpp" #include "SyskeyPromptDialog.hpp" ReplicateFromMediaPage::ReplicateFromMediaPage() : DCPromoWizardPage( IDD_REPLICATE_FROM_MEDIA, IDS_REPLICATE_FROM_MEDIA_PAGE_TITLE, IDS_REPLICATE_FROM_MEDIA_PAGE_SUBTITLE) { LOG_CTOR(ReplicateFromMediaPage); } ReplicateFromMediaPage::~ReplicateFromMediaPage() { LOG_DTOR(ReplicateFromMediaPage); } String FirstFixedDisk() { LOG_FUNCTION(FirstFixedDisk); String result; do { StringVector dl; HRESULT hr = FS::GetValidDrives(std::back_inserter(dl)); BREAK_ON_FAILED_HRESULT(hr); ASSERT(dl.size()); for ( StringVector::iterator i = dl.begin(); i != dl.end(); ++i) { String rootPath = *i + L"\\"; if (Win::GetDriveType(rootPath) == DRIVE_FIXED) { result = *i; break; } } } while (0); if (result.empty()) { // This is deadcode, really, cause we're sure to find a fixed volume // somewhere result = FS::GetRootFolder(Win::GetSystemDirectory()).substr(0, 3); } LOG(result); return result; } void ReplicateFromMediaPage::OnInit() { LOG_FUNCTION(ReplicateFromMediaPage::OnInit); Win::Edit_LimitText(Win::GetDlgItem(hwnd, IDC_SOURCE), MAX_PATH); State& state = State::GetInstance(); if (state.UsingAnswerFile()) { String option = state.GetAnswerFileOption(AnswerFile::OPTION_SOURCE_PATH); if (!option.empty()) { Win::CheckDlgButton(hwnd, IDC_USE_FILES, BST_CHECKED); Win::SetDlgItemText( hwnd, IDC_SOURCE, Win::ExpandEnvironmentStrings(option)); return; } } Win::CheckDlgButton(hwnd, IDC_USE_NET, BST_CHECKED); String root = FirstFixedDisk(); Win::SetDlgItemText( hwnd, IDC_SOURCE, root + String::load(IDS_SOURCE_SUFFIX)); } void ReplicateFromMediaPage::Enable() { int next = PSWIZB_NEXT; bool useFiles = Win::IsDlgButtonChecked(hwnd, IDC_USE_FILES); if (useFiles) { // if using files, the edit box must have some text. if (Win::GetTrimmedDlgItemText(hwnd, IDC_SOURCE).empty()) { next = 0; } } Win::PropSheet_SetWizButtons( Win::GetParent(hwnd), PSWIZB_BACK | next); Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_SOURCE), useFiles); Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_BROWSE), useFiles); } bool ReplicateFromMediaPage::OnCommand( HWND /* windowFrom */ , unsigned controlIDFrom, unsigned code) { // LOG_FUNCTION(ReplicateFromMediaPage::OnCommand); switch (controlIDFrom) { case IDC_USE_NET: case IDC_USE_FILES: { if (code == BN_CLICKED) { SetChanged(controlIDFrom); Enable(); return true; } } case IDC_BROWSE: { if (code == BN_CLICKED) { String path = BrowseForFolder(hwnd, IDS_SOURCE_BROWSE_TITLE); if (!path.empty()) { Win::SetDlgItemText(hwnd, IDC_SOURCE, path); } return true; } break; } case IDC_SOURCE: { if (code == EN_CHANGE) { SetChanged(controlIDFrom); Enable(); return true; } break; } default: { // do nothing break; } } return false; } bool ReplicateFromMediaPage::OnSetActive() { LOG_FUNCTION(ReplicateFromMediaPage::OnSetActive); ASSERT(State::GetInstance().GetOperation() == State::REPLICA); Win::PropSheet_SetWizButtons( Win::GetParent(hwnd), PSWIZB_BACK); State& state = State::GetInstance(); if (state.RunHiddenUnattended() || !state.IsAdvancedMode()) { LOG(L"skipping ReplicateFromMediaPage"); Wizard& wiz = GetWizard(); if (wiz.IsBacktracking()) { // backup once again wiz.Backtrack(hwnd); return true; } int nextPage = ReplicateFromMediaPage::Validate(); if (nextPage != -1) { wiz.SetNextPageID(hwnd, nextPage); } else { state.ClearHiddenWhileUnattended(); } } Enable(); return true; } bool ValidateSourcePath(HWND parent, const String& path, int editResId) { LOG_FUNCTION2(ValidateSourcePath, path); bool result = false; do { if (path.empty()) { popup.Gripe( parent, editResId, IDS_MUST_ENTER_SOURCE_PATH); break; } // Path must have a drive letter FS::PathSyntax syn = FS::GetPathSyntax(path); if (syn != FS::SYNTAX_ABSOLUTE_DRIVE) { popup.Gripe( parent, editResId, String::format(IDS_BAD_PATH_FORMAT, path.c_str())); break; } // mapped network drives are not ok. This is because the DsRole apis // copy the restored files on the server side of the api, in the // system context. // NTRAID#NTBUG9-309422-2001/02/12-sburns UINT type = Win::GetDriveType(path); switch (type) { // allow CDs and removeable media, too // NTRAID#NTBUG9-648713-2002/06/25-sburns case DRIVE_FIXED: case DRIVE_CDROM: case DRIVE_RAMDISK: case DRIVE_REMOVABLE: { result = true; break; } case DRIVE_UNKNOWN: case DRIVE_NO_ROOT_DIR: case DRIVE_REMOTE: default: { popup.Gripe( parent, editResId, String::format(IDS_BAD_DRIVE_TYPE, path.c_str())); break; } } } while (0); LOG(result ? L"true" : L"false") return result; } // Return true on success, false on failure bool GetDatabaseFacts(HWND parent, const String& sourcePath) { LOG_FUNCTION2(GetDatabaseFacts, sourcePath); DSROLE_IFM_OPERATION_HANDLE IfmHandle; ASSERT(Win::IsWindow(parent)); ASSERT(!sourcePath.empty()); bool result = false; PWSTR dnsDomainName = 0; State& state = State::GetInstance(); state.SetIsBackupGc(false); state.SetSyskeyLocation(State::STORED); // If there was an IfmHandle already, free it. state.FreeIfmHandle(); LOG(L"Calling DsRoleGetDatabaseFacts"); LOG(String::format(L"lpRestorePath: %1", sourcePath.c_str())); ULONG facts = 0; HRESULT hr = Win32ToHresult( ::DsRoleGetDatabaseFacts( 0, // this server sourcePath.c_str(), &dnsDomainName, &facts, &IfmHandle)); LOG_HRESULT(hr); if (SUCCEEDED(hr) && IfmHandle) { LOG(String::format(L"lpDNSDomainName: %1", dnsDomainName ? dnsDomainName : L"(null)")); LOG(String::format(L"State : 0x%1!X!", facts)); if (IfmHandle) { state.SetIfmHandle(IfmHandle); } if (dnsDomainName) { // Save this domain name. This will allow us to skip the ReplicaPage // since we now know the domain name. state.SetReplicaDomainDNSName(dnsDomainName); MIDL_user_free(dnsDomainName); } if (facts & DSROLE_DC_IS_GC) { LOG(L"is gc"); state.SetIsBackupGc(true); } if (facts & DSROLE_KEY_DISK) { LOG(L"syskey on disk"); state.SetSyskeyLocation(State::DISK); } else if (facts & DSROLE_KEY_PROMPT) { LOG(L"prompt for syskey"); state.SetSyskeyLocation(State::PROMPT); } else if (facts & DSROLE_KEY_STORED) { LOG(L"syskey stored"); // we set this as the default value, above. } else { // The api is insane. ASSERT(false); LOG(L"unexpected State value"); } result = true; } else { if (SUCCEEDED(hr)) { ASSERT(IfmHandle == NULL); ASSERT(!"DsRoleGetDatabaseFacts() should never return success w/o an out param"); hr = Win32ToHresult(ERROR_INVALID_PARAMETER); LOG_HRESULT(hr); } popup.Error( parent, hr, String::format(IDS_GET_FACTS_FAILED, sourcePath.c_str())); } LOG(result ? L"true" : L"false"); return result; } int ReplicateFromMediaPage::Validate() { LOG_FUNCTION(ReplicateFromMediaPage::Validate); State& state = State::GetInstance(); int nextPage = -1; bool useFiles = Win::IsDlgButtonChecked(hwnd, IDC_USE_FILES); do { // Don't check WasChanged for the radio buttons because when running // unattended, CheckDlgButton does not send a parent BN_CLICKED // notification, so WasChanged will not be set properly. // NTRAID#NTBUG9-602141-2002/04/15-sburns state.SetReplicateFromMedia(useFiles); if (!useFiles) { LOG(L"not using source media for replication"); nextPage = IDD_CONFIG_DNS_CLIENT; break; } String sourcePath = Win::GetTrimmedDlgItemText(hwnd, IDC_SOURCE); if (ValidateSourcePath(hwnd, sourcePath, IDC_SOURCE) ) { String s = FS::NormalizePath(Win::GetTrimmedDlgItemText(hwnd, IDC_SOURCE)); state.SetReplicationSourcePath(s); } else { break; } // check the restored backup for the syskey, the domain name, and the DC // type. if (!GetDatabaseFacts(hwnd, sourcePath)) { break; } State::SyskeyLocation loc = state.GetSyskeyLocation(); if (loc == State::DISK) { // Check if the disk is already inserted // NTRAID#NTBUG9-522250-2002/01/23-sburns if (FAILED(SyskeyDiskDialog::LocateSyskey(0))) { if (SyskeyDiskDialog().ModalExecute(hwnd) != IDOK) { break; } } } else if (loc == State::PROMPT) { if (SyskeyPromptDialog().ModalExecute(hwnd) != IDOK) { break; } } // The syskey is present, do we need to jump to the GC confirmation? if (state.IsBackupGc()) { nextPage = IDD_GC_CONFIRM; break; } // The syskey is present, the backup is not a gc, so move along nextPage = IDD_CONFIG_DNS_CLIENT; } while (0); if (nextPage != -1) { // only clear changes when the user has specified valid options. // otherwise, we want to go thru the validation until he gets it // right. ClearChanges(); } LOG(String::format(L"next = %1!d!", nextPage)); return nextPage; }