windows-nt/Source/XPSP1/NT/base/ntsetup/mpk/enduser/expand.c
2020-09-26 16:20:57 +08:00

862 lines
23 KiB
C

#include "enduser.h"
VOID
TransferNonClusterData(
IN HDISK DiskHandle,
IN OUT ULONG *SourceStart,
IN OUT ULONG *TargetStart
);
VOID
ExpandFromStart(
IN HDISK DiskHandle,
IN ULONG SourceStart,
IN ULONG TargetStart
);
VOID
ExpandFromEnd(
IN HDISK DiskHandle,
IN ULONG SourceStart,
IN ULONG TargetStart
);
VOID
InitializeClusterMapForward(
IN HDISK DiskHandle
);
VOID
InitializeClusterMapReverse(
IN HDISK DiskHandle
);
VOID
GetForwardClusterRun(
IN HDISK DiskHandle,
OUT ULONG *StartCluster,
OUT ULONG *StartOffset,
OUT ULONG *ClusterCount
);
VOID
GetReverseClusterRun(
IN HDISK DiskHandle,
OUT ULONG *StartCluster,
OUT ULONG *StartOffset,
OUT ULONG *ClusterCount
);
VOID
Fat32ExpandOneFat(
IN HDISK DiskHandle,
IN OUT ULONG *SourceStart,
IN OUT ULONG *TargetStart,
IN ULONG Fat32FatSectorCount,
IN ULONG Fat32AdjustedFatSectorCount
);
VOID
ExpandImage(
IN HDISK DiskHandle,
IN BYTE SectorsPerTrack,
IN ULONG SourceStart,
IN ULONG TargetStart
)
{
//
// Transfer non-cluster data to the start of the drive.
//
TransferNonClusterData(DiskHandle,&SourceStart,&TargetStart);
//
// Expand out data from the image moving forward until we either
// run out of image or we would overwrite data in the image we
// haven't used yet.
//
ExpandFromStart(DiskHandle,SourceStart,TargetStart);
//
// Expand out data from the image moving backwards until we
// reach the point at which the forward transfer above stopped.
//
ExpandFromEnd(DiskHandle,SourceStart,TargetStart);
}
VOID
TransferNonClusterData(
IN HDISK DiskHandle,
IN OUT ULONG *SourceStart,
IN OUT ULONG *TargetStart
)
{
ULONG Write;
ULONG Count;
ULONG Offset;
ULONG Fat32FatSectorCount;
ULONG Fat32AdjustedFatSectorCount;
BOOL Xms;
_Log("Transfer non cluster data, source = 0x%lx, target = 0x%lx\n",*SourceStart,*TargetStart);
//
// See if we've already done this step.
//
if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_DID_NONCLUSTER_DATA)) {
_Log("Non cluster data already transferred\n");
*SourceStart += PartitionImage.NonClusterSectors;
*TargetStart += PartitionImage.NonClusterSectors;
GaugeDelta(2*PartitionImage.NonClusterSectors);
return;
}
//
// this wil be zero if not resizing (FAT32)
//
if(PartitionImage.Fat32AdjustedSectorCount) {
_Log("Non cluster data sectors previously processed = 0x%lx\n",MasterDiskInfo.NonClusterSectorsDone);
GaugeDelta(2*MasterDiskInfo.NonClusterSectorsDone);
//
// Fat32 case
//
// BUGBUG We run into big problems if the image is located right at the beginning of the disk.
// This needs to be prevented in makemast.
//
//
// Get the old size of the FAT in sectors.
//
Fat32FatSectorCount = PartitionImage.Fat32OriginalFatTableSectCount;
//
// Calculate the new size of the FAT in sectors.
//
Fat32AdjustedFatSectorCount = PartitionImage.Fat32AdjustedFatTableEntryCount/(512/4);
Fat32AdjustedFatSectorCount = (PartitionImage.Fat32AdjustedFatTableEntryCount%(512/4)) ?
Fat32AdjustedFatSectorCount++: Fat32AdjustedFatSectorCount;
Offset = 0;
//
// all right, restore the reserved sectors at the beginning of the disk
// since the number of reserved sectors for FAT32 is small, just read
// and write them all at once.
//
if( MasterDiskInfo.NonClusterSectorsDone < PartitionImage.Fat32ReservedSectors ) {
//
// if we haven't already done this
//
XmsIoDiskRead(
DiskHandle,
*SourceStart,
PartitionImage.Fat32ReservedSectors,
&Write,
&Xms
);
XmsIoDiskWrite(DiskHandle,*TargetStart,Offset,Write,Xms);
_Log("Restore %lu reserved sectors from 0x%lx\n",Write,*SourceStart);
MasterDiskInfo.NonClusterSectorsDone += Write;
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MasterDiskInfo.State);
}
}
*SourceStart += PartitionImage.Fat32ReservedSectors;
*TargetStart += PartitionImage.Fat32ReservedSectors;
//
// now do the first FAT table
//
_Log("Restore FAT32 tables.\n");
if( MasterDiskInfo.NonClusterSectorsDone <
( PartitionImage.Fat32ReservedSectors + Fat32FatSectorCount )) {
//
// if we haven't already done this
//
_Log("Restore first FAT.\n");
Fat32ExpandOneFat( DiskHandle,
SourceStart,
TargetStart,
Fat32FatSectorCount,
Fat32AdjustedFatSectorCount
);
} else {
_Log("First FAT already restored.\n");
}
//
// now do the second FAT table
//
_Log("Restore second FAT.\n");
Fat32ExpandOneFat( DiskHandle,
SourceStart,
TargetStart,
Fat32FatSectorCount,
Fat32AdjustedFatSectorCount
);
} else {
//
// Other file systems
//
_Log("Non cluster data sectors previously processed = 0x%lx\n",MasterDiskInfo.NonClusterSectorsDone);
GaugeDelta(2*MasterDiskInfo.NonClusterSectorsDone);
*SourceStart += MasterDiskInfo.NonClusterSectorsDone;
*TargetStart += MasterDiskInfo.NonClusterSectorsDone;
while(MasterDiskInfo.NonClusterSectorsDone < PartitionImage.NonClusterSectors) {
XmsIoDiskRead(
DiskHandle,
*SourceStart,
PartitionImage.NonClusterSectors - MasterDiskInfo.NonClusterSectorsDone,
&Write,
&Xms
);
_Log("Read %lu non-cluster sectors from 0x%lx\n",Write,*SourceStart);
Offset = 0;
while(Write) {
//
// Write as large a chunk as possible without overlap.
//
if((*TargetStart + Write) > *SourceStart) {
Count = *SourceStart - *TargetStart;
} else {
Count = Write;
}
XmsIoDiskWrite(DiskHandle,*TargetStart,Offset,Count,Xms);
Write -= Count;
*SourceStart += Count;
Offset += Count;
MasterDiskInfo.NonClusterSectorsDone += Count;
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MasterDiskInfo.State);
}
_Log("Wrote %lu non-cluster sectors to 0x%lx\n",Count,*TargetStart);
*TargetStart += Count;
}
}
}
//
// Update master disk state to indicate that we're done with this step.
//
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MDS_DID_NONCLUSTER_DATA);
}
}
VOID
ExpandFromStart(
IN HDISK DiskHandle,
IN ULONG SourceStart,
IN ULONG TargetStart
)
{
ULONG Start,Offset,Count;
ULONG SourceFirst;
ULONG TargetFirst;
ULONG SoFar;
ULONG u;
BOOL Xms;
ULONG Write;
//
// See if we've already done this step.
//
if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_DID_XFER_FORWARD)) {
_Log("Already did expand in forward direction\n");
GaugeDelta(2*MasterDiskInfo.ForwardXferSectorCount);
return;
}
_Log("\nStarting forward expansion, sectors previously done = 0x%lx\n",MasterDiskInfo.ForwardXferSectorCount);
InitializeClusterMapForward(DiskHandle);
SoFar = 0;
//
// Get a run of clusters and calculate the first and last sector
// of the source and the target. If there are no more clusters left,
// we're done.
//
nextrun:
GetForwardClusterRun(DiskHandle,&Start,&Offset,&Count);
if(!Count) {
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MDS_DID_XFER_FORWARD);
}
return;
}
Start *= PartitionImage.SectorsPerCluster;
Offset *= PartitionImage.SectorsPerCluster;
Count *= PartitionImage.SectorsPerCluster;
_Log("\nSector run: start = 0x%lx, count = 0x%lx, offset = 0x%lx\n",Start,Count,Offset);
//
// See if we're already done this xfer or part of it on a previous pass.
// Note that SoFar cannot ever be greater than
// MasterDiskInfo.ForwardXFerSectorCount because we increment them both
// by the same amount after a transfer. In most cases they will be equal.
//
if((SoFar+Count) <= MasterDiskInfo.ForwardXferSectorCount) {
_Log("Already did this run, skipping\n");
SoFar += Count;
GaugeDelta(2*Count);
goto nextrun;
}
if(u = (MasterDiskInfo.ForwardXferSectorCount - SoFar)) {
//
// We know that Count > MasterDiskInfo.ForwardXFerSectorCount - SoFar,
// which means that if we get here, Count > u >= 1.
//
// Adjust the counts and fall through. Note that after this from now on
// MasterDiskInfo.ForwardXFerSectorCount == SoFar, meaning neither this
// nor the previous if clause will be triggered.
//
_Log("Already partially did this run, adjusting\n");
SoFar += u;
Start += u;
Offset += u;
Count -= u;
GaugeDelta(2*u);
}
SourceFirst = SourceStart + Offset;
TargetFirst = TargetStart + Start;
//
// If writing to the target would hose over data we haven't
// read from the source yet, we're done with the forward expansion.
//
if(SourceFirst < TargetFirst) {
_Log("Target passes source, done with forward expansion\n");
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MDS_DID_XFER_FORWARD);
}
return;
}
//
// If the source and target are the same, nothing to do.
// Otherwise, do our thing.
//
if(SourceFirst == TargetFirst) {
_Log("Source is same as target\n");
SoFar += Count;
MasterDiskInfo.ForwardXferSectorCount += Count;
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MasterDiskInfo.State);
}
GaugeDelta(2*Count);
} else {
while(Count) {
XmsIoDiskRead(DiskHandle,SourceFirst,Count,&Write,&Xms);
_Log("Read %lu sectors from 0x%lx\n",Write,SourceFirst);
Offset = 0;
while(Write) {
//
// Write as large a run as possible without overlap.
//
if((TargetFirst+Write) > SourceFirst) {
u = SourceFirst - TargetFirst;
} else {
u = Write;
}
_Log("Writing %lu sectors to 0x%lx\n",u,TargetFirst);
XmsIoDiskWrite(DiskHandle,TargetFirst,Offset,u,Xms);
//
// Update vars
//
SoFar += u;
SourceFirst += u;
Offset += u;
Write -= u;
Count -= u;
MasterDiskInfo.ForwardXferSectorCount += u;
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MasterDiskInfo.State);
}
_Log("Wrote %lu sectors to 0x%lx\n",u,TargetFirst);
TargetFirst += u;
}
}
}
//
// Process additional clusters.
//
goto nextrun;
}
VOID
ExpandFromEnd(
IN HDISK DiskHandle,
IN ULONG SourceStart,
IN ULONG TargetStart
)
{
ULONG End,Offset,Count;
ULONG SourceEnd;
ULONG TargetEnd;
ULONG SoFar;
ULONG u;
BOOL Xms;
ULONG Write;
//
// See if we've already done this step.
//
if(!CmdLineArgs.Test && (MasterDiskInfo.State >= MDS_DID_XFER_REVERSE)) {
_Log("Already did expand in reverse direction\n");
GaugeDelta(2*MasterDiskInfo.ReverseXferSectorCount);
return;
}
_Log("Starting reverse expansion, sectors previously done = 0x%lx\n",MasterDiskInfo.ReverseXferSectorCount);
InitializeClusterMapReverse(DiskHandle);
SoFar = 0;
//
// Get a run of clusters and calculate the first and last sector
// of the source and the target. If there are no more clusters left,
// we're done.
//
nextrun:
GetReverseClusterRun(DiskHandle,&End,&Offset,&Count);
if(!Count) {
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MDS_DID_XFER_REVERSE);
}
return;
}
End = (End + 1) * PartitionImage.SectorsPerCluster;
Offset = (Offset + 1) * PartitionImage.SectorsPerCluster;
Count *= PartitionImage.SectorsPerCluster;
_Log("\nSector run: end = 0x%lx, count = 0x%lx, offset = 0x%lx\n",End,Count,Offset);
//
// See if we're already done this xfer or part of it on a previous pass.
// Note that SoFar cannot ever be greater than
// MasterDiskInfo.ReverseXFerSectorCount because we increment them both
// by the same amount after a transfer. In most cases they will be equal.
//
if((SoFar+Count) <= MasterDiskInfo.ReverseXferSectorCount) {
_Log("Already did this run, skipping\n");
SoFar += Count;
GaugeDelta(2*Count);
goto nextrun;
}
if(u = (MasterDiskInfo.ReverseXferSectorCount - SoFar)) {
//
// We know that Count > MasterDiskInfo.ReverseXFerSectorCount - SoFar,
// which means that if we get here, Count > u >= 1.
//
// Adjust the counts and fall through. Note that after this from now on
// MasterDiskInfo.ReverseXFerSectorCount == SoFar, meaning neither this
// nor the previous if clause will be triggered.
//
_Log("Already partially did this run, adjusting\n");
SoFar += u;
End -= u;
Offset -= u;
Count -= u;
GaugeDelta(2*u);
}
SourceEnd = SourceStart + Offset;
TargetEnd = TargetStart + End;
//
// If writing to the target would hose over data we haven't
// read from the source yet, we're done.
//
if(TargetEnd < SourceEnd) {
_Log("Target passes source, done with reverse expansion\n");
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MDS_DID_XFER_REVERSE);
}
return;
}
//
// If the source and target are the same, nothing to do.
// (Note: this case should not occur, since we would have
// picked it up on the forward scan. But just in case,
// we handle it anyway.)
// Otherwise, do our thing.
//
if(SourceEnd == TargetEnd) {
_Log("Source is same as target\n");
SoFar += Count;
MasterDiskInfo.ReverseXferSectorCount += Count;
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MasterDiskInfo.State);
}
GaugeDelta(2*Count);
} else {
while(Count) {
XmsIoDiskRead(DiskHandle,SourceEnd-Count,Count,&Write,&Xms);
_Log("Read %lu sectors from 0x%lx\n",Write,SourceEnd-Count);
Offset = Write;
while(Write) {
//
// Write as large a run as possible without overlap.
//
if((TargetEnd-Write) < SourceEnd) {
u = TargetEnd - SourceEnd;
} else {
u = Write;
}
_Log("Writing %lu sectors to 0x%lx\n",u,TargetEnd-u);
XmsIoDiskWrite(DiskHandle,TargetEnd-u,Offset-u,u,Xms);
//
// Update vars
//
SoFar += u;
SourceEnd -= u;
TargetEnd -= u;
Offset -= u;
Write -= u;
Count -= u;
MasterDiskInfo.ReverseXferSectorCount += u;
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MasterDiskInfo.State);
}
_Log("Wrote %lu sectors to 0x%lx\n",u,TargetEnd);
}
}
}
//
// Process additional clusters.
//
goto nextrun;
}
////////////////////////////////////////////////////
ULONG _NextClusterToExamine;
BYTE _ClusterBuffer[512];
ULONG _BufferedClusterMapSector;
ULONG _ClusterBufferBase;
ULONG _ClusterOffset;
BOOL _First;
BYTE BitValue[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
VOID
InitializeClusterMapForward(
IN HDISK DiskHandle
)
{
//
// Read the first sector of the cluster bitmap.
//
if(!ReadDisk(DiskHandle,MasterDiskInfo.ClusterBitmapStart,1,IoBuffer)) {
FatalError(textReadFailedAtSector,1,MasterDiskInfo.ClusterBitmapStart);
}
memmove(_ClusterBuffer,IoBuffer,512);
_BufferedClusterMapSector = MasterDiskInfo.ClusterBitmapStart;
_NextClusterToExamine = 0;
_ClusterBufferBase = 0;
_ClusterOffset = 0;
}
VOID
GetForwardClusterRun(
IN HDISK DiskHandle,
OUT ULONG *StartCluster,
OUT ULONG *StartOffset,
OUT ULONG *ClusterCount
)
{
UINT cluster;
BOOL b;
*ClusterCount = 0;
//
// Locate the next 1 bit in the map.
//
while(_NextClusterToExamine <= PartitionImage.LastUsedCluster) {
//
// Reload the cluster buffer if necessary.
//
if(_NextClusterToExamine && !(_NextClusterToExamine % CLUSTER_BITS_PER_SECTOR)) {
if(!ReadDisk(DiskHandle,++_BufferedClusterMapSector,1,IoBuffer)) {
FatalError(textReadFailedAtSector,1,_BufferedClusterMapSector);
}
memmove(_ClusterBuffer,IoBuffer,512);
_ClusterBufferBase += CLUSTER_BITS_PER_SECTOR;
}
cluster = (UINT)(_NextClusterToExamine - _ClusterBufferBase);
//
// See if this bit is one, which starts a run of used clusters.
// To simplify things, we won't return a run that spans sectors
// in the cluster bitmap.
//
b = FALSE;
while((_ClusterBuffer[cluster/8] & BitValue[cluster%8])
&& (cluster < CLUSTER_BITS_PER_SECTOR)
&& (_NextClusterToExamine <= PartitionImage.LastUsedCluster)) {
if(!b) {
*StartOffset = _ClusterOffset;
*StartCluster = _NextClusterToExamine;
b = TRUE;
}
*ClusterCount += 1;
cluster++;
_NextClusterToExamine++;
_ClusterOffset++;
}
if(b) {
return;
}
_NextClusterToExamine++;
}
}
VOID
InitializeClusterMapReverse(
IN HDISK DiskHandle
)
{
ULONG Sector;
//
// Read the last sector of the cluster bitmap.
//
Sector = MasterDiskInfo.ClusterBitmapStart
+ (PartitionImage.LastUsedCluster/CLUSTER_BITS_PER_SECTOR);
if(!ReadDisk(DiskHandle,Sector,1,IoBuffer)) {
FatalError(textReadFailedAtSector,1,Sector);
}
memmove(_ClusterBuffer,IoBuffer,512);
_BufferedClusterMapSector = Sector;
_NextClusterToExamine = PartitionImage.LastUsedCluster;
_ClusterBufferBase = (PartitionImage.LastUsedCluster / CLUSTER_BITS_PER_SECTOR)
* CLUSTER_BITS_PER_SECTOR;
_ClusterOffset = PartitionImage.UsedClusterCount-1;
_First = TRUE;
}
VOID
GetReverseClusterRun(
IN HDISK DiskHandle,
OUT ULONG *StartCluster,
OUT ULONG *StartOffset,
OUT ULONG *ClusterCount
)
{
UINT cluster;
BOOL b;
*ClusterCount = 0;
//
// Locate the next 1 bit in the map.
//
while(_NextClusterToExamine != (ULONG)(-1)) {
//
// Reload the cluster buffer if necessary.
//
if(((_NextClusterToExamine % CLUSTER_BITS_PER_SECTOR) == (CLUSTER_BITS_PER_SECTOR-1)) && !_First) {
if(!ReadDisk(DiskHandle,--_BufferedClusterMapSector,1,IoBuffer)) {
FatalError(textReadFailedAtSector,1,_BufferedClusterMapSector);
}
memmove(_ClusterBuffer,IoBuffer,512);
_ClusterBufferBase -= CLUSTER_BITS_PER_SECTOR;
}
_First = FALSE;
cluster = (UINT)(_NextClusterToExamine - _ClusterBufferBase);
//
// See if this bit is one, which starts a run of used clusters.
// To simplify things, we won't return a run that spans sectors
// in the cluster bitmap.
//
b = FALSE;
while((_ClusterBuffer[cluster/8] & BitValue[cluster%8])
&& (cluster != (UINT)(-1))
&& (_NextClusterToExamine != (ULONG)(-1))) {
if(!b) {
*StartCluster = _NextClusterToExamine;
*StartOffset = _ClusterOffset;
b = TRUE;
}
*ClusterCount += 1;
cluster--;
_NextClusterToExamine--;
_ClusterOffset--;
}
if(b) {
return;
}
_NextClusterToExamine--;
}
return;
}
VOID
Fat32ExpandOneFat(
IN HDISK DiskHandle,
IN OUT ULONG *SourceStart,
IN OUT ULONG *TargetStart,
IN ULONG Fat32FatSectorCount,
IN ULONG Fat32AdjustedFatSectorCount
)
{
ULONG RemainingSectors;
ULONG Counter;
ULONG Write;
ULONG Offset;
BOOL Xms;
RemainingSectors = Fat32FatSectorCount;
Offset = 0;
//
// now restore the FAT table
//
while( RemainingSectors ) {
XmsIoDiskRead(
DiskHandle,
*SourceStart,
RemainingSectors,
&Write,
&Xms
);
XmsIoDiskWrite(DiskHandle,*TargetStart,Offset,Write,Xms);
RemainingSectors -= Write;
*SourceStart += Write;
*TargetStart += Write;
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MasterDiskInfo.State);
}
MasterDiskInfo.NonClusterSectorsDone += Write; // the final update is delayed until we
// fill the rest of the FAT with zeros.
}
//
// zero out the rest of the FAT table.
//
memset(IoBuffer, 0, 512);
for(Counter=0; Counter<Fat32AdjustedFatSectorCount-Fat32FatSectorCount; Counter++ ) {
if(!CmdLineArgs.Test) {
WriteDisk(DiskHandle,*TargetStart,1,IoBuffer);
}
(*TargetStart)++;
}
//
// putting the final update here insures that we are done with zeroing the FAT out.
//
if(!CmdLineArgs.Test) {
UpdateMasterDiskState(DiskHandle,MasterDiskInfo.State);
}
return;
}