/*++ 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; }