968 lines
27 KiB
C
968 lines
27 KiB
C
/*++
|
||
|
||
Copyright (c) 1998 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
copy.c
|
||
|
||
Abstract:
|
||
|
||
This is for supporting copying files, creating new files, and copying the registries to
|
||
the remote server.
|
||
|
||
Author:
|
||
|
||
Sean Selitrennikoff - 4/5/98
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
WCHAR pConfigPath[MAX_PATH];
|
||
WCHAR pSystemPath[MAX_PATH];
|
||
WCHAR pCSDVersion[128];
|
||
WCHAR pProcessorArchitecture[64];
|
||
WCHAR pCurrentType[128];
|
||
WCHAR pHalName[128];
|
||
|
||
#if 0
|
||
IMIRROR_MODIFY_DS_INFO ModifyInfo;
|
||
#endif
|
||
|
||
NTSTATUS
|
||
AddCopyToDoItems(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds all the to do items necessary for copying files and registries to
|
||
a server installation point, as well as creating new files necessary for remote boot.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if it completes adding all the to do items properly.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
Status = AddToDoItem(CheckPartitions, NULL, 0);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, IMirrorInitialize);
|
||
return Status;
|
||
}
|
||
|
||
Status = AddToDoItem(CopyPartitions, NULL, 0);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, IMirrorInitialize);
|
||
return Status;
|
||
}
|
||
#if 0
|
||
Status = AddToDoItem(PatchDSEntries, &ModifyInfo, sizeof(ModifyInfo)); // NOTE: This MUST come before MungeRegistry
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, IMirrorInitialize);
|
||
return Status;
|
||
}
|
||
#endif
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// Functions for processing each TO DO item
|
||
//
|
||
|
||
NTSTATUS
|
||
CopyCopyPartitions(
|
||
IN PVOID pBuffer,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine verifies that any partition on the same disk as in the parameter pBuffer, has
|
||
enough free space to hold all the files in the partition that is also in pBuffer.
|
||
|
||
Arguments:
|
||
|
||
pBuffer - Pointer to any arguments passed in the to do item.
|
||
|
||
Length - Length, in bytes of the arguments.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if it completes adding all the to do items properly.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PLIST_ENTRY listEntry;
|
||
PMIRROR_VOLUME_INFO mirrorVolInfo;
|
||
ULONG numberPartitions;
|
||
BOOLEAN copyRegistry = FALSE;
|
||
ULONG NameLength;
|
||
ULONG TmpUlong;
|
||
ULONG baseLength;
|
||
BOOLEAN gotUncPath = FALSE;
|
||
|
||
IMirrorNowDoing(CopyPartitions, NULL);
|
||
|
||
if (GlobalMirrorCfgInfo == NULL) {
|
||
|
||
Status = CheckForPartitions( pBuffer, Length );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyPartitions);
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
listEntry = GlobalMirrorCfgInfo->MirrorVolumeList.Flink;
|
||
|
||
numberPartitions = 0;
|
||
Status = STATUS_SUCCESS;
|
||
|
||
while (listEntry != &GlobalMirrorCfgInfo->MirrorVolumeList) {
|
||
|
||
mirrorVolInfo = (PMIRROR_VOLUME_INFO) CONTAINING_RECORD(
|
||
listEntry,
|
||
MIRROR_VOLUME_INFO,
|
||
ListEntry
|
||
);
|
||
listEntry = listEntry->Flink;
|
||
|
||
if (mirrorVolInfo->MirrorUncPath == NULL) {
|
||
|
||
if (! gotUncPath) {
|
||
|
||
gotUncPath = TRUE;
|
||
NameLength = TMP_BUFFER_SIZE;
|
||
|
||
Status = IMirrorGetMirrorDir( (PWCHAR)TmpBuffer,
|
||
&NameLength);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
IMirrorHandleError(Status, CopyPartitions);
|
||
return Status;
|
||
}
|
||
|
||
baseLength = lstrlenW( (PWCHAR) TmpBuffer );
|
||
}
|
||
|
||
swprintf( (PWCHAR)TmpBuffer2,
|
||
L"\\Mirror%d",
|
||
mirrorVolInfo->MirrorTableIndex );
|
||
|
||
*((PWCHAR)(TmpBuffer)+baseLength) = L'\0';
|
||
|
||
lstrcatW( (PWCHAR)TmpBuffer, (PWCHAR)TmpBuffer2 );
|
||
|
||
NameLength = (lstrlenW( (PWCHAR)TmpBuffer ) + 1) * sizeof(WCHAR);
|
||
|
||
mirrorVolInfo->MirrorUncPath = IMirrorAllocMem(NameLength);
|
||
|
||
if (mirrorVolInfo->MirrorUncPath == NULL) {
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
IMirrorHandleError(Status, CopyPartitions);
|
||
return Status;
|
||
}
|
||
|
||
RtlMoveMemory( mirrorVolInfo->MirrorUncPath,
|
||
TmpBuffer,
|
||
NameLength );
|
||
}
|
||
|
||
IMirrorNowDoing(CopyPartitions, mirrorVolInfo->MirrorUncPath);
|
||
|
||
if (mirrorVolInfo->IsBootDisk) {
|
||
|
||
copyRegistry = TRUE;
|
||
}
|
||
|
||
Status = AddToDoItem(CopyFiles, &mirrorVolInfo->DriveLetter, sizeof(WCHAR));
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CheckPartitions);
|
||
return Status;
|
||
}
|
||
|
||
numberPartitions++;
|
||
}
|
||
|
||
if (copyRegistry) {
|
||
|
||
Status = AddToDoItem(CopyRegistry, pBuffer, Length);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyPartitions);
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// write out the mirror config file locally so that if we restart, we
|
||
// can retrieve the same config again.
|
||
//
|
||
|
||
if (numberPartitions && ! GlobalMirrorCfgInfo->SysPrepImage) {
|
||
|
||
//
|
||
// Write it out to \\SystemRoot\System32\IMirror.dat
|
||
//
|
||
|
||
Status = GetBaseDeviceName(L"\\SystemRoot", (PWCHAR)TmpBuffer2, sizeof(TmpBuffer2));
|
||
|
||
wcscat((PWCHAR)TmpBuffer2, L"\\System32\\");
|
||
wcscat((PWCHAR)TmpBuffer2, IMIRROR_DAT_FILE_NAME );
|
||
|
||
Status = NtPathToDosPath((PWCHAR)TmpBuffer2, (PWCHAR)TmpBuffer, FALSE, FALSE);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
Status = WriteMirrorConfigFile((PWCHAR) TmpBuffer);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyPartitions);
|
||
}
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CopyCopyFiles(
|
||
IN PVOID pBuffer,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies all the files on the given drive to the remote server.
|
||
|
||
Arguments:
|
||
|
||
pBuffer - Pointer to any arguments passed in the to do item.
|
||
The argument must be the drive letter
|
||
|
||
Length - Length, in bytes of the arguments. Should be sizeof(WCHAR)
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if it completes the to do item properly.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY listEntry;
|
||
PMIRROR_VOLUME_INFO mirrorVolInfo;
|
||
NTSTATUS Status;
|
||
WCHAR LocalBuffer[TMP_BUFFER_SIZE];
|
||
WCHAR SourcePath[8];
|
||
PCOPY_TREE_CONTEXT copyContext = NULL;
|
||
BOOLEAN BackupPriviledged = FALSE;
|
||
|
||
Status = IMirrorNowDoing(CopyFiles, NULL);
|
||
if ( Status != NO_ERROR ) {
|
||
return Status;
|
||
}
|
||
|
||
if (GlobalMirrorCfgInfo == NULL) {
|
||
|
||
Status = CheckForPartitions( pBuffer, Length );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyFiles);
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
if (Length != sizeof(WCHAR) || pBuffer == NULL) {
|
||
|
||
IMirrorHandleError(ERROR_INVALID_DRIVE, CopyFiles);
|
||
return ERROR_INVALID_DRIVE;
|
||
}
|
||
|
||
listEntry = GlobalMirrorCfgInfo->MirrorVolumeList.Flink;
|
||
|
||
while (listEntry != &GlobalMirrorCfgInfo->MirrorVolumeList) {
|
||
|
||
mirrorVolInfo = (PMIRROR_VOLUME_INFO) CONTAINING_RECORD(
|
||
listEntry,
|
||
MIRROR_VOLUME_INFO,
|
||
ListEntry
|
||
);
|
||
listEntry = listEntry->Flink;
|
||
|
||
if (mirrorVolInfo->DriveLetter == *(PWCHAR)pBuffer) {
|
||
break;
|
||
}
|
||
|
||
mirrorVolInfo = NULL;
|
||
}
|
||
if (mirrorVolInfo == NULL) {
|
||
|
||
IMirrorHandleError(ERROR_INVALID_DRIVE, CopyFiles);
|
||
return ERROR_INVALID_DRIVE;
|
||
}
|
||
|
||
//
|
||
// Create root directory, don't fail if it already exists
|
||
//
|
||
if (!CreateDirectory(mirrorVolInfo->MirrorUncPath, NULL)) {
|
||
|
||
Status = GetLastError();
|
||
|
||
if (Status != ERROR_ALREADY_EXISTS) {
|
||
IMirrorHandleError(Status, CopyFiles);
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// create the config file in this mirror root
|
||
//
|
||
|
||
lstrcpyW( LocalBuffer, mirrorVolInfo->MirrorUncPath );
|
||
wcscat( LocalBuffer, L"\\");
|
||
wcscat( LocalBuffer, IMIRROR_DAT_FILE_NAME );
|
||
|
||
Status = WriteMirrorConfigFile(LocalBuffer);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyFiles);
|
||
return Status;
|
||
}
|
||
|
||
if (!GlobalMirrorCfgInfo->SysPrepImage) {
|
||
|
||
//
|
||
// create staging directory if one is required
|
||
//
|
||
|
||
lstrcpyW( LocalBuffer, mirrorVolInfo->MirrorUncPath );
|
||
wcscat( LocalBuffer, L"\\Staging");
|
||
|
||
if (!CreateDirectory( LocalBuffer, NULL)) {
|
||
Status = GetLastError();
|
||
|
||
if (Status != ERROR_ALREADY_EXISTS) {
|
||
IMirrorHandleError(Status, CopyFiles);
|
||
return Status;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (mirrorVolInfo->PartitionActive) {
|
||
|
||
//
|
||
// copy the boot code to the server
|
||
//
|
||
|
||
lstrcpyW( LocalBuffer, mirrorVolInfo->MirrorUncPath );
|
||
wcscat( LocalBuffer, L"\\BootCode.dat");
|
||
|
||
Status = SaveBootSector( mirrorVolInfo->DiskNumber,
|
||
mirrorVolInfo->PartitionNumber,
|
||
mirrorVolInfo->BlockSize,
|
||
LocalBuffer );
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
IMirrorHandleError(Status, CopyFiles);
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Create UserData directory, don't fail if it already exists
|
||
//
|
||
|
||
lstrcpyW( LocalBuffer, mirrorVolInfo->MirrorUncPath );
|
||
wcscat( LocalBuffer, L"\\UserData");
|
||
|
||
if (!CreateDirectory( LocalBuffer, NULL)) {
|
||
Status = GetLastError();
|
||
|
||
if (Status != ERROR_ALREADY_EXISTS) {
|
||
IMirrorHandleError(Status, CopyFiles);
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// set up the dest path ready for really long file names.
|
||
//
|
||
|
||
if (*(mirrorVolInfo->MirrorUncPath) == L'\\' &&
|
||
*(mirrorVolInfo->MirrorUncPath+1) == L'\\') {
|
||
|
||
if (*(mirrorVolInfo->MirrorUncPath+2) == L'?') {
|
||
|
||
// dest is \\?\..., it's of the correct format
|
||
|
||
lstrcpyW( LocalBuffer, mirrorVolInfo->MirrorUncPath );
|
||
|
||
} else {
|
||
|
||
// dest is \\billg1\imirror
|
||
// format should be \\?\UNC\billg1\imirror
|
||
|
||
lstrcpyW( LocalBuffer, L"\\\\?\\UNC" );
|
||
lstrcatW( LocalBuffer, mirrorVolInfo->MirrorUncPath + 1 );
|
||
}
|
||
} else {
|
||
|
||
// dest is something like X:
|
||
// format should be \\?\X:
|
||
|
||
lstrcpyW( LocalBuffer, L"\\\\?\\" );
|
||
lstrcatW( LocalBuffer, mirrorVolInfo->MirrorUncPath );
|
||
}
|
||
|
||
wcscat( LocalBuffer, L"\\UserData");
|
||
|
||
SourcePath[0] = L'\\'; // format is L"\\\\?\\E:"
|
||
SourcePath[1] = L'\\';
|
||
SourcePath[2] = L'?';
|
||
SourcePath[3] = L'\\';
|
||
SourcePath[4] = mirrorVolInfo->DriveLetter;
|
||
SourcePath[5] = L':';
|
||
SourcePath[6] = L'\\';
|
||
SourcePath[7] = L'\0';
|
||
|
||
//
|
||
// Copy all the files
|
||
//
|
||
|
||
Status = AllocateCopyTreeContext( ©Context, TRUE );
|
||
|
||
if (Status != ERROR_SUCCESS) {
|
||
|
||
IMirrorHandleError(Status, CopyFiles);
|
||
return Status;
|
||
}
|
||
|
||
if (RTEnableBackupRestorePrivilege()) {
|
||
BackupPriviledged = TRUE;
|
||
}
|
||
|
||
Status = CopyTree( copyContext,
|
||
(BOOLEAN) (mirrorVolInfo->PartitionType == PARTITION_IFS),
|
||
&SourcePath[0],
|
||
LocalBuffer );
|
||
|
||
if (BackupPriviledged) {
|
||
RTDisableBackupRestorePrivilege();
|
||
}
|
||
|
||
if (copyContext->Cancelled) {
|
||
//
|
||
// since the copy was cancelled, let's bail on the rest of the processing.
|
||
//
|
||
|
||
ClearAllToDoItems(TRUE);
|
||
}
|
||
|
||
FreeCopyTreeContext( copyContext );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyFiles);
|
||
return(Status);
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
CopyCopyRegistry(
|
||
IN PVOID pBuffer,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies the currently running registries to the server.
|
||
|
||
Arguments:
|
||
|
||
pBuffer - Pointer to any arguments passed in the to do item.
|
||
|
||
Length - Length, in bytes of the arguments.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if it completes the to do item properly.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PLIST_ENTRY listEntry;
|
||
ULONG Error;
|
||
PMIRROR_VOLUME_INFO mirrorVolInfo;
|
||
|
||
IMirrorNowDoing(CopyRegistry, NULL);
|
||
|
||
if (GlobalMirrorCfgInfo == NULL) {
|
||
|
||
Status = CheckForPartitions( pBuffer, Length );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyRegistry);
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
listEntry = GlobalMirrorCfgInfo->MirrorVolumeList.Flink;
|
||
|
||
while (listEntry != &GlobalMirrorCfgInfo->MirrorVolumeList) {
|
||
|
||
mirrorVolInfo = (PMIRROR_VOLUME_INFO) CONTAINING_RECORD(
|
||
listEntry,
|
||
MIRROR_VOLUME_INFO,
|
||
ListEntry
|
||
);
|
||
listEntry = listEntry->Flink;
|
||
|
||
if (mirrorVolInfo->IsBootDisk) {
|
||
break;
|
||
}
|
||
|
||
mirrorVolInfo = NULL;
|
||
}
|
||
if (mirrorVolInfo == NULL) {
|
||
|
||
IMirrorHandleError(ERROR_INVALID_DRIVE, CopyRegistry);
|
||
return ERROR_INVALID_DRIVE;
|
||
}
|
||
|
||
//
|
||
// Now do registry backup
|
||
//
|
||
|
||
Error = DoFullRegBackup( mirrorVolInfo->MirrorUncPath );
|
||
if (Error != NO_ERROR) {
|
||
IMirrorHandleError(Error, CopyRegistry);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
WriteMirrorConfigFile(
|
||
PWCHAR DestFile
|
||
)
|
||
{
|
||
ULONG bufferSize;
|
||
PCHAR buffer;
|
||
PLIST_ENTRY listEntry;
|
||
PMIRROR_VOLUME_INFO mirrorVolInfo;
|
||
PMIRROR_VOLUME_INFO_FILE mirrorVolInfoFile;
|
||
PMIRROR_CFG_INFO_FILE mirrorInfoFile;
|
||
ULONG pathLength;
|
||
ULONG systemPathLength;
|
||
ULONG csdVersionLength;
|
||
ULONG processorArchitectureLength;
|
||
ULONG currentTypeLength;
|
||
ULONG halNameLength;
|
||
PWCHAR nextString;
|
||
NTSTATUS Status;
|
||
HANDLE fileHandle;
|
||
|
||
retryWriteConfig:
|
||
|
||
mirrorInfoFile = NULL;
|
||
Status = STATUS_SUCCESS;
|
||
fileHandle = INVALID_HANDLE_VALUE;
|
||
|
||
ASSERT(GlobalMirrorCfgInfo != NULL);
|
||
|
||
systemPathLength = (lstrlenW( GlobalMirrorCfgInfo->SystemPath ) + 1) * sizeof(WCHAR);
|
||
csdVersionLength = (lstrlenW( GlobalMirrorCfgInfo->CSDVersion ) + 1) * sizeof(WCHAR);
|
||
processorArchitectureLength = (lstrlenW( GlobalMirrorCfgInfo->ProcessorArchitecture ) + 1) * sizeof(WCHAR);
|
||
currentTypeLength = (lstrlenW( GlobalMirrorCfgInfo->CurrentType ) + 1) * sizeof(WCHAR);
|
||
halNameLength = (lstrlenW( GlobalMirrorCfgInfo->HalName ) + 1) * sizeof(WCHAR);
|
||
|
||
bufferSize = sizeof( MIRROR_CFG_INFO_FILE ) +
|
||
(sizeof( MIRROR_VOLUME_INFO_FILE ) *
|
||
(GlobalMirrorCfgInfo->NumberVolumes - 1)) +
|
||
systemPathLength +
|
||
csdVersionLength +
|
||
processorArchitectureLength +
|
||
currentTypeLength +
|
||
halNameLength;
|
||
|
||
listEntry = GlobalMirrorCfgInfo->MirrorVolumeList.Flink;
|
||
|
||
while (listEntry != &GlobalMirrorCfgInfo->MirrorVolumeList) {
|
||
|
||
mirrorVolInfo = (PMIRROR_VOLUME_INFO) CONTAINING_RECORD(
|
||
listEntry,
|
||
MIRROR_VOLUME_INFO,
|
||
ListEntry
|
||
);
|
||
listEntry = listEntry->Flink;
|
||
bufferSize += ((lstrlenW( mirrorVolInfo->MirrorUncPath ) + 1) * sizeof(WCHAR)) +
|
||
((lstrlenW( mirrorVolInfo->VolumeLabel ) + 1) * sizeof(WCHAR)) +
|
||
((lstrlenW( mirrorVolInfo->NtName ) + 1) * sizeof(WCHAR)) +
|
||
((lstrlenW( mirrorVolInfo->ArcName ) + 1) * sizeof(WCHAR));
|
||
}
|
||
|
||
mirrorInfoFile = (PMIRROR_CFG_INFO_FILE) IMirrorAllocMem( bufferSize );
|
||
|
||
if (mirrorInfoFile == NULL) {
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
goto exitWriteFile;
|
||
}
|
||
|
||
mirrorInfoFile->MirrorVersion = IMIRROR_CURRENT_VERSION;
|
||
mirrorInfoFile->FileLength = bufferSize;
|
||
mirrorInfoFile->NumberVolumes = GlobalMirrorCfgInfo->NumberVolumes;
|
||
mirrorInfoFile->SystemPathLength = systemPathLength;
|
||
mirrorInfoFile->CSDVersionLength = csdVersionLength;
|
||
mirrorInfoFile->ProcessorArchitectureLength = processorArchitectureLength;
|
||
mirrorInfoFile->CurrentTypeLength = currentTypeLength;
|
||
mirrorInfoFile->HalNameLength = halNameLength;
|
||
mirrorInfoFile->SysPrepImage = GlobalMirrorCfgInfo->SysPrepImage;
|
||
mirrorInfoFile->Debug = GlobalMirrorCfgInfo->Debug;
|
||
mirrorInfoFile->MajorVersion = GlobalMirrorCfgInfo->MajorVersion;
|
||
mirrorInfoFile->MinorVersion = GlobalMirrorCfgInfo->MinorVersion;
|
||
mirrorInfoFile->BuildNumber = GlobalMirrorCfgInfo->BuildNumber;
|
||
mirrorInfoFile->KernelFileVersionMS = GlobalMirrorCfgInfo->KernelFileVersionMS;
|
||
mirrorInfoFile->KernelFileVersionLS = GlobalMirrorCfgInfo->KernelFileVersionLS;
|
||
mirrorInfoFile->KernelFileFlags = GlobalMirrorCfgInfo->KernelFileFlags;
|
||
|
||
mirrorVolInfoFile = &mirrorInfoFile->Volumes[mirrorInfoFile->NumberVolumes];
|
||
nextString = (PWCHAR) mirrorVolInfoFile;
|
||
|
||
mirrorInfoFile->SystemPathOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, GlobalMirrorCfgInfo->SystemPath );
|
||
nextString += systemPathLength / sizeof(WCHAR);
|
||
|
||
mirrorInfoFile->CSDVersionOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, GlobalMirrorCfgInfo->CSDVersion );
|
||
nextString += csdVersionLength / sizeof(WCHAR);
|
||
|
||
mirrorInfoFile->ProcessorArchitectureOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, GlobalMirrorCfgInfo->ProcessorArchitecture );
|
||
nextString += processorArchitectureLength / sizeof(WCHAR);
|
||
|
||
mirrorInfoFile->CurrentTypeOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, GlobalMirrorCfgInfo->CurrentType );
|
||
nextString += currentTypeLength / sizeof(WCHAR);
|
||
|
||
mirrorInfoFile->HalNameOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, GlobalMirrorCfgInfo->HalName );
|
||
nextString += halNameLength / sizeof(WCHAR);
|
||
|
||
listEntry = GlobalMirrorCfgInfo->MirrorVolumeList.Flink;
|
||
|
||
mirrorVolInfoFile = &mirrorInfoFile->Volumes[0];
|
||
|
||
while (listEntry != &GlobalMirrorCfgInfo->MirrorVolumeList) {
|
||
|
||
mirrorVolInfo = (PMIRROR_VOLUME_INFO) CONTAINING_RECORD(
|
||
listEntry,
|
||
MIRROR_VOLUME_INFO,
|
||
ListEntry
|
||
);
|
||
listEntry = listEntry->Flink;
|
||
|
||
mirrorVolInfoFile->MirrorTableIndex = mirrorVolInfo->MirrorTableIndex;
|
||
mirrorVolInfoFile->DriveLetter = mirrorVolInfo->DriveLetter;
|
||
mirrorVolInfoFile->PartitionType = mirrorVolInfo->PartitionType;
|
||
mirrorVolInfoFile->PartitionActive = mirrorVolInfo->PartitionActive;
|
||
mirrorVolInfoFile->IsBootDisk = mirrorVolInfo->IsBootDisk;
|
||
mirrorVolInfoFile->CompressedVolume = mirrorVolInfo->CompressedVolume;
|
||
mirrorVolInfoFile->DiskSignature = mirrorVolInfo->DiskSignature;
|
||
mirrorVolInfoFile->BlockSize = mirrorVolInfo->BlockSize;
|
||
mirrorVolInfoFile->LastUSNMirrored = mirrorVolInfo->LastUSNMirrored;
|
||
mirrorVolInfoFile->FileSystemFlags = mirrorVolInfo->FileSystemFlags;
|
||
wcscpy(mirrorVolInfoFile->FileSystemName, mirrorVolInfo->FileSystemName);
|
||
mirrorVolInfoFile->DiskSpaceUsed = mirrorVolInfo->DiskSpaceUsed;
|
||
mirrorVolInfoFile->StartingOffset = mirrorVolInfo->StartingOffset;
|
||
mirrorVolInfoFile->PartitionSize = mirrorVolInfo->PartitionSize;
|
||
mirrorVolInfoFile->DiskNumber = mirrorVolInfo->DiskNumber;
|
||
mirrorVolInfoFile->PartitionNumber = mirrorVolInfo->PartitionNumber;
|
||
|
||
// set the path in the config file relative to the root of this
|
||
// image. As example, set it to L"\Mirror1\UserData"
|
||
|
||
swprintf( (PWCHAR)TmpBuffer2,
|
||
L"\\Mirror%d\\UserData",
|
||
mirrorVolInfo->MirrorTableIndex );
|
||
|
||
pathLength = (lstrlenW( (PWCHAR)TmpBuffer2 ) + 1) * sizeof(WCHAR);
|
||
mirrorVolInfoFile->MirrorUncLength = pathLength;
|
||
mirrorVolInfoFile->MirrorUncPathOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, (PWCHAR)TmpBuffer2 );
|
||
nextString += pathLength / sizeof(WCHAR);
|
||
|
||
pathLength = (lstrlenW( mirrorVolInfo->VolumeLabel ) + 1) * sizeof(WCHAR);
|
||
mirrorVolInfoFile->VolumeLabelLength = pathLength;
|
||
mirrorVolInfoFile->VolumeLabelOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, mirrorVolInfo->VolumeLabel );
|
||
nextString += pathLength / sizeof(WCHAR);
|
||
|
||
pathLength = (lstrlenW( mirrorVolInfo->NtName ) + 1) * sizeof(WCHAR);
|
||
mirrorVolInfoFile->NtNameLength = pathLength;
|
||
mirrorVolInfoFile->NtNameOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, mirrorVolInfo->NtName );
|
||
nextString += pathLength / sizeof(WCHAR);
|
||
|
||
pathLength = (lstrlenW( mirrorVolInfo->ArcName ) + 1) * sizeof(WCHAR);
|
||
mirrorVolInfoFile->ArcNameLength = pathLength;
|
||
mirrorVolInfoFile->ArcNameOffset = (ULONG)((PCHAR) nextString - (PCHAR) mirrorInfoFile);
|
||
lstrcpyW( nextString, mirrorVolInfo->ArcName );
|
||
nextString += pathLength / sizeof(WCHAR);
|
||
|
||
mirrorVolInfoFile++;
|
||
|
||
//
|
||
// call off to the wizard to tell him what the system directory
|
||
// is if we have a valid one.
|
||
//
|
||
|
||
if (mirrorVolInfo->IsBootDisk && (systemPathLength > 3 * sizeof(WCHAR))) {
|
||
|
||
//
|
||
// pass it in the form of "MirrorX\UserData\WinNT"
|
||
// so we have to skip the C: in the systempath
|
||
//
|
||
|
||
swprintf( (PWCHAR)TmpBuffer2,
|
||
L"Mirror%d\\UserData",
|
||
mirrorVolInfo->MirrorTableIndex );
|
||
|
||
lstrcatW( (PWCHAR)TmpBuffer2, GlobalMirrorCfgInfo->SystemPath + 2 );
|
||
IMirrorSetSystemPath( (PWCHAR) TmpBuffer2,
|
||
(lstrlenW( (PWCHAR) TmpBuffer2)) );
|
||
}
|
||
}
|
||
|
||
fileHandle = CreateFile( DestFile,
|
||
GENERIC_WRITE,
|
||
0,
|
||
NULL,
|
||
CREATE_ALWAYS,
|
||
FILE_ATTRIBUTE_ARCHIVE,
|
||
NULL );
|
||
|
||
if (fileHandle == INVALID_HANDLE_VALUE) {
|
||
|
||
Status = GetLastError();
|
||
goto exitWriteFile;
|
||
}
|
||
|
||
if (!WriteFile( fileHandle,
|
||
mirrorInfoFile,
|
||
bufferSize,
|
||
&bufferSize,
|
||
NULL)) {
|
||
|
||
Status = GetLastError();
|
||
goto exitWriteFile;
|
||
}
|
||
|
||
exitWriteFile:
|
||
|
||
if (fileHandle != INVALID_HANDLE_VALUE) {
|
||
|
||
CloseHandle( fileHandle );
|
||
fileHandle = INVALID_HANDLE_VALUE;
|
||
}
|
||
|
||
if (mirrorInfoFile) {
|
||
IMirrorFreeMem( mirrorInfoFile );
|
||
mirrorInfoFile = NULL;
|
||
}
|
||
|
||
if (Status != ERROR_SUCCESS) {
|
||
|
||
DWORD errorCase;
|
||
|
||
errorCase = ReportCopyError( NULL,
|
||
DestFile,
|
||
COPY_ERROR_ACTION_CREATE_FILE,
|
||
Status );
|
||
if (errorCase == STATUS_RETRY) {
|
||
goto retryWriteConfig;
|
||
}
|
||
if ( errorCase == ERROR_SUCCESS ) {
|
||
Status = ERROR_SUCCESS;
|
||
}
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
#define MIN_BOOT_SECTOR_BLOCK_SIZE 512
|
||
|
||
NTSTATUS
|
||
SaveBootSector(
|
||
DWORD DiskNumber,
|
||
DWORD PartitionNumber,
|
||
DWORD BlockSize,
|
||
PWCHAR DestFile
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
UNICODE_STRING UnicodeString;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
DWORD bufferSize;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
HANDLE bootSectorHandle = INVALID_HANDLE_VALUE;
|
||
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
||
PUCHAR AlignedBuffer;
|
||
PUCHAR allocatedBuffer = NULL;
|
||
|
||
swprintf((PWCHAR)TmpBuffer, L"\\Device\\Harddisk%d\\Partition%d", DiskNumber, PartitionNumber );
|
||
|
||
RtlInitUnicodeString(&UnicodeString, (PWCHAR)TmpBuffer);
|
||
|
||
InitializeObjectAttributes(&ObjectAttributes,
|
||
&UnicodeString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
Status = NtCreateFile(&bootSectorHandle,
|
||
(ACCESS_MASK)FILE_GENERIC_READ,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
NULL,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
FILE_OPEN,
|
||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyPartitions);
|
||
goto exitSaveBootSector;
|
||
}
|
||
|
||
if (BlockSize < MIN_BOOT_SECTOR_BLOCK_SIZE) {
|
||
|
||
BlockSize = MIN_BOOT_SECTOR_BLOCK_SIZE;
|
||
}
|
||
|
||
if (BlockSize + MIN_BOOT_SECTOR_BLOCK_SIZE > TMP_BUFFER_SIZE) {
|
||
|
||
allocatedBuffer = IMirrorAllocMem( BlockSize + MIN_BOOT_SECTOR_BLOCK_SIZE );
|
||
|
||
if (allocatedBuffer == NULL) {
|
||
|
||
Status = STATUS_NO_MEMORY;
|
||
goto exitSaveBootSector;
|
||
}
|
||
|
||
AlignedBuffer = ALIGN(allocatedBuffer, MIN_BOOT_SECTOR_BLOCK_SIZE);
|
||
|
||
} else {
|
||
|
||
AlignedBuffer = ALIGN(TmpBuffer, MIN_BOOT_SECTOR_BLOCK_SIZE);
|
||
}
|
||
|
||
Status = NtReadFile(bootSectorHandle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
AlignedBuffer,
|
||
BlockSize,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyPartitions);
|
||
goto exitSaveBootSector;
|
||
}
|
||
|
||
fileHandle = CreateFile( DestFile,
|
||
GENERIC_WRITE,
|
||
0,
|
||
NULL,
|
||
CREATE_ALWAYS,
|
||
FILE_ATTRIBUTE_ARCHIVE,
|
||
NULL );
|
||
|
||
if (fileHandle == INVALID_HANDLE_VALUE) {
|
||
|
||
Status = GetLastError();
|
||
goto exitSaveBootSector;
|
||
}
|
||
|
||
if (!WriteFile( fileHandle,
|
||
AlignedBuffer,
|
||
BlockSize,
|
||
&bufferSize,
|
||
NULL)) {
|
||
|
||
Status = GetLastError();
|
||
|
||
} else {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
exitSaveBootSector:
|
||
|
||
if (bootSectorHandle != INVALID_HANDLE_VALUE) {
|
||
NtClose(bootSectorHandle);
|
||
}
|
||
|
||
if (fileHandle != INVALID_HANDLE_VALUE) {
|
||
NtClose(fileHandle);
|
||
}
|
||
|
||
if (allocatedBuffer) {
|
||
IMirrorFreeMem( allocatedBuffer );
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
IMirrorHandleError(Status, CopyPartitions);
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|