#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