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
786 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
imirror.c
|
|
|
|
Abstract:
|
|
|
|
This is the file for the IntelliMirror conversion DLL basic To Do item processing.
|
|
|
|
Author:
|
|
|
|
Sean Selitrennikoff - 4/5/98
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
LIST_ENTRY GlobalToDoList;
|
|
IMIRROR_CALLBACK Callbacks;
|
|
BYTE TmpBuffer[TMP_BUFFER_SIZE];
|
|
BYTE TmpBuffer2[TMP_BUFFER_SIZE];
|
|
BYTE TmpBuffer3[TMP_BUFFER_SIZE];
|
|
|
|
BOOL fCallbackPreviouslySet = FALSE;
|
|
|
|
//
|
|
// Definitions for this file
|
|
//
|
|
typedef struct _TODOITEM {
|
|
IMIRROR_TODO Item;
|
|
PVOID Buffer;
|
|
ULONG Length;
|
|
} TODOITEM, *PTODOITEM;
|
|
|
|
|
|
typedef struct _TODOLIST {
|
|
LIST_ENTRY ListEntry;
|
|
ULONG ToDoNum;
|
|
TODOITEM ToDoList[1];
|
|
} TODOLIST, *PTODOLIST;
|
|
|
|
|
|
|
|
VOID
|
|
IMirrorInitCallback(
|
|
PIMIRROR_CALLBACK pCallbacks
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the call back structure with the one supplied by the client.
|
|
|
|
Arguments:
|
|
|
|
pCallbacks - Client supplied information for making callbacks to the client.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (pCallbacks != NULL) {
|
|
Callbacks = *pCallbacks;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
// Main processing loop
|
|
//
|
|
//
|
|
//
|
|
NTSTATUS
|
|
ProcessToDoItems(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the main processing loop for To Do Items.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if it completed all to do items properly.
|
|
|
|
--*/
|
|
|
|
{
|
|
IMIRROR_TODO Item;
|
|
PVOID pBuffer;
|
|
ULONG Length;
|
|
NTSTATUS Status;
|
|
|
|
Status = InitToDo();
|
|
if ( Status != STATUS_SUCCESS )
|
|
return Status;
|
|
|
|
while (1) {
|
|
|
|
Status = GetNextToDoItem(&Item, &pBuffer, &Length);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
IMirrorHandleError(Status, IMirrorNone);
|
|
return Status;
|
|
}
|
|
|
|
switch (Item) {
|
|
|
|
case IMirrorNone:
|
|
return STATUS_SUCCESS;
|
|
|
|
case VerifySystemIsNt5:
|
|
Status = CheckIfNt5();
|
|
break;
|
|
|
|
case CheckPartitions:
|
|
Status = CheckForPartitions();
|
|
break;
|
|
|
|
case CopyPartitions:
|
|
Status = CopyCopyPartitions(pBuffer, Length);
|
|
break;
|
|
|
|
case CopyFiles:
|
|
Status = CopyCopyFiles(pBuffer, Length);
|
|
break;
|
|
|
|
case CopyRegistry:
|
|
Status = CopyCopyRegistry(pBuffer, Length);
|
|
break;
|
|
|
|
case RebootSystem:
|
|
Status = Callbacks.RebootFn(Callbacks.Context);
|
|
break;
|
|
}
|
|
|
|
IMirrorFreeMem(pBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
// TO DO Item functions
|
|
//
|
|
//
|
|
//
|
|
|
|
NTSTATUS
|
|
InitToDo(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads from the registry all the current ToDo items and puts
|
|
them in a single TODOLIST.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if it was initialized properly, else the appropriate error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Initialize global variables
|
|
//
|
|
InitializeListHead(&GlobalToDoList);
|
|
|
|
//
|
|
// If there is nothing in the registry, presume this is a fresh start.
|
|
//
|
|
|
|
Status = AddCheckMachineToDoItems();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ClearAllToDoItems(TRUE);
|
|
return Status;
|
|
}
|
|
|
|
Status = AddCopyToDoItems();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ClearAllToDoItems(TRUE);
|
|
return Status;
|
|
}
|
|
|
|
if ( Callbacks.RebootFn ) {
|
|
AddToDoItem( RebootSystem, NULL, 0 );
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetNextToDoItem(
|
|
OUT PIMIRROR_TODO Item,
|
|
OUT PVOID *Buffer,
|
|
OUT PULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the next thing TODO from the global list.
|
|
|
|
NOTE: The client is responsible for freeing Buffer.
|
|
|
|
Arguments:
|
|
|
|
Item - Place to store the next item to process.
|
|
|
|
Buffer - Any context for the item.
|
|
|
|
Length - Number of bytes in Buffer.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if it was able to get an item, else an appropriate error code.
|
|
|
|
--*/
|
|
{
|
|
PTODOLIST pToDoList;
|
|
PTODOLIST pNewToDoList;
|
|
PLIST_ENTRY pListEntry = NULL;
|
|
|
|
*Item = IMirrorNone;
|
|
*Buffer = NULL;
|
|
*Length = 0;
|
|
|
|
pToDoList = NULL;
|
|
|
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|
|
|
//
|
|
// Get the first list
|
|
//
|
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|
|
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|
TODOLIST,
|
|
ListEntry
|
|
);
|
|
|
|
if (pToDoList->ToDoNum != 0) {
|
|
break;
|
|
}
|
|
|
|
IMirrorFreeMem(pToDoList);
|
|
pToDoList = NULL;
|
|
|
|
}
|
|
|
|
if (IsListEmpty(&GlobalToDoList) && (pToDoList == NULL)) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!pListEntry) {
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
ASSERT(pToDoList->ToDoNum != 0);
|
|
|
|
//
|
|
// Found the first item.
|
|
//
|
|
|
|
*Item = pToDoList->ToDoList[0].Item;
|
|
*Buffer = pToDoList->ToDoList[0].Buffer;
|
|
*Length = pToDoList->ToDoList[0].Length;
|
|
|
|
if (Callbacks.RemoveToDoFn != NULL) {
|
|
|
|
Callbacks.RemoveToDoFn( Callbacks.Context, *Item, *Buffer, *Length );
|
|
}
|
|
|
|
pToDoList->ToDoNum--;
|
|
|
|
//
|
|
// Now create a new ToDo list for anything that may get added by the processing of this item.
|
|
// This creates an effective 'stack' of to do items, so that things get processed in the
|
|
// correct order.
|
|
//
|
|
|
|
pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST));
|
|
|
|
if (pNewToDoList == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Do an effective "pop" on the current list, by moving everything else up the list
|
|
//
|
|
if (pToDoList->ToDoNum == 0) {
|
|
IMirrorFreeMem(pToDoList);
|
|
} else {
|
|
RtlMoveMemory(&(pToDoList->ToDoList[0]), &(pToDoList->ToDoList[1]), sizeof(TODOITEM) * pToDoList->ToDoNum);
|
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|
}
|
|
|
|
//
|
|
// Now push on the new space for new items.
|
|
//
|
|
pNewToDoList->ToDoNum = 0;
|
|
InsertHeadList(&GlobalToDoList, &(pNewToDoList->ListEntry));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
AddToDoItem(
|
|
IN IMIRROR_TODO Item,
|
|
IN PVOID Buffer,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds a TODO item to the end of the current list. It allocates
|
|
new memory and copies the buffer.
|
|
|
|
Arguments:
|
|
|
|
Item - The item id.
|
|
|
|
Buffer - Buffer for any arguments, context for the item.
|
|
|
|
Length - Length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if it was able to add the item, else an appropriate error status.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTODOLIST pNewToDoList;
|
|
PLIST_ENTRY pListEntry;
|
|
PBYTE pBuf;
|
|
PTODOLIST pToDoList;
|
|
ULONG err;
|
|
|
|
if (Callbacks.AddToDoFn != NULL) {
|
|
|
|
err = Callbacks.AddToDoFn( Callbacks.Context, Item, Buffer, Length );
|
|
|
|
if (err != STATUS_SUCCESS) {
|
|
|
|
//
|
|
// if the UI bounces the request, we'll treat it as success.
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate space for the buffer
|
|
//
|
|
if (Length != 0) {
|
|
|
|
pBuf = IMirrorAllocMem(Length);
|
|
|
|
if (pBuf == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
} else {
|
|
pBuf = NULL;
|
|
}
|
|
|
|
//
|
|
// Get the current TODO List
|
|
//
|
|
if (IsListEmpty(&GlobalToDoList)) {
|
|
|
|
pNewToDoList = IMirrorAllocMem(sizeof(TODOLIST));
|
|
if (pNewToDoList == NULL) {
|
|
IMirrorFreeMem(pBuf);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
pNewToDoList->ToDoNum = 1;
|
|
|
|
} else {
|
|
|
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|
|
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|
TODOLIST,
|
|
ListEntry
|
|
);
|
|
|
|
//
|
|
// Allocate space for the new item
|
|
//
|
|
pNewToDoList = IMirrorReallocMem(pToDoList, sizeof(TODOLIST) + sizeof(TODOITEM) * pToDoList->ToDoNum);
|
|
|
|
if (pNewToDoList == NULL) {
|
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|
IMirrorFreeMem(pBuf);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
pNewToDoList->ToDoNum++;
|
|
|
|
}
|
|
|
|
//
|
|
// Insert the item at the end of the list
|
|
//
|
|
if (pBuf != NULL) {
|
|
RtlMoveMemory(pBuf, Buffer, Length);
|
|
}
|
|
pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Item = Item;
|
|
pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Buffer = pBuf;
|
|
pNewToDoList->ToDoList[pNewToDoList->ToDoNum - 1].Length = Length;
|
|
|
|
pListEntry = &(pNewToDoList->ListEntry);
|
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
ClearAllToDoItems(
|
|
IN BOOLEAN MemoryOnly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine clears out all To Do items in memory and the registry
|
|
|
|
Arguments:
|
|
|
|
MemoryOnly - TRUE if to only clear the stuff in memory.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PTODOLIST pToDoList;
|
|
PLIST_ENTRY pListEntry;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Handle;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Clear out all the items in memory
|
|
//
|
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|
|
|
//
|
|
// Get the first list
|
|
//
|
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|
|
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|
TODOLIST,
|
|
ListEntry
|
|
);
|
|
|
|
while (pToDoList->ToDoNum != 0) {
|
|
pToDoList->ToDoNum--;
|
|
|
|
if (Callbacks.RemoveToDoFn != NULL) {
|
|
|
|
Callbacks.RemoveToDoFn( Callbacks.Context,
|
|
pToDoList->ToDoList[pToDoList->ToDoNum].Item,
|
|
pToDoList->ToDoList[pToDoList->ToDoNum].Buffer,
|
|
pToDoList->ToDoList[pToDoList->ToDoNum].Length );
|
|
}
|
|
|
|
if (pToDoList->ToDoList[pToDoList->ToDoNum].Length != 0) {
|
|
IMirrorFreeMem(pToDoList->ToDoList[pToDoList->ToDoNum].Buffer);
|
|
}
|
|
}
|
|
|
|
IMirrorFreeMem(pToDoList);
|
|
|
|
}
|
|
|
|
if (MemoryOnly) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Now clear out the ones in the registry
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\RemoteBoot");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenKey(&Handle,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return;
|
|
}
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"ConversionState");
|
|
|
|
Status = NtDeleteValueKey(Handle, &UnicodeString);
|
|
|
|
NtClose(Handle);
|
|
}
|
|
|
|
NTSTATUS
|
|
SaveAllToDoItems(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes out all To Do items in the list to the registry so that conversion
|
|
can be restarted later.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if it was able to save, else an appropriate error status.
|
|
|
|
--*/
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ModifyToDoItem(
|
|
IN IMIRROR_TODO Item,
|
|
IN PVOID Buffer,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine changes the parameters to the first TODO item that matches Item.
|
|
|
|
Arguments:
|
|
|
|
Item - The item id.
|
|
|
|
Buffer - Buffer for any arguments, context for the item.
|
|
|
|
Length - Length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if it was able to change the item, else an appropriate error status.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY pListEntry;
|
|
LIST_ENTRY TmpGlobalList;
|
|
PTODOLIST pToDoList;
|
|
ULONG i;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
InitializeListHead(&TmpGlobalList);
|
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|
|
|
//
|
|
// Get the first list
|
|
//
|
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|
|
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|
TODOLIST,
|
|
ListEntry
|
|
);
|
|
|
|
//
|
|
// Save the entry away for later
|
|
//
|
|
InsertTailList(&TmpGlobalList, pListEntry);
|
|
|
|
//
|
|
// Walk the list until we find an item that matches.
|
|
//
|
|
i = 0;
|
|
|
|
while (i < pToDoList->ToDoNum) {
|
|
|
|
if (pToDoList->ToDoList[i].Item == Item) {
|
|
|
|
if (pToDoList->ToDoList[i].Length == Length) {
|
|
|
|
RtlMoveMemory(pToDoList->ToDoList[i].Buffer, Buffer, Length);
|
|
|
|
} else {
|
|
|
|
PVOID pTmp;
|
|
|
|
pTmp = IMirrorAllocMem(Length);
|
|
|
|
if (pTmp == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (pToDoList->ToDoList[i].Length != 0) {
|
|
IMirrorFreeMem(pToDoList->ToDoList[i].Buffer);
|
|
}
|
|
|
|
pToDoList->ToDoList[i].Buffer = pTmp;
|
|
pToDoList->ToDoList[i].Length = Length;
|
|
|
|
RtlMoveMemory(pTmp, Buffer, Length);
|
|
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto Done;
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Done:
|
|
|
|
//
|
|
// Restore global list
|
|
//
|
|
while (!IsListEmpty(&TmpGlobalList)) {
|
|
pListEntry = RemoveTailList(&TmpGlobalList);
|
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
CopyToDoItemParameters(
|
|
IN IMIRROR_TODO Item,
|
|
OUT PVOID Buffer,
|
|
IN OUT PULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds the first instance of Item, and copies its current parameters into Buffer.
|
|
|
|
Arguments:
|
|
|
|
Item - The item id.
|
|
|
|
Buffer - The arguments, context for the item.
|
|
|
|
Length - Length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if it was able to change the item, else an appropriate error status.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY pListEntry;
|
|
LIST_ENTRY TmpGlobalList;
|
|
PTODOLIST pToDoList;
|
|
ULONG i;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
InitializeListHead(&TmpGlobalList);
|
|
while (!IsListEmpty(&GlobalToDoList)) {
|
|
|
|
//
|
|
// Get the first list
|
|
//
|
|
pListEntry = RemoveHeadList(&GlobalToDoList);
|
|
|
|
pToDoList = CONTAINING_RECORD(pListEntry,
|
|
TODOLIST,
|
|
ListEntry
|
|
);
|
|
|
|
//
|
|
// Save the entry away for later
|
|
//
|
|
InsertTailList(&TmpGlobalList, pListEntry);
|
|
|
|
//
|
|
// Walk the list until we find an item that matches.
|
|
//
|
|
i = 0;
|
|
|
|
while (i < pToDoList->ToDoNum) {
|
|
|
|
if (pToDoList->ToDoList[i].Item == Item) {
|
|
|
|
if (pToDoList->ToDoList[i].Length <= *Length) {
|
|
|
|
if (pToDoList->ToDoList[i].Length != 0) {
|
|
|
|
RtlMoveMemory(Buffer,
|
|
pToDoList->ToDoList[i].Buffer,
|
|
pToDoList->ToDoList[i].Length
|
|
);
|
|
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
*Length = pToDoList->ToDoList[i].Length;
|
|
goto Done;
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Done:
|
|
|
|
//
|
|
// Restore global list
|
|
//
|
|
while (!IsListEmpty(&TmpGlobalList)) {
|
|
pListEntry = RemoveTailList(&TmpGlobalList);
|
|
InsertHeadList(&GlobalToDoList, pListEntry);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|