|
|
#include "enduser.h"
//
// Partition image structure for the partition being restored.
//
PARTITION_IMAGE PartitionImage;
//
// Number of sectors to zap to wipe out an image
// 0.98 MB of 512-byte sectors
//
#define ZAP_MAX 2000
//
// Maximum size of FAT32 fats
#define MAX_FAT32_TABLE_SIZE (16*1024*1024-65536)
#define MAX_FAT32_ENTRIES ((16*1024*1024-65536)/4)
VOID RelocateClusterBitmap( IN HDISK DiskHandle, IN ULONG ImageStart );
VOID RelocateBootPartition( IN HDISK DiskHandle, IN USHORT Cylinders, IN ULONG ExtendedCount );
VOID FixUpBpb( IN HDISK DiskHandle, IN BYTE SectorsPerTrack, IN USHORT Heads, IN ULONG StartSector );
VOID RemoveNonSelectedOsData( IN HDISK DiskHandle );
VOID CreatePartitionTableEntry( IN HDISK DiskHandle, IN USHORT Cylinders, IN ULONG DiskSectorCount, IN ULONG StartSector, OUT ULONG *LastSector, IN BOOL Relocating );
VOID TellUserToWait( VOID );
VOID StartGauge( VOID );
BOOL TestImage( IN HDISK DiskHandle, IN ULONG StartSector );
BOOL MungeParametersForFat32Extend( IN HDISK DiskHandle, IN USHORT Cylinders, IN BYTE SectorsPerTrack, IN ULONG SourceStart, IN ULONG *TargetStart, IN FPMASTER_DISK pMasterDisk, IN FPPARTITION_IMAGE pPartitionImage, IN VOID *TemporaryBuffer );
VOID AdjustTargetStart( IN HDISK DiskHandle, IN BYTE SectorsPerTrack, IN ULONG *TargetStart, IN VOID *TemporaryBuffer );
ULONG ComputeClusters( IN ULONG ClusterSize, IN ULONG Sectors, IN ULONG SectorSize, IN ULONG ReservedSectors, IN ULONG Fats );
BOOL IsUnknownPartition( IN BYTE SysId );
VOID RestoreUsersDisk( IN HDISK DiskHandle )
/*++
Routine Description:
This is the top-level routine concerned with restoring the user's disk so it seems as if only a single os was ever preinstalled on it.
Arguments:
DiskHandle - supplies open disk handle to master/target hard disk.
Return Value:
None. Does not return if error.
--*/
{ ULONG SourceStart; ULONG TargetStart; BYTE Int13Unit; BYTE SectorsPerTrack; USHORT Heads; USHORT Cylinders; ULONG ExtendedCount; UINT DiskId; ULONG LastSector; FPFAT32_BOOT_SECTOR pFat32BootSect; FPPARTITION_IMAGE pFat32ImgHdr;
TellUserToWait();
GetDiskInfoByHandle( DiskHandle, &Int13Unit, &SectorsPerTrack, &Heads, &Cylinders, &ExtendedCount, &DiskId );
SourceStart = MasterDiskInfo.ImageStartSector[MasterDiskInfo.SelectionOrdinal]; TargetStart = SectorsPerTrack;
_Log("Starting restore: SourceStart = 0x%lx, TargetStart = 0x%lx\n",SourceStart,TargetStart);
//
// Read the partition image information structure off the disk
// to determine how large the image is. Cache it away somewhere safe.
//
if(MasterDiskInfo.State >= MDS_CACHED_IMAGE_HEADER) { _Log("Have cached partition image header, fetching from disk\n"); if(!ReadDisk(DiskHandle,2,1,(FPBYTE)IoBuffer+512)) { FatalError(textReadFailedAtSector,1,2L); }
} else {
//
// Ok, figure out where we can start laying down the partition.
//
_Log("TargetStart is %d, adjusting...\n",TargetStart); AdjustTargetStart( DiskHandle, SectorsPerTrack, &TargetStart, (BYTE*)IoBuffer+4096); _Log("New TargetStart is %d.\n",TargetStart);
//
// pull the first two sectors of the image in
//
if(!ReadDisk(DiskHandle,SourceStart,2,(FPBYTE)IoBuffer+512)) { FatalError(textReadFailedAtSector,2,SourceStart); } //
// the first will be the image header, the second could be a fat32 boot sector
//
pFat32BootSect = (FPFAT32_BOOT_SECTOR)((BYTE*)IoBuffer+1024); //
// We need to adjust the target start to compensate for a preserved
// eisa/hiber partition
//
if( IsFat32(pFat32BootSect) ) { //
// if it is a fat32 boot sector, then we store away some useful things we will
// use when we call MungeParametersForFat32Extend.
//
pFat32ImgHdr = (FPPARTITION_IMAGE)((BYTE*)IoBuffer+512); pFat32ImgHdr->Fat32ReservedSectors = pFat32BootSect->PackedBpb.ReservedSectors;
#if 0
//
// this is not necessarily 0x20
//
if(pFat32ImgHdr->Fat32ReservedSectors != 0x20) { FatalError(textReadFailedAtSector,2,SourceStart); } #endif
//
// since this is a Fat32 image, we determine how big we can expand it,
// where we can start the expansion, and how big the new FATs need to be.
//
// We use IoBuffer+4096 as a convenient temporary work bufer.
//
// This will fill in the Fat32 fields of the partition image (pFat32ImageHdr)
// header which we will store away safely in the next step.
//
MungeParametersForFat32Extend(DiskHandle, Cylinders, SectorsPerTrack, SourceStart, &TargetStart, &MasterDiskInfo, (FPPARTITION_IMAGE)pFat32ImgHdr, (BYTE*)IoBuffer+4096);
}
//
// Save it.
//
if(!CmdLineArgs.Test) { if(!WriteDisk(DiskHandle,2,1,(FPBYTE)IoBuffer+512)) { FatalError(textWriteFailedAtSector,1,2L); } } _Log("Successfully cached partition image header\n");
//
// Clobbers first sector of IoBuffer
//
if(!CmdLineArgs.Test) { UpdateMasterDiskState(DiskHandle,MDS_CACHED_IMAGE_HEADER); _Log("Master disk state updated to indicate cached partition image header\n"); } } SourceStart++; memmove(&PartitionImage,(FPBYTE)IoBuffer+512,sizeof(PARTITION_IMAGE));
_Log("Image header for image to be restored --\n"); _Log(" Signature: 0x%lx\n",PartitionImage.Signature); _Log(" Size: %u\n",PartitionImage.Size); _Log(" NonClusterSectors: 0x%lx\n",PartitionImage.NonClusterSectors); _Log(" ClusterCount: 0x%lx\n",PartitionImage.ClusterCount); _Log(" TotalSectorCount: 0x%lx\n",PartitionImage.TotalSectorCount); _Log(" LastUsedCluster: 0x%lx\n",PartitionImage.LastUsedCluster); _Log(" UsedClusterCount: 0x%lx\n",PartitionImage.UsedClusterCount); _Log(" SectorsPerCluster: %u\n",PartitionImage.SectorsPerCluster); _Log(" SystemId: %u\n",PartitionImage.SystemId); _Log("\n");
if(CmdLineArgs.Test) { // validate the disk image first.
TestImage(DiskHandle,SourceStart-1); TellUserToWait(); }
StartGauge();
//
// Fix up things so that no one can get back the data for the OSes
// they didn't install.
//
RemoveNonSelectedOsData(DiskHandle);
XmsInit();
//
// Relocate the cluster bitmap if necessary
//
RelocateClusterBitmap(DiskHandle,SourceStart);
//
// Relocate the boot partition if necessary.
//
RelocateBootPartition(DiskHandle,Cylinders,ExtendedCount);
//
// Transfer the partition data from the image to the start of
// the hard drive.
//
ExpandImage(DiskHandle,SectorsPerTrack,SourceStart,TargetStart);
XmsTerminate();
TellUserToWait();
//
// Next, fix up the BPB's geometry-related fields.
//
FixUpBpb(DiskHandle,SectorsPerTrack,Heads,TargetStart);
//
// The next step is to create the partition table entry that describes
// the partition we are restoring and remove the one for the bootable
// partition.
//
CreatePartitionTableEntry( DiskHandle, Cylinders, ExtendedCount, TargetStart, &LastSector, FALSE );
//
// Now we're done. As a single final step, we recreate the
// mirror boot sector for NTFS. Note that there is a window for failure
// in this operation, but there's no good way around this. If we write
// this sector before now we risk wiping out the bootstrap program.
//
if(PartitionImage.SystemId == 7) { if(ReadDisk(DiskHandle,TargetStart,1,IoBuffer)) { if(!CmdLineArgs.Test) { if(!WriteDisk(DiskHandle,LastSector,1,IoBuffer)) { FatalError(textWriteFailedAtSector,1,LastSector); } } } else { FatalError(textReadFailedAtSector,1,TargetStart); } } }
VOID RemoveNonSelectedOsData( IN HDISK DiskHandle ) { UINT i; ULONG SectorCount; ULONG OriginalCount; ULONG CurrentSector; PPARTITION_IMAGE p;
//
// See if we've already done this step.
//
if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_REMOVED_OTHERS)) { _Log("Already removed non-selected OS data\n"); GaugeDelta(ZAP_MAX * (MasterDiskInfo.ImageCount-1)); return; }
//
// Scribble over the first 1 MB or so of each image. This takes out
// some significant file system data structures and some data.
// We also take out the partition image header itself, but we do that
// last so if we restart we'll be able to complete operating on the
// image we were working on.
//
p = IoBuffer; for(i=0; i<MasterDiskInfo.ImageCount; i++) {
if(i == MasterDiskInfo.SelectionOrdinal) { continue; }
CurrentSector = MasterDiskInfo.ImageStartSector[i]; if(!ReadDisk(DiskHandle,CurrentSector++,1,IoBuffer)) { FatalError(textReadFailedAtSector,1,CurrentSector-1); }
//
// If the sector is not a valid partition image header,
// then we assume we've already taken it out in a previous pass
// and we don't worry about it.
//
if(p->Signature == PARTITION_IMAGE_SIGNATURE) {
_Log("Removing non-selected OS data for image %u\n",i);
SectorCount = p->NonClusterSectors + (p->UsedClusterCount * p->SectorsPerCluster); if(SectorCount > ZAP_MAX) { SectorCount = ZAP_MAX; } OriginalCount = SectorCount;
memset(IoBuffer,0,63*512); while(SectorCount >= 63) { if(!CmdLineArgs.Test) { if(!WriteDisk(DiskHandle,CurrentSector,63,IoBuffer)) { FatalError(textWriteFailedAtSector,63,CurrentSector); } } CurrentSector += 63; SectorCount -= 63; GaugeDelta(63); } if(SectorCount) { if(!CmdLineArgs.Test) { if(!WriteDisk(DiskHandle,CurrentSector,(BYTE)SectorCount,IoBuffer)) { FatalError(textWriteFailedAtSector,(unsigned)SectorCount,CurrentSector); } } GaugeDelta(SectorCount); }
//
// Now take out the image header.
//
if(!CmdLineArgs.Test) { if(!WriteDisk(DiskHandle,MasterDiskInfo.ImageStartSector[i],1,IoBuffer)) { FatalError(textWriteFailedAtSector,1,MasterDiskInfo.ImageStartSector[i]); } }
//
// We allowed for ZAP_MAX sectors in the gauge but there might
// have been less than that in the image (strange case, but possible).
//
if(OriginalCount < (ULONG)ZAP_MAX) { GaugeDelta((ULONG)ZAP_MAX - OriginalCount); } } else { _Log("Non-selected OS data for image %u previously removed\n",i); GaugeDelta(ZAP_MAX); } }
//
// Update state to indicate that we've done this step.
//
if(!CmdLineArgs.Test) { _Log("Updating master disk state to indicate non-selected os data removed...\n"); UpdateMasterDiskState(DiskHandle,MDS_REMOVED_OTHERS); _Log("Master disk state updated to indicate non-selected os data removed\n"); } }
VOID RelocateClusterBitmap( IN HDISK DiskHandle, IN ULONG ImageStart ) { ULONG BitmapSize; ULONG Read; ULONG Target; BOOL Xms;
//
// Figure out how large the cluster bitmap is in sectors.
//
BitmapSize = (PartitionImage.LastUsedCluster/CLUSTER_BITS_PER_SECTOR) + 1; _Log("Cluster bitmap is 0x%lx sectors\n",BitmapSize);
//
// If we've already done this step, nothing to do.
//
if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_RELOCATED_BITMAP)) { _Log("Already relocated cluster bitmap\n"); GaugeDelta(2*BitmapSize); return; }
ImageStart += PartitionImage.NonClusterSectors + (PartitionImage.SectorsPerCluster * PartitionImage.UsedClusterCount);
if(PartitionImage.Flags & PARTIMAGE_RELOCATE_BITMAP) {
//
// Figure out where the bitmap will be relocated to.
//
Target = PartitionImage.BitmapRelocationStart;
MasterDiskInfo.ClusterBitmapStart = CmdLineArgs.Test ? ImageStart : Target;
_Log("Cluster bitmap to be relocated from sector 0x%lx to sector 0x%lx\n",ImageStart,Target);
//
// Note that there's no overlap problem so we just flat out
// transfer the bitmap from beginning to end.
//
while(BitmapSize) {
XmsIoDiskRead(DiskHandle,ImageStart,BitmapSize,&Read,&Xms);
XmsIoDiskWrite(DiskHandle,Target,0,Read,Xms);
BitmapSize -= Read; ImageStart += Read; Target += Read; } } else { _Log("No need to relocate cluster bitmap\n"); MasterDiskInfo.ClusterBitmapStart = ImageStart; }
//
// Note that we update state to indicate that this is done even if we
// don't actually relocate the cluster bitmap, for completeness and
// tracking of what's going on.
//
if(!CmdLineArgs.Test) { _Log("Updating master disk state to indicate cluster bitmap relocated...\n"); UpdateMasterDiskState(DiskHandle,MDS_RELOCATED_BITMAP); _Log("Master disk state updated to indicate cluster bitmap relocated\n"); } }
VOID RelocateBootPartition( IN HDISK DiskHandle, IN USHORT Cylinders, IN ULONG ExtendedCount ) { ULONG Read; ULONG Target; ULONG ImageStart; ULONG Count; BOOL Xms;
if(PartitionImage.Flags & PARTIMAGE_RELOCATE_BOOT) { //
// If we've already done this step, nothing to do.
//
if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_RELOCATED_BOOT)) {
_Log("Already relocated boot partition\n"); GaugeDelta(2*MasterDiskInfo.StartupPartitionSectorCount);
} else {
//
// Figure out where the boot partition will be relocated to.
//
Target = PartitionImage.BootRelocationStart; ImageStart = MasterDiskInfo.StartupPartitionStartSector; Count = MasterDiskInfo.StartupPartitionSectorCount;
if(!CmdLineArgs.Test) { MasterDiskInfo.StartupPartitionStartSector = Target; }
_Log( "Cluster bitmap to be relocated from sector 0x%lx to sector 0x%lx\n", ImageStart, Target );
//
// Note that there's no overlap problem so we just flat out
// transfer the boot partition from end to end.
//
while(Count) {
XmsIoDiskRead(DiskHandle,ImageStart,Count,&Read,&Xms);
XmsIoDiskWrite(DiskHandle,Target,0,Read,Xms);
Count -= Read; ImageStart += Read; Target += Read; }
if(!CmdLineArgs.Test) { _Log("Updating master disk state to indicate boot part relocated...\n"); UpdateMasterDiskState(DiskHandle,MDS_RELOCATED_BOOT); _Log("Master disk state updated to indicate boot part relocated\n"); } }
//
// Ok, it's been transferred. Fix up the mbr to point at it.
// Note that CreatePartitionTableEntry updates master disk state but is protected by
// checking aginst CmdLineArgs.Test.
//
if(CmdLineArgs.Test || (MasterDiskInfo.State < MDS_RELOCATED_BOOT_MBR)) {
CreatePartitionTableEntry( DiskHandle, Cylinders, ExtendedCount, MasterDiskInfo.StartupPartitionStartSector, &Target, TRUE ); }
} else { _Log("No need to relocate boot partition\n"); } }
VOID FixUpBpb( IN HDISK DiskHandle, IN BYTE SectorsPerTrack, IN USHORT Heads, IN ULONG StartSector ) { USHORT BackupBootSectorOfs;
//
// See if we've already done this step.
//
if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_UPDATED_BPB)) { _Log("Already fixed up BPB\n"); return; }
if(!ReadDisk(DiskHandle,StartSector,1,IoBuffer)) { FatalError(textReadFailedAtSector,1,StartSector); }
if(PartitionImage.Fat32ReservedSectors) { //
// this is a FAT32 partition, we munge some extra stuff in the BPB
// when we do the partition expansion
//
FPFAT32_BOOT_SECTOR pBootSect = IoBuffer; ULONG FatSectorCount;
pBootSect->PackedBpb.LargeSectors = PartitionImage.Fat32AdjustedSectorCount;
FatSectorCount = PartitionImage.Fat32AdjustedFatTableEntryCount / (512/4); FatSectorCount = (PartitionImage.Fat32AdjustedFatTableEntryCount % (512/4)) ? FatSectorCount++ : FatSectorCount;
pBootSect->PackedBpb.LargeSectorsPerFat = FatSectorCount; BackupBootSectorOfs = pBootSect->PackedBpb.BackupBootSector;
}
//
// Slam the relevent fields.
//
*(FPUSHORT)&((FPBYTE)IoBuffer)[24] = SectorsPerTrack; *(FPUSHORT)&((FPBYTE)IoBuffer)[26] = Heads; *(FPULONG)&((FPBYTE)IoBuffer)[28] = StartSector; //
// Want to do this but for fat32 it's in a different place
// so it's dangerous
//
//*(FPBYTE)&((FPBYTE)IoBuffer)[36] = Int13Unit;
if(!CmdLineArgs.Test) { if(!WriteDisk(DiskHandle,StartSector,1,IoBuffer)) { FatalError(textWriteFailedAtSector,1,StartSector); } if( PartitionImage.Fat32ReservedSectors ) { //
// Fat32 has a backup boot sector
//
if(!WriteDisk(DiskHandle,StartSector+BackupBootSectorOfs,1,IoBuffer)) { FatalError(textWriteFailedAtSector,1,StartSector+BackupBootSectorOfs); } _Log("Successfully fixed up FAT32 mirror BPB\n"); } }
_Log("Successfully fixed up BPB\n");
if(PartitionImage.Fat32ReservedSectors) { //
// FAT32 case.
//
ULONG NewFreeClusterCount; ULONG OldFreeClusterCount; USHORT FsInfoSectorOfs; FPFSINFO_SECTOR pFsInfoSector;
//
// need to fixup the FsInfoSector to reflect the new free space count.
//
OldFreeClusterCount = PartitionImage.ClusterCount - PartitionImage.UsedClusterCount; NewFreeClusterCount = PartitionImage.Fat32AdjustedFatTableEntryCount - PartitionImage.UsedClusterCount;
FsInfoSectorOfs = ((FPFAT32_BOOT_SECTOR)IoBuffer)->PackedBpb.FsInfoSector;
//
// ok, get FSINFO in.
//
if(!ReadDisk(DiskHandle,StartSector+FsInfoSectorOfs,1,IoBuffer)) { FatalError(textReadFailedAtSector,1,StartSector+FsInfoSectorOfs); }
//
// now verify it is, in fact, an FSINFO sector.
//
pFsInfoSector = (FPFSINFO_SECTOR)IoBuffer;
if(pFsInfoSector->FsInfoSignature != FSINFO_SIGNATURE || pFsInfoSector->SectorBeginSignature != FSINFO_SECTOR_BEGIN_SIGNATURE || pFsInfoSector->SectorEndSignature != FSINFO_SECTOR_END_SIGNATURE ) { FatalError(textReadFailedAtSector,1,StartSector+FsInfoSectorOfs); }
//
// validate our old free cluster count
//
if( OldFreeClusterCount != pFsInfoSector->FreeClusterCount ) { FatalError(textReadFailedAtSector,1,StartSector+FsInfoSectorOfs); }
//
// now drop in our new freespace count.
//
pFsInfoSector->FreeClusterCount = NewFreeClusterCount;
//
// Write FSINFO sect back out. Twice. (the two copies are identical.)
//
if(!CmdLineArgs.Test) { if(!WriteDisk(DiskHandle,StartSector+FsInfoSectorOfs,1,IoBuffer)) { FatalError(textWriteFailedAtSector,1,StartSector+FsInfoSectorOfs); }
if(!WriteDisk(DiskHandle,StartSector+BackupBootSectorOfs+FsInfoSectorOfs,1,IoBuffer)) { FatalError(textWriteFailedAtSector,1,StartSector+BackupBootSectorOfs+FsInfoSectorOfs); } }
_Log("Successfully fixed up FsInfoSector(s)\n"); }
if(!CmdLineArgs.Test) { _Log("Updating master disk state to indicate BPB fixed up...\n"); UpdateMasterDiskState(DiskHandle,MDS_UPDATED_BPB); _Log("Master disk state updated to indicate BPB fixed up\n"); } }
VOID CreatePartitionTableEntry( IN HDISK DiskHandle, IN USHORT Cylinders, IN ULONG DiskSectorCount, IN ULONG StartSector, OUT ULONG *LastSector, IN BOOL Relocating ) { unsigned i; USHORT SectorsPerCylinder; USHORT r; ULONG EndSector; BOOL Overflow; ULONG C; BYTE H; BYTE S;
struct { BYTE Active; BYTE StartH; BYTE StartS; BYTE StartC; BYTE SysId; BYTE EndH; BYTE EndS; BYTE EndC; ULONG Start; ULONG Count; } *PartTabEnt,*TheEntry;
if(!DiskSectorCount) { DiskSectorCount = (ULONG)MasterDiskInfo.OriginalSectorsPerTrack * (ULONG)MasterDiskInfo.OriginalHeads * (ULONG)Cylinders; } SectorsPerCylinder = MasterDiskInfo.OriginalHeads * MasterDiskInfo.OriginalSectorsPerTrack;
//
// Read the MBR
//
if(!ReadDisk(DiskHandle,0,1,IoBuffer)) { FatalError(textReadFailedAtSector,1,0L); }
//
// Traverse the MBR, trying to find the MPK boot partition.
// Also make sure all entries are inactive.
//
TheEntry = NULL; for(i=0; i<4; i++) { PartTabEnt = (FPVOID)((FPBYTE)IoBuffer + 0x1be + (i*16));
if(PartTabEnt->SysId && (PartTabEnt->Start == MasterDiskInfo.StartupPartitionStartSector) && !TheEntry) { TheEntry = PartTabEnt; }
PartTabEnt->Active = 0; }
if(!TheEntry) { //
// Couldn't find it, something is seriously corrupt.
//
FatalError(textCantFindMPKBoot); }
if(Relocating) { EndSector = StartSector + MasterDiskInfo.StartupPartitionSectorCount; } else { if( PartitionImage.Fat32ReservedSectors ) { //
// FAT32 resize case
//
EndSector = PartitionImage.Fat32AdjustedSectorCount + StartSector; } else { EndSector = PartitionImage.TotalSectorCount + StartSector; } //
// Refigure the end sector so it's aligned to a cylinder boundary.
//
if(r = (USHORT)(EndSector % SectorsPerCylinder)) { EndSector += SectorsPerCylinder - r; } //
// In some cases NT reports the disk is 1 or 2 cylinders
// larger than int13 reports. Thus we may have a volume that
// spans beyond the end of the disk as reported by int13.
// If we cap the end of the partition to the size reported
// by int13 in this case, we will end up with a partition
// whose size in the partition table is smaller than the
// size recorded in the BPB. NTFS is particular will then
// refuse to mount the drive and you get inaccassible boot device.
// BIOSes will typically allow I/O to these "extra" cylinders
// even though they're not reported via int13 function 8, so this
// shouldn't be a problem.
//
//if(EndSector > DiskSectorCount) {
// EndSector = DiskSectorCount;
//}
}
TheEntry->Active = 0x80; TheEntry->Start = StartSector; TheEntry->Count = EndSector - StartSector;
//
// Calculate start CHS values.
//
C = StartSector / SectorsPerCylinder; if(C >= (ULONG)Cylinders) { C = Cylinders - 1; H = (BYTE)(MasterDiskInfo.OriginalHeads - 1); S = (BYTE)(MasterDiskInfo.OriginalSectorsPerTrack - 1); } else { H = (BYTE)((StartSector % SectorsPerCylinder) / MasterDiskInfo.OriginalSectorsPerTrack); S = (BYTE)((StartSector % SectorsPerCylinder) % MasterDiskInfo.OriginalSectorsPerTrack); }
TheEntry->StartC = (BYTE)C; TheEntry->StartH = H; TheEntry->StartS = (BYTE)((S + 1) | (((USHORT)C & 0x300) >> 2));
//
// Similarly for the end.
//
EndSector--; *LastSector = EndSector; C = EndSector / SectorsPerCylinder; if(C >= (ULONG)Cylinders) { C = Cylinders - 1; H = (BYTE)(MasterDiskInfo.OriginalHeads - 1); S = (BYTE)(MasterDiskInfo.OriginalSectorsPerTrack - 1); Overflow = TRUE; } else { H = (BYTE)((EndSector % SectorsPerCylinder) / MasterDiskInfo.OriginalSectorsPerTrack); S = (BYTE)((EndSector % SectorsPerCylinder) % MasterDiskInfo.OriginalSectorsPerTrack); Overflow = FALSE; }
TheEntry->EndC = (BYTE)C; TheEntry->EndH = H; TheEntry->EndS = (BYTE)((S + 1) | (((USHORT)C & 0x300) >> 2));
if(!Relocating) { TheEntry->SysId = PartitionImage.SystemId; } if(Overflow) { switch(TheEntry->SysId) { case 1: case 4: case 6: //
// Regular FAT12/FAT12/BIGFAT --> XINT13 FAT
//
TheEntry->SysId = 0xe; break;
case 0xb: //
// FAT32 --> XINT13 FAT32
//
TheEntry->SysId = 0xc; break; } } else { switch(TheEntry->SysId) { case 0xc: //
// XINT13 FAT32 --> FAT32
//
TheEntry->SysId = 0xb; break;
case 0xe: //
// XINT13 FAT --> regular FAT
//
if(Relocating) { if(MasterDiskInfo.StartupPartitionSectorCount >= 65536L) { TheEntry->SysId = 6; } else { if(MasterDiskInfo.StartupPartitionSectorCount >= 32680L) { TheEntry->SysId = 4; } else { TheEntry->SysId = 1; } } } else { if(PartitionImage.TotalSectorCount >= 65536L) { TheEntry->SysId = 6; } else { if(PartitionImage.TotalSectorCount >= 32680L) { TheEntry->SysId = 4; } else { TheEntry->SysId = 1; } } } break; } }
//
// Write the MBR.
//
// Note that after the MBR has been updated, the system will no longer
// boot into this program. Thus the master disk state is now irrelevent.
// But just for completeness, we track that we completed this operation.
//
if(!CmdLineArgs.Test) { if(!WriteDisk(DiskHandle,0,1,IoBuffer)) { FatalError(textWriteFailedAtSector,1,0L); } }
if(!CmdLineArgs.Test) { UpdateMasterDiskState(DiskHandle,Relocating ? MDS_RELOCATED_BOOT_MBR : MDS_UPDATED_MBR); } }
VOID TellUserToWait( VOID ) { FPCHAR p,q; char c; UINT line; INT maxlen;
DispClearClientArea(NULL);
//
// This could be more than one line. We want the message centered
// and left-aligned. Determine the longest line length and center
// the entire message based on that length.
//
maxlen = 0; p = textPleaseWaitRestoring; do { //
// Locate the next newline or terminator
//
for(q=p; (*q != '\n') && *q; q++);
//
// See if this line is maximum length seen so far.
//
if((q-p) > maxlen) { maxlen = q-p; }
p = q+1;
} while(*q);
//
// Second pass actually prints it out.
//
p = textPleaseWaitRestoring; line = 1; do { for(q=p; (*q != '\n') && *q; q++);
//
// Nul-terminate the line in preparation for printing it out.
//
c = *q; *q = 0;
DispPositionCursor((BYTE)((80-maxlen)/2),(BYTE)(TEXT_TOP_LINE+line)); DispWriteString(p); line++;
*q = c; p = q+1;
} while(*q); }
VOID StartGauge( VOID ) { ULONG SectorCount;
//
// Figure out how many sectors we will transfer in total.
// This includes
//
// a) relocating the cluster bitmap
// b) relocating the boot partition
// c) transferring the actual data
// d) zapping unselected OS images
//
SectorCount = 0;
if(PartitionImage.Flags & PARTIMAGE_RELOCATE_BITMAP) { SectorCount += (PartitionImage.LastUsedCluster/CLUSTER_BITS_PER_SECTOR) + 1; }
if(PartitionImage.Flags & PARTIMAGE_RELOCATE_BOOT) { SectorCount += MasterDiskInfo.StartupPartitionSectorCount; }
SectorCount += PartitionImage.NonClusterSectors;
SectorCount += PartitionImage.SectorsPerCluster * PartitionImage.UsedClusterCount;
SectorCount *= 2;
SectorCount += ZAP_MAX * (MasterDiskInfo.ImageCount-1);
GaugeInit(SectorCount); }
BOOL TestImage( IN HDISK DiskHandle, IN ULONG StartSector ) { FPVOID Buffer,OriginalBuffer; ULONG CurrentSector; ULONG ImageCRC; ULONG CalcCRC; ULONG BytesCRC;
ULONG SectorsRemaining; ULONG TotalSectors; ULONG BitmapSize; BYTE Count;
DispClearClientArea(NULL); DispPositionCursor(TEXT_LEFT_MARGIN,TEXT_TOP_LINE);
DispWriteString(textValidatingImage); _Log("Validating image...\n"); DispWriteString("\n\n"); // need to allocate aligned buffer
if(!AllocTrackBuffer(63,&Buffer,&OriginalBuffer)) { FatalError(textOOM); return FALSE; }
CalcCRC = CRC32_INITIAL_VALUE; BytesCRC = 0;
// read inital sector to get info
CurrentSector = StartSector; if( ReadDisk( DiskHandle, CurrentSector, 1, Buffer ) ) { ImageCRC = ((PPARTITION_IMAGE)Buffer)->CRC;
BitmapSize = ((PPARTITION_IMAGE)Buffer)->LastUsedCluster;
BitmapSize = (BitmapSize % (8*512)) ? BitmapSize/(8*512)+1 : BitmapSize/(8*512); SectorsRemaining = ((PPARTITION_IMAGE)Buffer)->NonClusterSectors // fs structs
+ ((PPARTITION_IMAGE)Buffer)->SectorsPerCluster * ((PPARTITION_IMAGE)Buffer)->UsedClusterCount // data area
+ BitmapSize; // image cluster bitmap
((PPARTITION_IMAGE)Buffer)->CRC = 0; ((PPARTITION_IMAGE)Buffer)->BitmapRelocationStart = 0; ((PPARTITION_IMAGE)Buffer)->BootRelocationStart = 0; ((PPARTITION_IMAGE)Buffer)->Flags = 0;
TotalSectors = SectorsRemaining; } else { FatalError(textReadFailedAtSector,1,CurrentSector); return FALSE; }
CurrentSector++; // update the computed CRC
CalcCRC = CRC32Compute( Buffer, 512, CalcCRC); BytesCRC += 512;
GaugeInit(SectorsRemaining);
// loop reading the entire file, updating the CRC
while (SectorsRemaining) { Count = (BYTE) ((SectorsRemaining > 63L) ? 63L : SectorsRemaining);
if( ReadDisk( DiskHandle, CurrentSector, Count , Buffer ) ) { CalcCRC = CRC32Compute( Buffer, Count*512, CalcCRC); BytesCRC += Count*512; } else { FatalError(textReadFailedAtSector,Count,CurrentSector); return FALSE; } SectorsRemaining -= Count; CurrentSector += Count;
// print progress
GaugeDelta(Count); } // compare with stored CRC
DispClearClientArea(NULL); DispPositionCursor(TEXT_LEFT_MARGIN,TEXT_TOP_LINE); _Log("Image file checksum = 0x%08lx\n",CalcCRC); if( CalcCRC != ImageCRC ) { FatalError(textChecksumFail); _Log("** WARNING ** checksum does not match original checksum 0x%08lx\n",ImageCRC); return FALSE; } else { DispWriteString(textChecksumOk); } _Log("Image checksum ok.\n"); free(OriginalBuffer); return TRUE; }
BOOL MungeParametersForFat32Extend( IN HDISK DiskHandle, IN USHORT Cylinders, IN BYTE SectorsPerTrack, IN ULONG SourceStart, IN ULONG *TargetStart, IN FPMASTER_DISK pMasterDisk, IN FPPARTITION_IMAGE pPartitionImage, IN VOID *TemporaryBuffer ) { ULONG SectorsPerCylinder; USHORT ReservedSectorCount; ULONG NewSectorCount; ULONG NewFatSize; ULONG ClusterSize;
//
// check for FAT32
//
if( pPartitionImage->SystemId == 0x0b || pPartitionImage->SystemId == 0x0c ) {
SectorsPerCylinder = pMasterDisk->OriginalHeads * pMasterDisk->OriginalSectorsPerTrack;
//
// get the reserved sector count and the cluster size from the header
//
ReservedSectorCount = pPartitionImage->Fat32ReservedSectors; ClusterSize = pPartitionImage->SectorsPerCluster;
//
// Read the boot sector of the image
//
if(!ReadDisk(DiskHandle,SourceStart+1,1,TemporaryBuffer)) { FatalError(textReadFailedAtSector,1,0L); }
//
// Need to save away the original FAT32 fat size.
//
if( IsFat32( TemporaryBuffer ) ) { pPartitionImage->Fat32OriginalFatTableSectCount = ((FPFAT32_BOOT_SECTOR)TemporaryBuffer)->PackedBpb.LargeSectorsPerFat; } else { //
// If we're here, and this isn't FAT32, we're in trouble.
//
FatalError(textCantFindMasterDisk); }
//
// calculate the max size of the new partition
// = (total cylinder count - the new start) * (sectors/cyl)
//
// we assume the new partition will extend to the end of the disk.
//
NewSectorCount = Cylinders * SectorsPerCylinder - *TargetStart;
//
// given this number of sectors, calculate how many clusters we can make
// and how many FAT entries we need to track them
//
NewFatSize = ComputeClusters( ClusterSize*512, // # of bytes in a cluster
NewSectorCount, // # of sectors in partition
512, // sector size in bytes
ReservedSectorCount, // reserved sector count
2 // # of Fats
); if( NewFatSize < MAX_FAT32_ENTRIES ) { //
// if this will fit in a 16MB-64K FAT, then leave it alone.
//
} else { //
// otherwise we clip the partition size to the max allowed.
//
NewFatSize = MAX_FAT32_ENTRIES; NewSectorCount = ReservedSectorCount + MAX_FAT32_ENTRIES/256 + MAX_FAT32_ENTRIES * ClusterSize; }
pPartitionImage->Fat32AdjustedFatTableEntryCount = NewFatSize; pPartitionImage->Fat32AdjustedSectorCount = NewSectorCount; }
return TRUE; } VOID AdjustTargetStart( IN HDISK DiskHandle, IN BYTE SectorsPerTrack, IN ULONG *TargetStart, IN VOID *TemporaryBuffer ) { unsigned i; BOOL foundUnknown; FPPARTITION_TABLE_ENTRY pPartitionTab;
//
// Read the MBR
//
if(!ReadDisk(DiskHandle,0,1,TemporaryBuffer)) { FatalError(textReadFailedAtSector,1,0L); }
//
// Validate that it is a good MBR.
//
if( ((FPMBR)TemporaryBuffer)->AA55Signature != BOOT_RECORD_SIGNATURE ) { FatalError(textReadFailedAtSector,1,0L); _Log(" WARNING: The MBR was invalid!"); }
//
// now inspect the MBR, and check for an unrecognized partition.
//
pPartitionTab = ((FPMBR)TemporaryBuffer)->PartitionTable;
foundUnknown = FALSE; for(i=0; i<4; i++) { if( IsUnknownPartition(pPartitionTab[i].SysId) ) {
//
// we assume the EISA config/hiber partition is at the start of the disk
// adjust the start of the image restore to the cylinder past the end of it
//
foundUnknown = TRUE; } }
_Log(" The master disk claims %ld sectors were reserved for EISA and hiber partitions.\n", MasterDiskInfo.FreeSpaceStart);
if(foundUnknown == FALSE && MasterDiskInfo.FreeSpaceStart ) { //
// eh? How did FreeSpaceStart get set without having a partition there?
//
_Log(" WARNING: The master disk claims disk space was reserved for \n"); _Log(" EISA/hiber partition when one does not appear to exist!\n");
FatalError(textCantOpenMasterDisk);
} if(MasterDiskInfo.FreeSpaceStart) { //
// MasterDiskInfo.FreeSpaceStart will be non-zero if we discovered a non-recognized
// partition when we built the master disk. The target start sector should be adjusted
// to this number.
//
*TargetStart = MasterDiskInfo.FreeSpaceStart; }
//
// otherwise we should just leave the target start sector alone.
//
return; }
//
// modified from \nt\private\utils\ufat\src\rfatsa.cxx
//
ULONG ComputeClusters( IN ULONG ClusterSize, IN ULONG Sectors, IN ULONG SectorSize, IN ULONG ReservedSectors, IN ULONG Fats ) /*++
Routine Description:
This routine computes the number of clusters on a volume given the cluster size, volume size and the fat type.
Arguments:
ClusterSize - Supplies the size of a cluster in number of bytes.
Sectors - Supplies the total number of sectors in the volume.
SectorSize - Supplies the size of a sector in number of bytes.
ReservedSectors - Supplies the number of reserved sectors.
Fats - Supplies the number of copies of fat for this volume.
Return Value:
ULONG - The total number of clusters for the given configuration.
++*/ { ULONG entries_per_sec; // Number of FAT entries per sector.
ULONG fat_entry_size; // Size of each FAT entry in number of BITS.
ULONG sectors_left; // Number of sectors left for consideration.
ULONG sec_per_clus; // Sectors per cluster.
ULONG increment = 1; // Increment step size in number of FAT sectors.
ULONG clusters = 0; // Number of clusters in total.
ULONG temp; // Temporary place-holder for optimizing certain
// computations.
sectors_left = Sectors - ReservedSectors; sec_per_clus = ClusterSize / SectorSize;
//
// The Fat entry size is 32 bits, since we only support FAT32
//
fat_entry_size = 32;
//
// Compute the number of FAT entries a sector can hold.
// NOTE that fat_entry_size is the size in BITS,
// this is the reason for the "* 8" (bits per byte).
//
entries_per_sec = (SectorSize * 8) / fat_entry_size;
//
// Compute a sensible increment step size to begin with.
//
while (Sectors / (increment * entries_per_sec * sec_per_clus) > 1) { increment *= 2; }
//
// We have to handle the first sector of FAT entries
// separately because the first two entries are reserved.
// Kind of yucky, isn't it?
//
temp = Fats + ((entries_per_sec - 2) * sec_per_clus);
if (sectors_left < temp) {
return (sectors_left - Fats) / sec_per_clus;
} else {
sectors_left -= temp; clusters += entries_per_sec - 2;
while (increment && sectors_left) {
temp = (Fats + entries_per_sec * sec_per_clus) * increment;
if (sectors_left < temp) {
//
// If the increment step is only one, try to utilize the remaining sectors
// as much as possible.
//
if (increment == 1) {
//
// Additional clusters may be possible after allocating
// one more sector of fat.
//
if ( sectors_left > Fats) { temp = (sectors_left - Fats) / sec_per_clus; if (temp > 0) { clusters += temp; } }
}
//
// Cut the increment step by half if it is too big.
//
increment /= 2;
} else {
sectors_left -= temp; clusters += increment * entries_per_sec;
}
} return clusters; } FatalError("This line should never be executed.");
return 0; }
BOOL IsUnknownPartition( IN BYTE SysId ) { if( SysId != 0x00 && // not unused
SysId != 0x01 && SysId != 0x04 && SysId != 0x06 && SysId != 0x07 && SysId != 0x0b && SysId != 0x0c && SysId != 0x0e ) { return TRUE; } return FALSE; }
|