Source code of Windows XP (NT5)
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.

1323 lines
28 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. imirror.c
  5. Abstract:
  6. This is the file for the IntelliMirror conversion DLL basic To Do item processing.
  7. Author:
  8. Sean Selitrennikoff - 4/5/98
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Global variables
  15. //
  16. LIST_ENTRY GlobalToDoList;
  17. IMIRROR_CALLBACK Callbacks;
  18. BYTE TmpBuffer[TMP_BUFFER_SIZE];
  19. BYTE TmpBuffer2[TMP_BUFFER_SIZE];
  20. BYTE TmpBuffer3[TMP_BUFFER_SIZE];
  21. HANDLE ghInst;
  22. BOOL fInitedFromRegistry;
  23. BOOL fCallbackPreviouslySet = FALSE;
  24. #ifdef DEBUGLOG
  25. HANDLE hDebugLogFile = INVALID_HANDLE_VALUE;
  26. CRITICAL_SECTION DebugFileLock;
  27. #endif
  28. //
  29. // Definitions for this file
  30. //
  31. typedef struct _TODOITEM {
  32. IMIRROR_TODO Item;
  33. PVOID Buffer;
  34. ULONG Length;
  35. } TODOITEM, *PTODOITEM;
  36. typedef struct _TODOLIST {
  37. LIST_ENTRY ListEntry;
  38. ULONG ToDoNum;
  39. TODOITEM ToDoList[1];
  40. } TODOLIST, *PTODOLIST;
  41. //
  42. // Main entry routine
  43. //
  44. DWORD
  45. IMirrorInitDll(
  46. HINSTANCE hInst,
  47. DWORD Reason,
  48. PVOID Context
  49. )
  50. /*++
  51. Routine Description:
  52. This routine initializes all the components for this DLL
  53. Arguments:
  54. hInst - Instance that is calling us.
  55. Reason - Why we are being invoked.
  56. Context - Context passed for this init.
  57. Return Value:
  58. TRUE if successful, else FALSE
  59. --*/
  60. {
  61. if (Reason == DLL_PROCESS_ATTACH) {
  62. #ifdef DEBUGLOG
  63. InitializeCriticalSection( &DebugFileLock );
  64. hDebugLogFile = CreateFile(L"C:\\imlog",
  65. GENERIC_READ | GENERIC_WRITE,
  66. FILE_SHARE_READ | FILE_SHARE_WRITE,
  67. NULL,
  68. CREATE_ALWAYS,
  69. 0,
  70. NULL);
  71. if (hDebugLogFile != INVALID_HANDLE_VALUE){
  72. UCHAR FileTmpBuf[MAX_PATH ];
  73. SYSTEMTIME Time;
  74. // log the start time
  75. GetLocalTime(&Time);
  76. sprintf(FileTmpBuf,"Starting on %d-%d-%d at %d:%d:%d\n",
  77. Time.wMonth,
  78. Time.wDay,
  79. Time.wYear,
  80. Time.wHour,
  81. Time.wMinute,
  82. Time.wSecond);
  83. IMLogToFile(FileTmpBuf);
  84. }
  85. #endif
  86. ghInst = hInst;
  87. #ifdef DEBUGLOG
  88. } else if (Reason == DLL_PROCESS_DETACH) {
  89. if (hDebugLogFile != INVALID_HANDLE_VALUE){
  90. SYSTEMTIME Time;
  91. UCHAR FileTmpBuf[MAX_PATH ];
  92. GetLocalTime(&Time);
  93. sprintf(FileTmpBuf,"Ending on %d-%d-%d at %d:%d:%d\n",
  94. Time.wMonth, Time.wDay, Time.wYear,
  95. Time.wHour, Time.wMinute, Time.wSecond);
  96. IMLogToFile(FileTmpBuf);
  97. IMFlushAndCloseLog();
  98. hDebugLogFile = INVALID_HANDLE_VALUE;
  99. DeleteCriticalSection( &DebugFileLock );
  100. }
  101. #endif
  102. }
  103. return(TRUE);
  104. }
  105. VOID
  106. IMirrorInitCallback(
  107. PIMIRROR_CALLBACK pCallbacks
  108. )
  109. /*++
  110. Routine Description:
  111. This routine initializes the call back structure with the one supplied by the client.
  112. Arguments:
  113. pCallbacks - Client supplied information for making callbacks to the client.
  114. Return Value:
  115. None.
  116. --*/
  117. {
  118. if (pCallbacks != NULL) {
  119. Callbacks = *pCallbacks;
  120. if (fInitedFromRegistry) {
  121. IMirrorReinit();
  122. }
  123. }
  124. }
  125. //
  126. //
  127. //
  128. // Main processing loop
  129. //
  130. //
  131. //
  132. NTSTATUS
  133. ProcessToDoItems(
  134. VOID
  135. )
  136. /*++
  137. Routine Description:
  138. This routine is the main processing loop for To Do Items.
  139. Arguments:
  140. None
  141. Return Value:
  142. STATUS_SUCCESS if it completed all to do items properly.
  143. --*/
  144. {
  145. IMIRROR_TODO Item;
  146. PVOID pBuffer;
  147. ULONG Length;
  148. NTSTATUS Status;
  149. Status = InitToDo();
  150. if ( Status != STATUS_SUCCESS )
  151. return Status;
  152. while (1) {
  153. Status = GetNextToDoItem(&Item, &pBuffer, &Length);
  154. if (!NT_SUCCESS(Status)) {
  155. IMirrorHandleError(Status, IMirrorNone);
  156. return Status;
  157. }
  158. switch (Item) {
  159. case IMirrorNone:
  160. return STATUS_SUCCESS;
  161. case VerifySystemIsNt5:
  162. Status = CheckIfNt5(pBuffer, Length);
  163. break;
  164. case CheckPartitions:
  165. Status = CheckForPartitions(pBuffer, Length);
  166. break;
  167. case CopyPartitions:
  168. Status = CopyCopyPartitions(pBuffer, Length);
  169. break;
  170. case CopyFiles:
  171. Status = CopyCopyFiles(pBuffer, Length);
  172. break;
  173. case CopyRegistry:
  174. Status = CopyCopyRegistry(pBuffer, Length);
  175. break;
  176. #if 0
  177. case PatchDSEntries:
  178. Status = ModifyDSEntries(pBuffer, Length);
  179. break;
  180. #endif
  181. case RebootSystem:
  182. Status = Callbacks.RebootFn(Callbacks.Context);
  183. break;
  184. }
  185. IMirrorFreeMem(pBuffer);
  186. }
  187. }
  188. //
  189. //
  190. //
  191. // TO DO Item functions
  192. //
  193. //
  194. //
  195. NTSTATUS
  196. InitToDo(
  197. VOID
  198. )
  199. /*++
  200. Routine Description:
  201. This routine reads from the registry all the current ToDo items and puts
  202. them in a single TODOLIST.
  203. Arguments:
  204. None
  205. Return Value:
  206. STATUS_SUCCESS if it was initialized properly, else the appropriate error code.
  207. --*/
  208. {
  209. #if 0
  210. PTODOLIST pToDoList;
  211. PTODOLIST pNewToDoList;
  212. PTODOITEM pToDoItem;
  213. PLIST_ENTRY pListEntry;
  214. UNICODE_STRING UnicodeString;
  215. OBJECT_ATTRIBUTES ObjectAttributes;
  216. PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
  217. HANDLE Handle;
  218. ULONG ByteCount;
  219. ULONG BytesLeft;
  220. ULONG i;
  221. PBYTE pBuffer;
  222. #endif
  223. NTSTATUS Status;
  224. //
  225. // Initialize global variables
  226. //
  227. InitializeListHead(&GlobalToDoList);
  228. #if 0
  229. //
  230. //
  231. // Read the current ToDo list from the registry
  232. //
  233. //
  234. RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\RemoteBoot");
  235. InitializeObjectAttributes(&ObjectAttributes,
  236. &UnicodeString,
  237. OBJ_CASE_INSENSITIVE,
  238. NULL,
  239. NULL
  240. );
  241. Status = NtOpenKey(&Handle,
  242. KEY_ALL_ACCESS,
  243. &ObjectAttributes
  244. );
  245. if (!NT_SUCCESS(Status)) {
  246. goto NoRegistry;
  247. }
  248. RtlInitUnicodeString(&UnicodeString, L"ConversionState");
  249. //
  250. // Get the size of the buffer needed
  251. //
  252. ByteCount = 0;
  253. Status = NtQueryValueKey(Handle,
  254. &UnicodeString,
  255. KeyValuePartialInformation,
  256. NULL,
  257. 0,
  258. &ByteCount
  259. );
  260. if (Status != STATUS_BUFFER_TOO_SMALL) {
  261. NtClose(Handle);
  262. goto NoRegistry;
  263. }
  264. pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)IMirrorAllocMem(ByteCount);
  265. if (pKeyInfo == NULL) {
  266. NtClose(Handle);
  267. return STATUS_NO_MEMORY;
  268. }
  269. //
  270. // Get the buffer from the registry
  271. //
  272. Status = NtQueryValueKey(Handle,
  273. &UnicodeString,
  274. KeyValuePartialInformation,
  275. pKeyInfo,
  276. ByteCount,
  277. &ByteCount
  278. );
  279. if (!NT_SUCCESS(Status)) {
  280. IMirrorFreeMem(pKeyInfo);
  281. NtClose(Handle);
  282. return Status;
  283. }
  284. pBuffer = &(pKeyInfo->Data[0]);
  285. BytesLeft = pKeyInfo->DataLength;
  286. ByteCount = BytesLeft;
  287. //
  288. // Now translate the buffer into our internal structures.
  289. //
  290. while (BytesLeft != 0) {
  291. pToDoList = (PTODOLIST)(pBuffer + ByteCount - BytesLeft);
  292. ASSERT(pToDoList->ToDoNum != 0);
  293. pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST) +
  294. sizeof(TODOITEM) * (pToDoList->ToDoNum - 1)
  295. );
  296. if (pNewToDoList == NULL) {
  297. ClearAllToDoItems(TRUE);
  298. NtClose(Handle);
  299. return STATUS_NO_MEMORY;
  300. }
  301. BytesLeft -= (sizeof(TODOLIST) + sizeof(TODOITEM) * (pToDoList->ToDoNum - 1));
  302. pToDoItem = &(pToDoList->ToDoList[0]);
  303. //
  304. // Translate over one entire TODOLIST
  305. //
  306. while (pNewToDoList->ToDoNum < pToDoList->ToDoNum) {
  307. i = pNewToDoList->ToDoNum;
  308. pNewToDoList->ToDoList[i] = *pToDoItem;
  309. pNewToDoList->ToDoList[i].Buffer = IMirrorAllocMem(pToDoItem->Length);
  310. BytesLeft -= pToDoItem->Length;
  311. if (pNewToDoList->ToDoList[i].Buffer == NULL) {
  312. ClearAllToDoItems(TRUE);
  313. while (i > 0) {
  314. i--;
  315. IMirrorFreeMem(pNewToDoList->ToDoList[i].Buffer);
  316. }
  317. IMirrorFreeMem(pNewToDoList);
  318. NtClose(Handle);
  319. return STATUS_NO_MEMORY;
  320. }
  321. RtlMoveMemory(pNewToDoList->ToDoList[i].Buffer,
  322. pToDoItem + 1,
  323. pToDoItem->Length
  324. );
  325. pNewToDoList->ToDoNum++;
  326. pToDoItem = (PTODOITEM)(((PBYTE)pToDoItem) + pToDoItem->Length);
  327. pToDoItem++;
  328. }
  329. //
  330. // Add this list to the global To Do list
  331. //
  332. InsertTailList(&GlobalToDoList, &(pNewToDoList->ListEntry));
  333. }
  334. //
  335. // Remove everything from the registry so we don't accidentally restart again and again and...
  336. //
  337. RtlInitUnicodeString(&UnicodeString, L"ConversionState");
  338. Status = NtDeleteValueKey(Handle, &UnicodeString);
  339. NtClose(Handle);
  340. if (!IsListEmpty(&GlobalToDoList)) {
  341. fInitedFromRegistry = TRUE;
  342. return STATUS_SUCCESS;
  343. }
  344. NoRegistry:
  345. #endif
  346. fInitedFromRegistry = FALSE;
  347. //
  348. // If there is nothing in the registry, presume this is a fresh start.
  349. //
  350. Status = AddCheckMachineToDoItems();
  351. if (!NT_SUCCESS(Status)) {
  352. ClearAllToDoItems(TRUE);
  353. return Status;
  354. }
  355. Status = AddCopyToDoItems();
  356. if (!NT_SUCCESS(Status)) {
  357. ClearAllToDoItems(TRUE);
  358. return Status;
  359. }
  360. if ( Callbacks.RebootFn ) {
  361. AddToDoItem( RebootSystem, NULL, 0 );
  362. }
  363. return STATUS_SUCCESS;
  364. }
  365. NTSTATUS
  366. GetNextToDoItem(
  367. OUT PIMIRROR_TODO Item,
  368. OUT PVOID *Buffer,
  369. OUT PULONG Length
  370. )
  371. /*++
  372. Routine Description:
  373. This routine gets the next thing TODO from the global list.
  374. NOTE: The client is responsible for freeing Buffer.
  375. Arguments:
  376. Item - Place to store the next item to process.
  377. Buffer - Any context for the item.
  378. Length - Number of bytes in Buffer.
  379. Return Value:
  380. STATUS_SUCCESS if it was able to get an item, else an appropriate error code.
  381. --*/
  382. {
  383. PTODOLIST pToDoList;
  384. PTODOLIST pNewToDoList;
  385. PLIST_ENTRY pListEntry;
  386. *Item = IMirrorNone;
  387. *Buffer = NULL;
  388. *Length = 0;
  389. pToDoList = NULL;
  390. while (!IsListEmpty(&GlobalToDoList)) {
  391. //
  392. // Get the first list
  393. //
  394. pListEntry = RemoveHeadList(&GlobalToDoList);
  395. pToDoList = CONTAINING_RECORD(pListEntry,
  396. TODOLIST,
  397. ListEntry
  398. );
  399. if (pToDoList->ToDoNum != 0) {
  400. break;
  401. }
  402. IMirrorFreeMem(pToDoList);
  403. pToDoList = NULL;
  404. }
  405. if (IsListEmpty(&GlobalToDoList) && (pToDoList == NULL)) {
  406. return STATUS_SUCCESS;
  407. }
  408. ASSERT(pToDoList->ToDoNum != 0);
  409. //
  410. // Found the first item.
  411. //
  412. *Item = pToDoList->ToDoList[0].Item;
  413. *Buffer = pToDoList->ToDoList[0].Buffer;
  414. *Length = pToDoList->ToDoList[0].Length;
  415. if (Callbacks.RemoveToDoFn != NULL) {
  416. Callbacks.RemoveToDoFn( Callbacks.Context, *Item, *Buffer, *Length );
  417. }
  418. pToDoList->ToDoNum--;
  419. //
  420. // Now create a new ToDo list for anything that may get added by the processing of this item.
  421. // This creates an effective 'stack' of to do items, so that things get processed in the
  422. // correct order.
  423. //
  424. pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST));
  425. if (pNewToDoList == NULL) {
  426. return STATUS_NO_MEMORY;
  427. }
  428. //
  429. // Do an effective "pop" on the current list, by moving everything else up the list
  430. //
  431. if (pToDoList->ToDoNum == 0) {
  432. IMirrorFreeMem(pToDoList);
  433. } else {
  434. RtlMoveMemory(&(pToDoList->ToDoList[0]), &(pToDoList->ToDoList[1]), sizeof(TODOITEM) * pToDoList->ToDoNum);
  435. InsertHeadList(&GlobalToDoList, pListEntry);
  436. }
  437. //
  438. // Now push on the new space for new items.
  439. //
  440. pNewToDoList->ToDoNum = 0;
  441. InsertHeadList(&GlobalToDoList, &(pNewToDoList->ListEntry));
  442. return STATUS_SUCCESS;
  443. }
  444. NTSTATUS
  445. AddToDoItem(
  446. IN IMIRROR_TODO Item,
  447. IN PVOID Buffer,
  448. IN ULONG Length
  449. )
  450. /*++
  451. Routine Description:
  452. This routine adds a TODO item to the end of the current list. It allocates
  453. new memory and copies the buffer.
  454. Arguments:
  455. Item - The item id.
  456. Buffer - Buffer for any arguments, context for the item.
  457. Length - Length of the buffer in bytes.
  458. Return Value:
  459. STATUS_SUCCESS if it was able to add the item, else an appropriate error status.
  460. --*/
  461. {
  462. PTODOLIST pNewToDoList;
  463. PLIST_ENTRY pListEntry;
  464. PBYTE pBuf;
  465. LIST_ENTRY TmpToDoList;
  466. PTODOLIST pToDoList;
  467. ULONG i;
  468. ULONG err;
  469. if (Callbacks.AddToDoFn != NULL) {
  470. err = Callbacks.AddToDoFn( Callbacks.Context, Item, Buffer, Length );
  471. if (err != STATUS_SUCCESS) {
  472. //
  473. // if the UI bounces the request, we'll treat it as success.
  474. //
  475. return STATUS_SUCCESS;
  476. }
  477. }
  478. //
  479. // Allocate space for the buffer
  480. //
  481. if (Length != 0) {
  482. pBuf = IMirrorAllocMem(Length);
  483. if (pBuf == NULL) {
  484. return STATUS_NO_MEMORY;
  485. }
  486. } else {
  487. pBuf = NULL;
  488. }
  489. //
  490. // Get the current TODO List
  491. //
  492. if (IsListEmpty(&GlobalToDoList)) {
  493. pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST));
  494. if (pNewToDoList == NULL) {
  495. IMirrorFreeMem(pBuf);
  496. return STATUS_NO_MEMORY;
  497. }
  498. pNewToDoList->ToDoNum = 1;
  499. } else {
  500. pListEntry = RemoveHeadList(&GlobalToDoList);
  501. pToDoList = CONTAINING_RECORD(pListEntry,
  502. TODOLIST,
  503. ListEntry
  504. );
  505. //
  506. // Allocate space for the new item
  507. //
  508. pNewToDoList = IMirrorReallocMem(pToDoList, sizeof(TODOLIST) + sizeof(TODOITEM) * pToDoList->ToDoNum);
  509. if (pNewToDoList == NULL) {
  510. InsertHeadList(&GlobalToDoList, pListEntry);
  511. IMirrorFreeMem(pBuf);
  512. return STATUS_NO_MEMORY;
  513. }
  514. pNewToDoList->ToDoNum++;
  515. }
  516. //
  517. // Insert the item at the end of the list
  518. //
  519. if (pBuf != NULL) {
  520. RtlMoveMemory(pBuf, Buffer, Length);
  521. }
  522. pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Item = Item;
  523. pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Buffer = pBuf;
  524. pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Length = Length;
  525. pListEntry = &(pNewToDoList->ListEntry);
  526. InsertHeadList(&GlobalToDoList, pListEntry);
  527. return STATUS_SUCCESS;
  528. }
  529. VOID
  530. ClearAllToDoItems(
  531. IN BOOLEAN MemoryOnly
  532. )
  533. /*++
  534. Routine Description:
  535. This routine clears out all To Do items in memory and the registry
  536. Arguments:
  537. MemoryOnly - TRUE if to only clear the stuff in memory.
  538. Return Value:
  539. None.
  540. --*/
  541. {
  542. PTODOLIST pToDoList;
  543. PLIST_ENTRY pListEntry;
  544. UNICODE_STRING UnicodeString;
  545. OBJECT_ATTRIBUTES ObjectAttributes;
  546. HANDLE Handle;
  547. NTSTATUS Status;
  548. //
  549. // Clear out all the items in memory
  550. //
  551. while (!IsListEmpty(&GlobalToDoList)) {
  552. //
  553. // Get the first list
  554. //
  555. pListEntry = RemoveHeadList(&GlobalToDoList);
  556. pToDoList = CONTAINING_RECORD(pListEntry,
  557. TODOLIST,
  558. ListEntry
  559. );
  560. while (pToDoList->ToDoNum != 0) {
  561. pToDoList->ToDoNum--;
  562. if (Callbacks.RemoveToDoFn != NULL) {
  563. Callbacks.RemoveToDoFn( Callbacks.Context,
  564. pToDoList->ToDoList[pToDoList->ToDoNum].Item,
  565. pToDoList->ToDoList[pToDoList->ToDoNum].Buffer,
  566. pToDoList->ToDoList[pToDoList->ToDoNum].Length );
  567. }
  568. if (pToDoList->ToDoList[pToDoList->ToDoNum].Length != 0) {
  569. IMirrorFreeMem(pToDoList->ToDoList[pToDoList->ToDoNum].Buffer);
  570. }
  571. }
  572. IMirrorFreeMem(pToDoList);
  573. }
  574. if (MemoryOnly) {
  575. return;
  576. }
  577. //
  578. // Now clear out the ones in the registry
  579. //
  580. RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\RemoteBoot");
  581. InitializeObjectAttributes(&ObjectAttributes,
  582. &UnicodeString,
  583. OBJ_CASE_INSENSITIVE,
  584. NULL,
  585. NULL
  586. );
  587. Status = NtOpenKey(&Handle,
  588. KEY_ALL_ACCESS,
  589. &ObjectAttributes
  590. );
  591. if (!NT_SUCCESS(Status)) {
  592. return;
  593. }
  594. RtlInitUnicodeString(&UnicodeString, L"ConversionState");
  595. Status = NtDeleteValueKey(Handle, &UnicodeString);
  596. NtClose(Handle);
  597. }
  598. NTSTATUS
  599. SaveAllToDoItems(
  600. VOID
  601. )
  602. /*++
  603. Routine Description:
  604. This routine writes out all To Do items in the list to the registry so that conversion
  605. can be restarted later.
  606. Arguments:
  607. None.
  608. Return Value:
  609. STATUS_SUCCESS if it was able to save, else an appropriate error status.
  610. --*/
  611. {
  612. return STATUS_SUCCESS;
  613. #if 0
  614. PTODOLIST pToDoList;
  615. PTODOITEM pToDoItem;
  616. PLIST_ENTRY pListEntry;
  617. LIST_ENTRY TmpGlobalList;
  618. UNICODE_STRING UnicodeString;
  619. OBJECT_ATTRIBUTES ObjectAttributes;
  620. HANDLE Handle;
  621. ULONG ByteCount;
  622. ULONG i;
  623. PBYTE pBuffer;
  624. PBYTE pTmp;
  625. NTSTATUS Status;
  626. //
  627. // First find the size of buffer that will be needed.
  628. //
  629. ByteCount = 0;
  630. InitializeListHead(&TmpGlobalList);
  631. while (!IsListEmpty(&GlobalToDoList)) {
  632. //
  633. // Get the first list
  634. //
  635. pListEntry = RemoveHeadList(&GlobalToDoList);
  636. pToDoList = CONTAINING_RECORD(pListEntry,
  637. TODOLIST,
  638. ListEntry
  639. );
  640. //
  641. // Get the size of all the items
  642. //
  643. i = 0;
  644. while (i < pToDoList->ToDoNum) {
  645. if (i == 0) {
  646. ByteCount += sizeof(TODOLIST);
  647. } else {
  648. ByteCount += sizeof(TODOITEM);
  649. }
  650. ByteCount += pToDoList->ToDoList[i].Length;
  651. i++;
  652. }
  653. //
  654. // Save the entry away for later
  655. //
  656. InsertTailList(&TmpGlobalList, pListEntry);
  657. }
  658. if (ByteCount == 0) {
  659. return STATUS_SUCCESS;
  660. }
  661. //
  662. // Restore global list
  663. //
  664. while (!IsListEmpty(&TmpGlobalList)) {
  665. pListEntry = RemoveHeadList(&TmpGlobalList);
  666. InsertTailList(&GlobalToDoList, pListEntry);
  667. }
  668. //
  669. // Allocate a buffer for everything.
  670. //
  671. pBuffer = IMirrorAllocMem(ByteCount);
  672. if (pBuffer == NULL) {
  673. return STATUS_NO_MEMORY;
  674. }
  675. //
  676. // Fill the buffer
  677. //
  678. pTmp = pBuffer;
  679. while (!IsListEmpty(&GlobalToDoList)) {
  680. //
  681. // Get the first list
  682. //
  683. pListEntry = RemoveHeadList(&GlobalToDoList);
  684. pToDoList = CONTAINING_RECORD(pListEntry,
  685. TODOLIST,
  686. ListEntry
  687. );
  688. //
  689. // Copy all the items
  690. //
  691. i = 0;
  692. while (i < pToDoList->ToDoNum) {
  693. if (i == 0) {
  694. RtlMoveMemory(pTmp, pToDoList, sizeof(TODOLIST));
  695. pToDoItem = &(((PTODOLIST)pTmp)->ToDoList[0]);
  696. pTmp += sizeof(TODOLIST);
  697. } else {
  698. RtlMoveMemory(pTmp, &(pToDoList->ToDoList[i]), sizeof(TODOITEM));
  699. pToDoItem = (PTODOITEM)pTmp;
  700. pTmp += sizeof(TODOITEM);
  701. }
  702. if (pToDoList->ToDoList[i].Length != 0) {
  703. RtlMoveMemory(pTmp, pToDoList->ToDoList[i].Buffer, pToDoList->ToDoList[i].Length);
  704. pTmp += pToDoList->ToDoList[i].Length;
  705. }
  706. pToDoItem->Buffer = NULL;
  707. i++;
  708. }
  709. //
  710. // Save the entry away for later
  711. //
  712. InsertTailList(&TmpGlobalList, pListEntry);
  713. }
  714. //
  715. // Restore global list
  716. //
  717. while (!IsListEmpty(&TmpGlobalList)) {
  718. pListEntry = RemoveHeadList(&TmpGlobalList);
  719. InsertTailList(&GlobalToDoList, pListEntry);
  720. }
  721. //
  722. // Now write the buffer to the registry
  723. //
  724. RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\RemoteBoot");
  725. InitializeObjectAttributes(&ObjectAttributes,
  726. &UnicodeString,
  727. OBJ_CASE_INSENSITIVE,
  728. NULL,
  729. NULL
  730. );
  731. Status = NtCreateKey(&Handle,
  732. KEY_ALL_ACCESS,
  733. &ObjectAttributes,
  734. 0,
  735. (PUNICODE_STRING)NULL,
  736. 0,
  737. &i // disposition
  738. );
  739. if (!NT_SUCCESS(Status)) {
  740. IMirrorFreeMem(pBuffer);
  741. return Status;
  742. }
  743. RtlInitUnicodeString(&UnicodeString, L"ConversionState");
  744. Status = NtSetValueKey(Handle,
  745. &UnicodeString,
  746. 0,
  747. REG_BINARY,
  748. pBuffer,
  749. ByteCount
  750. );
  751. NtClose(Handle);
  752. IMirrorFreeMem(pBuffer);
  753. return Status;
  754. #endif
  755. }
  756. NTSTATUS
  757. ModifyToDoItem(
  758. IN IMIRROR_TODO Item,
  759. IN PVOID Buffer,
  760. IN ULONG Length
  761. )
  762. /*++
  763. Routine Description:
  764. This routine changes the parameters to the first TODO item that matches Item.
  765. Arguments:
  766. Item - The item id.
  767. Buffer - Buffer for any arguments, context for the item.
  768. Length - Length of the buffer in bytes.
  769. Return Value:
  770. STATUS_SUCCESS if it was able to change the item, else an appropriate error status.
  771. --*/
  772. {
  773. PLIST_ENTRY pListEntry;
  774. LIST_ENTRY TmpGlobalList;
  775. PTODOLIST pToDoList;
  776. ULONG i;
  777. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  778. InitializeListHead(&TmpGlobalList);
  779. while (!IsListEmpty(&GlobalToDoList)) {
  780. //
  781. // Get the first list
  782. //
  783. pListEntry = RemoveHeadList(&GlobalToDoList);
  784. pToDoList = CONTAINING_RECORD(pListEntry,
  785. TODOLIST,
  786. ListEntry
  787. );
  788. //
  789. // Save the entry away for later
  790. //
  791. InsertTailList(&TmpGlobalList, pListEntry);
  792. //
  793. // Walk the list until we find an item that matches.
  794. //
  795. i = 0;
  796. while (i < pToDoList->ToDoNum) {
  797. if (pToDoList->ToDoList[i].Item == Item) {
  798. if (pToDoList->ToDoList[i].Length == Length) {
  799. RtlMoveMemory(pToDoList->ToDoList[i].Buffer, Buffer, Length);
  800. } else {
  801. PVOID pTmp;
  802. pTmp = IMirrorAllocMem(Length);
  803. if (pTmp == NULL) {
  804. return STATUS_NO_MEMORY;
  805. }
  806. if (pToDoList->ToDoList[i].Length != 0) {
  807. IMirrorFreeMem(pToDoList->ToDoList[i].Buffer);
  808. }
  809. pToDoList->ToDoList[i].Buffer = pTmp;
  810. pToDoList->ToDoList[i].Length = Length;
  811. RtlMoveMemory(pTmp, Buffer, Length);
  812. }
  813. Status = STATUS_SUCCESS;
  814. goto Done;
  815. }
  816. i++;
  817. }
  818. }
  819. Done:
  820. //
  821. // Restore global list
  822. //
  823. while (!IsListEmpty(&TmpGlobalList)) {
  824. pListEntry = RemoveTailList(&TmpGlobalList);
  825. InsertHeadList(&GlobalToDoList, pListEntry);
  826. }
  827. return Status;
  828. }
  829. NTSTATUS
  830. CopyToDoItemParameters(
  831. IN IMIRROR_TODO Item,
  832. OUT PVOID Buffer,
  833. IN OUT PULONG Length
  834. )
  835. /*++
  836. Routine Description:
  837. This routine finds the first instance of Item, and copies its current parameters into Buffer.
  838. Arguments:
  839. Item - The item id.
  840. Buffer - The arguments, context for the item.
  841. Length - Length of the buffer in bytes.
  842. Return Value:
  843. STATUS_SUCCESS if it was able to change the item, else an appropriate error status.
  844. --*/
  845. {
  846. PLIST_ENTRY pListEntry;
  847. LIST_ENTRY TmpGlobalList;
  848. PTODOLIST pToDoList;
  849. ULONG i;
  850. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  851. InitializeListHead(&TmpGlobalList);
  852. while (!IsListEmpty(&GlobalToDoList)) {
  853. //
  854. // Get the first list
  855. //
  856. pListEntry = RemoveHeadList(&GlobalToDoList);
  857. pToDoList = CONTAINING_RECORD(pListEntry,
  858. TODOLIST,
  859. ListEntry
  860. );
  861. //
  862. // Save the entry away for later
  863. //
  864. InsertTailList(&TmpGlobalList, pListEntry);
  865. //
  866. // Walk the list until we find an item that matches.
  867. //
  868. i = 0;
  869. while (i < pToDoList->ToDoNum) {
  870. if (pToDoList->ToDoList[i].Item == Item) {
  871. if (pToDoList->ToDoList[i].Length <= *Length) {
  872. if (pToDoList->ToDoList[i].Length != 0) {
  873. RtlMoveMemory(Buffer,
  874. pToDoList->ToDoList[i].Buffer,
  875. pToDoList->ToDoList[i].Length
  876. );
  877. }
  878. Status = STATUS_SUCCESS;
  879. } else {
  880. Status = STATUS_INSUFFICIENT_RESOURCES;
  881. }
  882. *Length = pToDoList->ToDoList[i].Length;
  883. goto Done;
  884. }
  885. i++;
  886. }
  887. }
  888. Done:
  889. //
  890. // Restore global list
  891. //
  892. while (!IsListEmpty(&TmpGlobalList)) {
  893. pListEntry = RemoveTailList(&TmpGlobalList);
  894. InsertHeadList(&GlobalToDoList, pListEntry);
  895. }
  896. return Status;
  897. }
  898. #if 0
  899. NTSTATUS
  900. IMirrorDoReboot(
  901. IN PVOID pBuffer,
  902. IN ULONG Length
  903. )
  904. /*++
  905. Routine Description:
  906. This routine saves all the current to do items in the registry, and asks the UI if the
  907. reboot should be executed now.
  908. Arguments:
  909. pBuffer - Pointer to any arguments passed in the to do item.
  910. Length - Length, in bytes of the arguments.
  911. Return Value:
  912. STATUS_SUCCESS if it completes adding all the to do items properly.
  913. --*/
  914. {
  915. NTSTATUS Status;
  916. BOOL fRebootNow;
  917. BOOLEAN WasEnabled;
  918. DWORD Error;
  919. //
  920. // Add items to reverify the machine when the reboot is complete.
  921. //
  922. #if 0
  923. Status = AddToDoItem(VerifyNetworkComponents, NULL, 0);
  924. if (!NT_SUCCESS(Status)) {
  925. IMirrorHandleError(Status, IMirrorInitialize);
  926. return Status;
  927. }
  928. #endif
  929. //
  930. // Now save everything away...
  931. //
  932. Status = SaveAllToDoItems();
  933. if (!NT_SUCCESS(Status)) {
  934. IMirrorHandleError(Status, IMirrorReboot);
  935. return Status;
  936. }
  937. ClearAllToDoItems(TRUE);
  938. IMirrorWarnReboot(&fRebootNow);
  939. if (!fRebootNow) {
  940. return STATUS_SUCCESS;
  941. }
  942. //
  943. // Reboot the machine to start CSC
  944. //
  945. Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
  946. (BOOLEAN)TRUE,
  947. TRUE,
  948. &WasEnabled
  949. );
  950. if (Status == STATUS_NO_TOKEN) {
  951. //
  952. // No thread token, use the process token
  953. //
  954. Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
  955. (BOOLEAN)TRUE,
  956. FALSE,
  957. &WasEnabled
  958. );
  959. }
  960. if (!InitiateSystemShutdown(NULL, NULL, 0, TRUE, TRUE)) {
  961. IMirrorHandleError(ERROR_SUCCESS_REBOOT_REQUIRED, IMirrorReboot);
  962. }
  963. return STATUS_SUCCESS;
  964. }
  965. #endif