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.

531 lines
11 KiB

  1. // Copyright (C) 1997-2000 Microsoft Corporation
  2. //
  3. // install replica from media page
  4. //
  5. // 7 Feb 2000 sburns
  6. #include "headers.hxx"
  7. #include "resource.h"
  8. #include "common.hpp"
  9. #include "page.hpp"
  10. #include "ReplicateFromMediaPage.hpp"
  11. #include "state.hpp"
  12. #include "SyskeyDiskDialog.hpp"
  13. #include "SyskeyPromptDialog.hpp"
  14. ReplicateFromMediaPage::ReplicateFromMediaPage()
  15. :
  16. DCPromoWizardPage(
  17. IDD_REPLICATE_FROM_MEDIA,
  18. IDS_REPLICATE_FROM_MEDIA_PAGE_TITLE,
  19. IDS_REPLICATE_FROM_MEDIA_PAGE_SUBTITLE)
  20. {
  21. LOG_CTOR(ReplicateFromMediaPage);
  22. }
  23. ReplicateFromMediaPage::~ReplicateFromMediaPage()
  24. {
  25. LOG_DTOR(ReplicateFromMediaPage);
  26. }
  27. String
  28. FirstFixedDisk()
  29. {
  30. LOG_FUNCTION(FirstFixedDisk);
  31. String result;
  32. do
  33. {
  34. StringVector dl;
  35. HRESULT hr = FS::GetValidDrives(std::back_inserter(dl));
  36. BREAK_ON_FAILED_HRESULT(hr);
  37. ASSERT(dl.size());
  38. for (
  39. StringVector::iterator i = dl.begin();
  40. i != dl.end();
  41. ++i)
  42. {
  43. String rootPath = *i + L"\\";
  44. if (Win::GetDriveType(rootPath) == DRIVE_FIXED)
  45. {
  46. result = *i;
  47. break;
  48. }
  49. }
  50. }
  51. while (0);
  52. if (result.empty())
  53. {
  54. // This is deadcode, really, cause we're sure to find a fixed volume
  55. // somewhere
  56. result = FS::GetRootFolder(Win::GetSystemDirectory()).substr(0, 3);
  57. }
  58. LOG(result);
  59. return result;
  60. }
  61. void
  62. ReplicateFromMediaPage::OnInit()
  63. {
  64. LOG_FUNCTION(ReplicateFromMediaPage::OnInit);
  65. Win::Edit_LimitText(Win::GetDlgItem(hwnd, IDC_SOURCE), MAX_PATH);
  66. State& state = State::GetInstance();
  67. if (state.UsingAnswerFile())
  68. {
  69. String option =
  70. state.GetAnswerFileOption(AnswerFile::OPTION_SOURCE_PATH);
  71. if (!option.empty())
  72. {
  73. Win::CheckDlgButton(hwnd, IDC_USE_FILES, BST_CHECKED);
  74. Win::SetDlgItemText(
  75. hwnd,
  76. IDC_SOURCE,
  77. Win::ExpandEnvironmentStrings(option));
  78. return;
  79. }
  80. }
  81. Win::CheckDlgButton(hwnd, IDC_USE_NET, BST_CHECKED);
  82. String root = FirstFixedDisk();
  83. Win::SetDlgItemText(
  84. hwnd,
  85. IDC_SOURCE,
  86. root + String::load(IDS_SOURCE_SUFFIX));
  87. }
  88. void
  89. ReplicateFromMediaPage::Enable()
  90. {
  91. int next = PSWIZB_NEXT;
  92. bool useFiles = Win::IsDlgButtonChecked(hwnd, IDC_USE_FILES);
  93. if (useFiles)
  94. {
  95. // if using files, the edit box must have some text.
  96. if (Win::GetTrimmedDlgItemText(hwnd, IDC_SOURCE).empty())
  97. {
  98. next = 0;
  99. }
  100. }
  101. Win::PropSheet_SetWizButtons(
  102. Win::GetParent(hwnd),
  103. PSWIZB_BACK | next);
  104. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_SOURCE), useFiles);
  105. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_BROWSE), useFiles);
  106. }
  107. bool
  108. ReplicateFromMediaPage::OnCommand(
  109. HWND /* windowFrom */ ,
  110. unsigned controlIDFrom,
  111. unsigned code)
  112. {
  113. // LOG_FUNCTION(ReplicateFromMediaPage::OnCommand);
  114. switch (controlIDFrom)
  115. {
  116. case IDC_USE_NET:
  117. case IDC_USE_FILES:
  118. {
  119. if (code == BN_CLICKED)
  120. {
  121. SetChanged(controlIDFrom);
  122. Enable();
  123. return true;
  124. }
  125. }
  126. case IDC_BROWSE:
  127. {
  128. if (code == BN_CLICKED)
  129. {
  130. String path = BrowseForFolder(hwnd, IDS_SOURCE_BROWSE_TITLE);
  131. if (!path.empty())
  132. {
  133. Win::SetDlgItemText(hwnd, IDC_SOURCE, path);
  134. }
  135. return true;
  136. }
  137. break;
  138. }
  139. case IDC_SOURCE:
  140. {
  141. if (code == EN_CHANGE)
  142. {
  143. SetChanged(controlIDFrom);
  144. Enable();
  145. return true;
  146. }
  147. break;
  148. }
  149. default:
  150. {
  151. // do nothing
  152. break;
  153. }
  154. }
  155. return false;
  156. }
  157. bool
  158. ReplicateFromMediaPage::OnSetActive()
  159. {
  160. LOG_FUNCTION(ReplicateFromMediaPage::OnSetActive);
  161. ASSERT(State::GetInstance().GetOperation() == State::REPLICA);
  162. Win::PropSheet_SetWizButtons(
  163. Win::GetParent(hwnd),
  164. PSWIZB_BACK);
  165. State& state = State::GetInstance();
  166. if (state.RunHiddenUnattended() || !state.IsAdvancedMode())
  167. {
  168. LOG(L"skipping ReplicateFromMediaPage");
  169. Wizard& wiz = GetWizard();
  170. if (wiz.IsBacktracking())
  171. {
  172. // backup once again
  173. wiz.Backtrack(hwnd);
  174. return true;
  175. }
  176. int nextPage = ReplicateFromMediaPage::Validate();
  177. if (nextPage != -1)
  178. {
  179. wiz.SetNextPageID(hwnd, nextPage);
  180. }
  181. else
  182. {
  183. state.ClearHiddenWhileUnattended();
  184. }
  185. }
  186. Enable();
  187. return true;
  188. }
  189. bool
  190. ValidateSourcePath(HWND parent, const String& path, int editResId)
  191. {
  192. LOG_FUNCTION2(ValidateSourcePath, path);
  193. bool result = false;
  194. do
  195. {
  196. if (path.empty())
  197. {
  198. popup.Gripe(
  199. parent,
  200. editResId,
  201. IDS_MUST_ENTER_SOURCE_PATH);
  202. break;
  203. }
  204. // Path must have a drive letter
  205. FS::PathSyntax syn = FS::GetPathSyntax(path);
  206. if (syn != FS::SYNTAX_ABSOLUTE_DRIVE)
  207. {
  208. popup.Gripe(
  209. parent,
  210. editResId,
  211. String::format(IDS_BAD_PATH_FORMAT, path.c_str()));
  212. break;
  213. }
  214. // mapped network drives are not ok. This is because the DsRole apis
  215. // copy the restored files on the server side of the api, in the
  216. // system context.
  217. // NTRAID#NTBUG9-309422-2001/02/12-sburns
  218. UINT type = Win::GetDriveType(path);
  219. switch (type)
  220. {
  221. // allow CDs and removeable media, too
  222. // NTRAID#NTBUG9-648713-2002/06/25-sburns
  223. case DRIVE_FIXED:
  224. case DRIVE_CDROM:
  225. case DRIVE_RAMDISK:
  226. case DRIVE_REMOVABLE:
  227. {
  228. result = true;
  229. break;
  230. }
  231. case DRIVE_UNKNOWN:
  232. case DRIVE_NO_ROOT_DIR:
  233. case DRIVE_REMOTE:
  234. default:
  235. {
  236. popup.Gripe(
  237. parent,
  238. editResId,
  239. String::format(IDS_BAD_DRIVE_TYPE, path.c_str()));
  240. break;
  241. }
  242. }
  243. }
  244. while (0);
  245. LOG(result ? L"true" : L"false")
  246. return result;
  247. }
  248. // Return true on success, false on failure
  249. bool
  250. GetDatabaseFacts(HWND parent, const String& sourcePath)
  251. {
  252. LOG_FUNCTION2(GetDatabaseFacts, sourcePath);
  253. DSROLE_IFM_OPERATION_HANDLE IfmHandle;
  254. ASSERT(Win::IsWindow(parent));
  255. ASSERT(!sourcePath.empty());
  256. bool result = false;
  257. PWSTR dnsDomainName = 0;
  258. State& state = State::GetInstance();
  259. state.SetIsBackupGc(false);
  260. state.SetSyskeyLocation(State::STORED);
  261. // If there was an IfmHandle already, free it.
  262. state.FreeIfmHandle();
  263. LOG(L"Calling DsRoleGetDatabaseFacts");
  264. LOG(String::format(L"lpRestorePath: %1", sourcePath.c_str()));
  265. ULONG facts = 0;
  266. HRESULT hr =
  267. Win32ToHresult(
  268. ::DsRoleGetDatabaseFacts(
  269. 0, // this server
  270. sourcePath.c_str(),
  271. &dnsDomainName,
  272. &facts,
  273. &IfmHandle));
  274. LOG_HRESULT(hr);
  275. if (SUCCEEDED(hr) && IfmHandle)
  276. {
  277. LOG(String::format(L"lpDNSDomainName: %1", dnsDomainName ? dnsDomainName : L"(null)"));
  278. LOG(String::format(L"State : 0x%1!X!", facts));
  279. if (IfmHandle) {
  280. state.SetIfmHandle(IfmHandle);
  281. }
  282. if (dnsDomainName)
  283. {
  284. // Save this domain name. This will allow us to skip the ReplicaPage
  285. // since we now know the domain name.
  286. state.SetReplicaDomainDNSName(dnsDomainName);
  287. MIDL_user_free(dnsDomainName);
  288. }
  289. if (facts & DSROLE_DC_IS_GC)
  290. {
  291. LOG(L"is gc");
  292. state.SetIsBackupGc(true);
  293. }
  294. if (facts & DSROLE_KEY_DISK)
  295. {
  296. LOG(L"syskey on disk");
  297. state.SetSyskeyLocation(State::DISK);
  298. }
  299. else if (facts & DSROLE_KEY_PROMPT)
  300. {
  301. LOG(L"prompt for syskey");
  302. state.SetSyskeyLocation(State::PROMPT);
  303. }
  304. else if (facts & DSROLE_KEY_STORED)
  305. {
  306. LOG(L"syskey stored");
  307. // we set this as the default value, above.
  308. }
  309. else
  310. {
  311. // The api is insane.
  312. ASSERT(false);
  313. LOG(L"unexpected State value");
  314. }
  315. result = true;
  316. }
  317. else
  318. {
  319. if (SUCCEEDED(hr)) {
  320. ASSERT(IfmHandle == NULL);
  321. ASSERT(!"DsRoleGetDatabaseFacts() should never return success w/o an out param");
  322. hr = Win32ToHresult(ERROR_INVALID_PARAMETER);
  323. LOG_HRESULT(hr);
  324. }
  325. popup.Error(
  326. parent,
  327. hr,
  328. String::format(IDS_GET_FACTS_FAILED, sourcePath.c_str()));
  329. }
  330. LOG(result ? L"true" : L"false");
  331. return result;
  332. }
  333. int
  334. ReplicateFromMediaPage::Validate()
  335. {
  336. LOG_FUNCTION(ReplicateFromMediaPage::Validate);
  337. State& state = State::GetInstance();
  338. int nextPage = -1;
  339. bool useFiles = Win::IsDlgButtonChecked(hwnd, IDC_USE_FILES);
  340. do
  341. {
  342. // Don't check WasChanged for the radio buttons because when running
  343. // unattended, CheckDlgButton does not send a parent BN_CLICKED
  344. // notification, so WasChanged will not be set properly.
  345. // NTRAID#NTBUG9-602141-2002/04/15-sburns
  346. state.SetReplicateFromMedia(useFiles);
  347. if (!useFiles)
  348. {
  349. LOG(L"not using source media for replication");
  350. nextPage = IDD_CONFIG_DNS_CLIENT;
  351. break;
  352. }
  353. String sourcePath = Win::GetTrimmedDlgItemText(hwnd, IDC_SOURCE);
  354. if (ValidateSourcePath(hwnd, sourcePath, IDC_SOURCE) )
  355. {
  356. String s =
  357. FS::NormalizePath(Win::GetTrimmedDlgItemText(hwnd, IDC_SOURCE));
  358. state.SetReplicationSourcePath(s);
  359. }
  360. else
  361. {
  362. break;
  363. }
  364. // check the restored backup for the syskey, the domain name, and the DC
  365. // type.
  366. if (!GetDatabaseFacts(hwnd, sourcePath))
  367. {
  368. break;
  369. }
  370. State::SyskeyLocation loc = state.GetSyskeyLocation();
  371. if (loc == State::DISK)
  372. {
  373. // Check if the disk is already inserted
  374. // NTRAID#NTBUG9-522250-2002/01/23-sburns
  375. if (FAILED(SyskeyDiskDialog::LocateSyskey(0)))
  376. {
  377. if (SyskeyDiskDialog().ModalExecute(hwnd) != IDOK)
  378. {
  379. break;
  380. }
  381. }
  382. }
  383. else if (loc == State::PROMPT)
  384. {
  385. if (SyskeyPromptDialog().ModalExecute(hwnd) != IDOK)
  386. {
  387. break;
  388. }
  389. }
  390. // The syskey is present, do we need to jump to the GC confirmation?
  391. if (state.IsBackupGc())
  392. {
  393. nextPage = IDD_GC_CONFIRM;
  394. break;
  395. }
  396. // The syskey is present, the backup is not a gc, so move along
  397. nextPage = IDD_CONFIG_DNS_CLIENT;
  398. }
  399. while (0);
  400. if (nextPage != -1)
  401. {
  402. // only clear changes when the user has specified valid options.
  403. // otherwise, we want to go thru the validation until he gets it
  404. // right.
  405. ClearChanges();
  406. }
  407. LOG(String::format(L"next = %1!d!", nextPage));
  408. return nextPage;
  409. }