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.

786 lines
16 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. BOOL fCallbackPreviouslySet = FALSE;
  22. //
  23. // Definitions for this file
  24. //
  25. typedef struct _TODOITEM {
  26. IMIRROR_TODO Item;
  27. PVOID Buffer;
  28. ULONG Length;
  29. } TODOITEM, *PTODOITEM;
  30. typedef struct _TODOLIST {
  31. LIST_ENTRY ListEntry;
  32. ULONG ToDoNum;
  33. TODOITEM ToDoList[1];
  34. } TODOLIST, *PTODOLIST;
  35. VOID
  36. IMirrorInitCallback(
  37. PIMIRROR_CALLBACK pCallbacks
  38. )
  39. /*++
  40. Routine Description:
  41. This routine initializes the call back structure with the one supplied by the client.
  42. Arguments:
  43. pCallbacks - Client supplied information for making callbacks to the client.
  44. Return Value:
  45. None.
  46. --*/
  47. {
  48. if (pCallbacks != NULL) {
  49. Callbacks = *pCallbacks;
  50. }
  51. }
  52. //
  53. //
  54. //
  55. // Main processing loop
  56. //
  57. //
  58. //
  59. NTSTATUS
  60. ProcessToDoItems(
  61. VOID
  62. )
  63. /*++
  64. Routine Description:
  65. This routine is the main processing loop for To Do Items.
  66. Arguments:
  67. None
  68. Return Value:
  69. STATUS_SUCCESS if it completed all to do items properly.
  70. --*/
  71. {
  72. IMIRROR_TODO Item;
  73. PVOID pBuffer;
  74. ULONG Length;
  75. NTSTATUS Status;
  76. Status = InitToDo();
  77. if ( Status != STATUS_SUCCESS )
  78. return Status;
  79. while (1) {
  80. Status = GetNextToDoItem(&Item, &pBuffer, &Length);
  81. if (!NT_SUCCESS(Status)) {
  82. IMirrorHandleError(Status, IMirrorNone);
  83. return Status;
  84. }
  85. switch (Item) {
  86. case IMirrorNone:
  87. return STATUS_SUCCESS;
  88. case VerifySystemIsNt5:
  89. Status = CheckIfNt5();
  90. break;
  91. case CheckPartitions:
  92. Status = CheckForPartitions();
  93. break;
  94. case CopyPartitions:
  95. Status = CopyCopyPartitions(pBuffer, Length);
  96. break;
  97. case CopyFiles:
  98. Status = CopyCopyFiles(pBuffer, Length);
  99. break;
  100. case CopyRegistry:
  101. Status = CopyCopyRegistry(pBuffer, Length);
  102. break;
  103. case RebootSystem:
  104. Status = Callbacks.RebootFn(Callbacks.Context);
  105. break;
  106. }
  107. IMirrorFreeMem(pBuffer);
  108. }
  109. }
  110. //
  111. //
  112. //
  113. // TO DO Item functions
  114. //
  115. //
  116. //
  117. NTSTATUS
  118. InitToDo(
  119. VOID
  120. )
  121. /*++
  122. Routine Description:
  123. This routine reads from the registry all the current ToDo items and puts
  124. them in a single TODOLIST.
  125. Arguments:
  126. None
  127. Return Value:
  128. STATUS_SUCCESS if it was initialized properly, else the appropriate error code.
  129. --*/
  130. {
  131. NTSTATUS Status;
  132. //
  133. // Initialize global variables
  134. //
  135. InitializeListHead(&GlobalToDoList);
  136. //
  137. // If there is nothing in the registry, presume this is a fresh start.
  138. //
  139. Status = AddCheckMachineToDoItems();
  140. if (!NT_SUCCESS(Status)) {
  141. ClearAllToDoItems(TRUE);
  142. return Status;
  143. }
  144. Status = AddCopyToDoItems();
  145. if (!NT_SUCCESS(Status)) {
  146. ClearAllToDoItems(TRUE);
  147. return Status;
  148. }
  149. if ( Callbacks.RebootFn ) {
  150. AddToDoItem( RebootSystem, NULL, 0 );
  151. }
  152. return STATUS_SUCCESS;
  153. }
  154. NTSTATUS
  155. GetNextToDoItem(
  156. OUT PIMIRROR_TODO Item,
  157. OUT PVOID *Buffer,
  158. OUT PULONG Length
  159. )
  160. /*++
  161. Routine Description:
  162. This routine gets the next thing TODO from the global list.
  163. NOTE: The client is responsible for freeing Buffer.
  164. Arguments:
  165. Item - Place to store the next item to process.
  166. Buffer - Any context for the item.
  167. Length - Number of bytes in Buffer.
  168. Return Value:
  169. STATUS_SUCCESS if it was able to get an item, else an appropriate error code.
  170. --*/
  171. {
  172. PTODOLIST pToDoList;
  173. PTODOLIST pNewToDoList;
  174. PLIST_ENTRY pListEntry = NULL;
  175. *Item = IMirrorNone;
  176. *Buffer = NULL;
  177. *Length = 0;
  178. pToDoList = NULL;
  179. while (!IsListEmpty(&GlobalToDoList)) {
  180. //
  181. // Get the first list
  182. //
  183. pListEntry = RemoveHeadList(&GlobalToDoList);
  184. pToDoList = CONTAINING_RECORD(pListEntry,
  185. TODOLIST,
  186. ListEntry
  187. );
  188. if (pToDoList->ToDoNum != 0) {
  189. break;
  190. }
  191. IMirrorFreeMem(pToDoList);
  192. pToDoList = NULL;
  193. }
  194. if (IsListEmpty(&GlobalToDoList) && (pToDoList == NULL)) {
  195. return STATUS_SUCCESS;
  196. }
  197. if (!pListEntry) {
  198. return ERROR_INVALID_DATA;
  199. }
  200. ASSERT(pToDoList->ToDoNum != 0);
  201. //
  202. // Found the first item.
  203. //
  204. *Item = pToDoList->ToDoList[0].Item;
  205. *Buffer = pToDoList->ToDoList[0].Buffer;
  206. *Length = pToDoList->ToDoList[0].Length;
  207. if (Callbacks.RemoveToDoFn != NULL) {
  208. Callbacks.RemoveToDoFn( Callbacks.Context, *Item, *Buffer, *Length );
  209. }
  210. pToDoList->ToDoNum--;
  211. //
  212. // Now create a new ToDo list for anything that may get added by the processing of this item.
  213. // This creates an effective 'stack' of to do items, so that things get processed in the
  214. // correct order.
  215. //
  216. pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST));
  217. if (pNewToDoList == NULL) {
  218. return STATUS_NO_MEMORY;
  219. }
  220. //
  221. // Do an effective "pop" on the current list, by moving everything else up the list
  222. //
  223. if (pToDoList->ToDoNum == 0) {
  224. IMirrorFreeMem(pToDoList);
  225. } else {
  226. RtlMoveMemory(&(pToDoList->ToDoList[0]), &(pToDoList->ToDoList[1]), sizeof(TODOITEM) * pToDoList->ToDoNum);
  227. InsertHeadList(&GlobalToDoList, pListEntry);
  228. }
  229. //
  230. // Now push on the new space for new items.
  231. //
  232. pNewToDoList->ToDoNum = 0;
  233. InsertHeadList(&GlobalToDoList, &(pNewToDoList->ListEntry));
  234. return STATUS_SUCCESS;
  235. }
  236. NTSTATUS
  237. AddToDoItem(
  238. IN IMIRROR_TODO Item,
  239. IN PVOID Buffer,
  240. IN ULONG Length
  241. )
  242. /*++
  243. Routine Description:
  244. This routine adds a TODO item to the end of the current list. It allocates
  245. new memory and copies the buffer.
  246. Arguments:
  247. Item - The item id.
  248. Buffer - Buffer for any arguments, context for the item.
  249. Length - Length of the buffer in bytes.
  250. Return Value:
  251. STATUS_SUCCESS if it was able to add the item, else an appropriate error status.
  252. --*/
  253. {
  254. PTODOLIST pNewToDoList;
  255. PLIST_ENTRY pListEntry;
  256. PBYTE pBuf;
  257. PTODOLIST pToDoList;
  258. ULONG err;
  259. if (Callbacks.AddToDoFn != NULL) {
  260. err = Callbacks.AddToDoFn( Callbacks.Context, Item, Buffer, Length );
  261. if (err != STATUS_SUCCESS) {
  262. //
  263. // if the UI bounces the request, we'll treat it as success.
  264. //
  265. return STATUS_SUCCESS;
  266. }
  267. }
  268. //
  269. // Allocate space for the buffer
  270. //
  271. if (Length != 0) {
  272. pBuf = IMirrorAllocMem(Length);
  273. if (pBuf == NULL) {
  274. return STATUS_NO_MEMORY;
  275. }
  276. } else {
  277. pBuf = NULL;
  278. }
  279. //
  280. // Get the current TODO List
  281. //
  282. if (IsListEmpty(&GlobalToDoList)) {
  283. pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST));
  284. if (pNewToDoList == NULL) {
  285. IMirrorFreeMem(pBuf);
  286. return STATUS_NO_MEMORY;
  287. }
  288. pNewToDoList->ToDoNum = 1;
  289. } else {
  290. pListEntry = RemoveHeadList(&GlobalToDoList);
  291. pToDoList = CONTAINING_RECORD(pListEntry,
  292. TODOLIST,
  293. ListEntry
  294. );
  295. //
  296. // Allocate space for the new item
  297. //
  298. pNewToDoList = IMirrorReallocMem(pToDoList, sizeof(TODOLIST) + sizeof(TODOITEM) * pToDoList->ToDoNum);
  299. if (pNewToDoList == NULL) {
  300. InsertHeadList(&GlobalToDoList, pListEntry);
  301. IMirrorFreeMem(pBuf);
  302. return STATUS_NO_MEMORY;
  303. }
  304. pNewToDoList->ToDoNum++;
  305. }
  306. //
  307. // Insert the item at the end of the list
  308. //
  309. if (pBuf != NULL) {
  310. RtlMoveMemory(pBuf, Buffer, Length);
  311. }
  312. pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Item = Item;
  313. pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Buffer = pBuf;
  314. pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Length = Length;
  315. pListEntry = &(pNewToDoList->ListEntry);
  316. InsertHeadList(&GlobalToDoList, pListEntry);
  317. return STATUS_SUCCESS;
  318. }
  319. VOID
  320. ClearAllToDoItems(
  321. IN BOOLEAN MemoryOnly
  322. )
  323. /*++
  324. Routine Description:
  325. This routine clears out all To Do items in memory and the registry
  326. Arguments:
  327. MemoryOnly - TRUE if to only clear the stuff in memory.
  328. Return Value:
  329. None.
  330. --*/
  331. {
  332. PTODOLIST pToDoList;
  333. PLIST_ENTRY pListEntry;
  334. UNICODE_STRING UnicodeString;
  335. OBJECT_ATTRIBUTES ObjectAttributes;
  336. HANDLE Handle;
  337. NTSTATUS Status;
  338. //
  339. // Clear out all the items in memory
  340. //
  341. while (!IsListEmpty(&GlobalToDoList)) {
  342. //
  343. // Get the first list
  344. //
  345. pListEntry = RemoveHeadList(&GlobalToDoList);
  346. pToDoList = CONTAINING_RECORD(pListEntry,
  347. TODOLIST,
  348. ListEntry
  349. );
  350. while (pToDoList->ToDoNum != 0) {
  351. pToDoList->ToDoNum--;
  352. if (Callbacks.RemoveToDoFn != NULL) {
  353. Callbacks.RemoveToDoFn( Callbacks.Context,
  354. pToDoList->ToDoList[pToDoList->ToDoNum].Item,
  355. pToDoList->ToDoList[pToDoList->ToDoNum].Buffer,
  356. pToDoList->ToDoList[pToDoList->ToDoNum].Length );
  357. }
  358. if (pToDoList->ToDoList[pToDoList->ToDoNum].Length != 0) {
  359. IMirrorFreeMem(pToDoList->ToDoList[pToDoList->ToDoNum].Buffer);
  360. }
  361. }
  362. IMirrorFreeMem(pToDoList);
  363. }
  364. if (MemoryOnly) {
  365. return;
  366. }
  367. //
  368. // Now clear out the ones in the registry
  369. //
  370. RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\RemoteBoot");
  371. InitializeObjectAttributes(&ObjectAttributes,
  372. &UnicodeString,
  373. OBJ_CASE_INSENSITIVE,
  374. NULL,
  375. NULL
  376. );
  377. Status = NtOpenKey(&Handle,
  378. KEY_ALL_ACCESS,
  379. &ObjectAttributes
  380. );
  381. if (!NT_SUCCESS(Status)) {
  382. return;
  383. }
  384. RtlInitUnicodeString(&UnicodeString, L"ConversionState");
  385. Status = NtDeleteValueKey(Handle, &UnicodeString);
  386. NtClose(Handle);
  387. }
  388. NTSTATUS
  389. SaveAllToDoItems(
  390. VOID
  391. )
  392. /*++
  393. Routine Description:
  394. This routine writes out all To Do items in the list to the registry so that conversion
  395. can be restarted later.
  396. Arguments:
  397. None.
  398. Return Value:
  399. STATUS_SUCCESS if it was able to save, else an appropriate error status.
  400. --*/
  401. {
  402. return STATUS_SUCCESS;
  403. }
  404. NTSTATUS
  405. ModifyToDoItem(
  406. IN IMIRROR_TODO Item,
  407. IN PVOID Buffer,
  408. IN ULONG Length
  409. )
  410. /*++
  411. Routine Description:
  412. This routine changes the parameters to the first TODO item that matches Item.
  413. Arguments:
  414. Item - The item id.
  415. Buffer - Buffer for any arguments, context for the item.
  416. Length - Length of the buffer in bytes.
  417. Return Value:
  418. STATUS_SUCCESS if it was able to change the item, else an appropriate error status.
  419. --*/
  420. {
  421. PLIST_ENTRY pListEntry;
  422. LIST_ENTRY TmpGlobalList;
  423. PTODOLIST pToDoList;
  424. ULONG i;
  425. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  426. InitializeListHead(&TmpGlobalList);
  427. while (!IsListEmpty(&GlobalToDoList)) {
  428. //
  429. // Get the first list
  430. //
  431. pListEntry = RemoveHeadList(&GlobalToDoList);
  432. pToDoList = CONTAINING_RECORD(pListEntry,
  433. TODOLIST,
  434. ListEntry
  435. );
  436. //
  437. // Save the entry away for later
  438. //
  439. InsertTailList(&TmpGlobalList, pListEntry);
  440. //
  441. // Walk the list until we find an item that matches.
  442. //
  443. i = 0;
  444. while (i < pToDoList->ToDoNum) {
  445. if (pToDoList->ToDoList[i].Item == Item) {
  446. if (pToDoList->ToDoList[i].Length == Length) {
  447. RtlMoveMemory(pToDoList->ToDoList[i].Buffer, Buffer, Length);
  448. } else {
  449. PVOID pTmp;
  450. pTmp = IMirrorAllocMem(Length);
  451. if (pTmp == NULL) {
  452. return STATUS_NO_MEMORY;
  453. }
  454. if (pToDoList->ToDoList[i].Length != 0) {
  455. IMirrorFreeMem(pToDoList->ToDoList[i].Buffer);
  456. }
  457. pToDoList->ToDoList[i].Buffer = pTmp;
  458. pToDoList->ToDoList[i].Length = Length;
  459. RtlMoveMemory(pTmp, Buffer, Length);
  460. }
  461. Status = STATUS_SUCCESS;
  462. goto Done;
  463. }
  464. i++;
  465. }
  466. }
  467. Done:
  468. //
  469. // Restore global list
  470. //
  471. while (!IsListEmpty(&TmpGlobalList)) {
  472. pListEntry = RemoveTailList(&TmpGlobalList);
  473. InsertHeadList(&GlobalToDoList, pListEntry);
  474. }
  475. return Status;
  476. }
  477. NTSTATUS
  478. CopyToDoItemParameters(
  479. IN IMIRROR_TODO Item,
  480. OUT PVOID Buffer,
  481. IN OUT PULONG Length
  482. )
  483. /*++
  484. Routine Description:
  485. This routine finds the first instance of Item, and copies its current parameters into Buffer.
  486. Arguments:
  487. Item - The item id.
  488. Buffer - The arguments, context for the item.
  489. Length - Length of the buffer in bytes.
  490. Return Value:
  491. STATUS_SUCCESS if it was able to change the item, else an appropriate error status.
  492. --*/
  493. {
  494. PLIST_ENTRY pListEntry;
  495. LIST_ENTRY TmpGlobalList;
  496. PTODOLIST pToDoList;
  497. ULONG i;
  498. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  499. InitializeListHead(&TmpGlobalList);
  500. while (!IsListEmpty(&GlobalToDoList)) {
  501. //
  502. // Get the first list
  503. //
  504. pListEntry = RemoveHeadList(&GlobalToDoList);
  505. pToDoList = CONTAINING_RECORD(pListEntry,
  506. TODOLIST,
  507. ListEntry
  508. );
  509. //
  510. // Save the entry away for later
  511. //
  512. InsertTailList(&TmpGlobalList, pListEntry);
  513. //
  514. // Walk the list until we find an item that matches.
  515. //
  516. i = 0;
  517. while (i < pToDoList->ToDoNum) {
  518. if (pToDoList->ToDoList[i].Item == Item) {
  519. if (pToDoList->ToDoList[i].Length <= *Length) {
  520. if (pToDoList->ToDoList[i].Length != 0) {
  521. RtlMoveMemory(Buffer,
  522. pToDoList->ToDoList[i].Buffer,
  523. pToDoList->ToDoList[i].Length
  524. );
  525. }
  526. Status = STATUS_SUCCESS;
  527. } else {
  528. Status = STATUS_INSUFFICIENT_RESOURCES;
  529. }
  530. *Length = pToDoList->ToDoList[i].Length;
  531. goto Done;
  532. }
  533. i++;
  534. }
  535. }
  536. Done:
  537. //
  538. // Restore global list
  539. //
  540. while (!IsListEmpty(&TmpGlobalList)) {
  541. pListEntry = RemoveTailList(&TmpGlobalList);
  542. InsertHeadList(&GlobalToDoList, pListEntry);
  543. }
  544. return Status;
  545. }