github.com/Microsoft/azure-vhd-utils@v0.0.0-20230613175315-7c30a3748a1b/vhdcore/footer/diskGeometry.go (about)

     1  package footer
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Microsoft/azure-vhd-utils/vhdcore"
     7  )
     8  
     9  // DiskGeometry represents the cylinder, heads and sectors (CHS) per track.
    10  //
    11  type DiskGeometry struct {
    12  	// Offset = 0, Size = 2
    13  	// Stored in big-endian format
    14  	Cylinder uint16
    15  	// Offset = 2, Size = 1
    16  	Heads byte
    17  	// Offset = 3, Size = 1
    18  	Sectors byte
    19  }
    20  
    21  // CreateNewDiskGeometry creates a new DiskGeometry from the given virtual
    22  // size. CHS field values are calculated based on the total data sectors
    23  // present in the disk image.
    24  //
    25  func CreateNewDiskGeometry(virtualSize int64) *DiskGeometry {
    26  	// Total data sectors present in the disk image
    27  	var totalSectors = virtualSize / vhdcore.VhdSectorLength
    28  	// Sectors per track on the disk
    29  	var sectorsPerTrack int64
    30  	// Number of heads present on the disk
    31  	var heads int32
    32  	// Cylinders * heads
    33  	var cylinderTimesHeads int64
    34  
    35  	//                  C   * H  * S
    36  	if totalSectors > 65535*16*255 {
    37  		totalSectors = 65535 * 16 * 255
    38  	}
    39  
    40  	if totalSectors >= 65535*16*63 {
    41  		sectorsPerTrack = 255
    42  		cylinderTimesHeads = totalSectors / sectorsPerTrack
    43  		heads = 16
    44  
    45  		return &DiskGeometry{
    46  			Cylinder: uint16(cylinderTimesHeads / int64(heads)),
    47  			Heads:    byte(heads),
    48  			Sectors:  byte(sectorsPerTrack),
    49  		}
    50  	}
    51  
    52  	sectorsPerTrack = 17
    53  	cylinderTimesHeads = totalSectors / sectorsPerTrack
    54  	heads = int32((cylinderTimesHeads + 1023) / 1024)
    55  
    56  	if heads < 4 {
    57  		heads = 4
    58  	}
    59  
    60  	if cylinderTimesHeads >= int64(heads*1024) || heads > 16 {
    61  		sectorsPerTrack = 31
    62  		heads = 16
    63  		cylinderTimesHeads = totalSectors / sectorsPerTrack
    64  	}
    65  
    66  	if cylinderTimesHeads >= int64(heads*1024) {
    67  		sectorsPerTrack = 63
    68  		heads = 16
    69  		cylinderTimesHeads = totalSectors / sectorsPerTrack
    70  	}
    71  
    72  	return &DiskGeometry{
    73  		Cylinder: uint16(cylinderTimesHeads / int64(heads)),
    74  		Heads:    byte(heads),
    75  		Sectors:  byte(sectorsPerTrack),
    76  	}
    77  }
    78  
    79  // CreateCopy creates a copy of this instance
    80  //
    81  func (d *DiskGeometry) CreateCopy() *DiskGeometry {
    82  	return &DiskGeometry{
    83  		Cylinder: d.Cylinder,
    84  		Heads:    d.Heads,
    85  		Sectors:  d.Sectors,
    86  	}
    87  }
    88  
    89  // Equals returns true if this and other points to the same instance
    90  // or if CHS fields of pointed instances are same
    91  //
    92  func (d *DiskGeometry) Equals(other *DiskGeometry) bool {
    93  	if other == nil {
    94  		return false
    95  	}
    96  
    97  	return other == d || *other == *d
    98  }
    99  
   100  // String returns the string representation of this range, this satisfies stringer interface.
   101  //
   102  func (d *DiskGeometry) String() string {
   103  	return fmt.Sprintf("Cylinder:%d Heads:%d Sectors:%d", d.Cylinder, d.Heads, d.Sectors)
   104  }