├── .gitignore ├── LICENSE.txt ├── README.md ├── go.mod ├── mbr.go └── mbr_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Timofey Koolin, Rekby. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Go Reference](https://pkg.go.dev/badge/github.com/rekby/mbr.svg)](https://pkg.go.dev/github.com/rekby/mbr) 2 | 3 | Documentation: https://pkg.go.dev/github.com/rekby/mbr 4 | 5 | Library for work with MBR (Master boot record) record of disk. 6 | 7 | Main purpose when create library - usage for direct resize partitions as https://github.com/amarao/ptmax 8 | from golang without external dependency. 9 | 10 | GoDoc: https://godoc.org/github.com/rekby/mbr 11 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rekby/mbr 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /mbr.go: -------------------------------------------------------------------------------- 1 | package mbr 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | ) 7 | 8 | var ErrorBadMbrSign = errors.New("MBR: Bad signature") 9 | var ErrorPartitionsIntersection = errors.New("MBR: Partitions have intersections") 10 | var ErrorPartitionLastSectorHigh = errors.New("MBR: Last sector have very high number") 11 | var ErrorPartitionBootFlag = errors.New("MBR: Bad value in boot flag") 12 | var ErrorDiskSizeNotEvenSectors = errors.New("MBR: Disk size is not evenly divisible by sector size") 13 | var ErrorInvalidProtectiveType = errors.New("Invalid value for ProtectiveType") 14 | 15 | type MBR struct { 16 | bytes []byte 17 | } 18 | 19 | type MBRPartition struct { 20 | Num int 21 | bytes []byte 22 | } 23 | 24 | type PartitionType byte 25 | 26 | const ( 27 | PART_EMPTY = PartitionType(0) 28 | PART_LINUX_SWAP_SOLARIS = PartitionType(0x82) 29 | PART_LVM = PartitionType(0x8E) 30 | PART_HYBRID_GPT = PartitionType(0xED) 31 | PART_GPT = PartitionType(0xEE) 32 | ) 33 | 34 | type ProtectiveType int 35 | 36 | const ( 37 | DiskSize = ProtectiveType(1) 38 | MaxSize = ProtectiveType(2) 39 | DefaultProtective = ProtectiveType(0) 40 | ) 41 | 42 | const mbrFirstPartEntryOffset = 446 // bytes 43 | const mbrPartEntrySize = 16 // bytes 44 | const mbrSize = 512 // bytes 45 | const mbrSignOffset = 510 // bytes 46 | 47 | const partitionBootableOffset = 0 // bytes 48 | const partitionTypeOffset = 4 // bytes 49 | const partitionLBAStartOffset = 8 // bytes 50 | const partitionLBALengthOffset = 12 // bytes 51 | 52 | const partitionNumFirst = 1 53 | const partitionNumLast = 4 54 | const partitionBootableValue = 0x80 55 | const partitionNonBootableValue = 0 56 | 57 | /* 58 | Read MBR from disk. 59 | Example: 60 | f, _ := os.Open("/dev/sda") 61 | Mbr, err := mbr.Read(f) 62 | if err != nil ... 63 | f.Close() 64 | */ 65 | func Read(disk io.Reader) (*MBR, error) { 66 | var this *MBR = &MBR{} 67 | this.bytes = make([]byte, mbrSize) 68 | _, err := disk.Read(this.bytes) 69 | if err != nil { 70 | return this, err 71 | } 72 | 73 | return this, this.Check() 74 | } 75 | 76 | func (this *MBR) Check() error { 77 | // Check signature 78 | if this.bytes[mbrSignOffset] != 0x55 || this.bytes[mbrSignOffset+1] != 0xAA { 79 | return ErrorBadMbrSign 80 | } 81 | 82 | // Check partitions 83 | maxLen := uint64(0xFFFFFFFF) 84 | for l := partitionNumFirst; l <= partitionNumLast; l++ { 85 | lp := this.GetPartition(l) 86 | if lp.IsEmpty() { 87 | continue 88 | } 89 | 90 | // Check if partition last sector out of uint32 bounds 91 | last := uint64(lp.GetLBAStart()) + uint64(lp.GetLBALen()) 92 | if last > maxLen { 93 | // Most/All GPT partitioners write a length for the Protective MBR of maxLen 94 | // even though it is strictly out of bounds. Specifically allow for that. 95 | if !(l == partitionNumFirst && last == maxLen+1 && lp.GetType() == PART_GPT) { 96 | return ErrorPartitionLastSectorHigh 97 | } 98 | } 99 | 100 | // Check partition bootable status 101 | if lp.bytes[partitionBootableOffset] != partitionBootableValue && lp.bytes[partitionBootableOffset] != partitionNonBootableValue { 102 | return ErrorPartitionBootFlag 103 | } 104 | 105 | // Check if partitions have intersections 106 | for r := partitionNumFirst; r <= partitionNumLast; r++ { 107 | if l == r { 108 | continue 109 | } 110 | rp := this.GetPartition(r) 111 | if rp.IsEmpty() { 112 | continue 113 | } 114 | 115 | if lp.GetLBAStart() > rp.GetLBAStart() && uint64(lp.GetLBAStart()) < uint64(rp.GetLBAStart())+uint64(rp.GetLBALen()) { 116 | return ErrorPartitionsIntersection 117 | } 118 | } 119 | } 120 | 121 | return nil 122 | } 123 | 124 | func (this *MBR) FixSignature() { 125 | this.bytes[mbrSignOffset] = 0x55 126 | this.bytes[mbrSignOffset+1] = 0xAA 127 | } 128 | 129 | /* 130 | Write MBR to disk 131 | Example: 132 | f, _ := os.OpenFile("/dev/sda", os.O_RDWR | os.O_SYNC, 0600) 133 | err := Mbr.Write(f) 134 | if err != nil ... 135 | f.Close() 136 | */ 137 | func (this MBR) Write(disk io.Writer) error { 138 | _, err := disk.Write(this.bytes) 139 | return err 140 | } 141 | 142 | func (this MBR) GetPartition(num int) *MBRPartition { 143 | if num < partitionNumFirst || num > partitionNumLast { 144 | return nil 145 | } 146 | 147 | var part *MBRPartition = &MBRPartition{Num:num} 148 | partStart := mbrFirstPartEntryOffset + (num-1)*mbrPartEntrySize 149 | part.bytes = this.bytes[partStart : partStart+mbrPartEntrySize] 150 | return part 151 | } 152 | 153 | func (this MBR) GetAllPartitions() []*MBRPartition { 154 | res := make([]*MBRPartition, 4) 155 | for i := 0; i < 4; i++ { 156 | res[i] = this.GetPartition(i + 1) 157 | } 158 | return res 159 | } 160 | 161 | func (this MBR) IsGPT() bool { 162 | for _, part := range this.GetAllPartitions() { 163 | if part.GetType() == PART_GPT || part.GetType() == PART_HYBRID_GPT { 164 | return true 165 | } 166 | } 167 | return false 168 | } 169 | 170 | // MakeProtective - Make this MBR a GPT Protective MBR 171 | // sectorSize is either 512 or 4096. diskSize is the size of entire disk in bytes. 172 | // https://en.wikipedia.org/wiki/GUID_Partition_Table#Protective_MBR_(LBA_0) 173 | // 174 | // ProtectiveType value determines how the size of the partition is set. 175 | // DefaultProtective - implementation default value 176 | // MaxSize - Size of the ProtectiveMBR partition will be set to 0xFFFFFFFF 177 | // While this is strictly outside the UEFI spec, it is the behavior 178 | // of linux and windows partitioners. 179 | // DiskSize - the actual length of the partition size size up to 0xFFFFFFFF - 1 180 | func (this *MBR) MakeProtective(sectorSize int, diskSize uint64, pType ProtectiveType) error { 181 | 182 | if diskSize%uint64(sectorSize) != 0 { 183 | return ErrorDiskSizeNotEvenSectors 184 | } 185 | this.FixSignature() 186 | 187 | ptLBAStart := uint32(1) 188 | ptLBALen := uint32(0xFFFFFFFF) 189 | 190 | if pType == DiskSize { 191 | max := uint64(0xFFFFFFFF) 192 | actual := diskSize/uint64(sectorSize) - uint64(ptLBAStart) 193 | if actual > max { 194 | ptLBALen = uint32(max) 195 | } else { 196 | ptLBALen = uint32(actual) 197 | } 198 | } else if pType != MaxSize && pType != DefaultProtective { 199 | return ErrorInvalidProtectiveType 200 | } 201 | 202 | pt := this.GetPartition(1) 203 | pt.SetType(PART_GPT) 204 | pt.SetLBAStart(ptLBAStart) 205 | pt.SetLBALen(ptLBALen) 206 | pt.bytes[partitionBootableOffset] = partitionNonBootableValue 207 | 208 | // zero the other partitions. 209 | for pnum := 2; pnum <= 4; pnum++ { 210 | pt := this.GetPartition(pnum) 211 | pt.SetType(PART_EMPTY) 212 | pt.SetLBAStart(0) 213 | pt.SetLBALen(0) 214 | pt.bytes[partitionBootableOffset] = partitionNonBootableValue 215 | } 216 | 217 | return nil 218 | } 219 | 220 | /* 221 | Return number of first sector of partition. Numbers starts from 1. 222 | */ 223 | func (this *MBRPartition) GetLBAStart() uint32 { 224 | return readLittleEndianUINT32(this.bytes[partitionLBAStartOffset : partitionLBAStartOffset+4]) 225 | } 226 | 227 | /* 228 | Return count of sectors in partition. 229 | */ 230 | func (this *MBRPartition) GetLBALen() uint32 { 231 | return readLittleEndianUINT32(this.bytes[partitionLBALengthOffset : partitionLBALengthOffset+4]) 232 | } 233 | 234 | /* 235 | Return number of last setor if partition. 236 | 237 | If last sector num more then max uint32 - panic. It mean error in metadata. 238 | */ 239 | func (this *MBRPartition) GetLBALast() uint32 { 240 | last := uint64(this.GetLBAStart()) + uint64(this.GetLBALen()) - 1 241 | 242 | // If last > max uint32 - panic 243 | if last > uint64(0xFFFFFFFF) { 244 | panic(errors.New("Overflow while calc last sector. Max sector number in mbr must be less or equal 0xFFFFFFFF")) 245 | } 246 | return uint32(last) 247 | } 248 | 249 | func (this *MBRPartition) GetType() PartitionType { 250 | return PartitionType(this.bytes[partitionTypeOffset]) 251 | } 252 | func (this *MBRPartition) SetType(t PartitionType) { 253 | this.bytes[partitionTypeOffset] = byte(t) 254 | } 255 | 256 | /* 257 | Return true if partition have empty type 258 | */ 259 | func (this *MBRPartition) IsEmpty() bool { 260 | return this.GetType() == PART_EMPTY 261 | } 262 | 263 | /* 264 | Set start sector of partition. Number of sector starts from 1. 0 - invalid value. 265 | */ 266 | func (this *MBRPartition) SetLBAStart(startSector uint32) { 267 | writeLittleEndianUINT32(this.bytes[partitionLBAStartOffset:partitionLBAStartOffset+4], startSector) 268 | } 269 | 270 | /* 271 | Set length of partition in sectors. 272 | */ 273 | func (this *MBRPartition) SetLBALen(sectorCount uint32) { 274 | writeLittleEndianUINT32(this.bytes[partitionLBALengthOffset:partitionLBALengthOffset+4], sectorCount) 275 | } 276 | 277 | /* 278 | Set the Bootable flag on this partition. 279 | */ 280 | func (this *MBRPartition) SetBootable(bootable bool) { 281 | if bootable { 282 | this.bytes[partitionBootableOffset] = partitionBootableValue 283 | } else { 284 | this.bytes[partitionBootableOffset] = partitionNonBootableValue 285 | } 286 | } 287 | 288 | /* 289 | Return true if this partition's bootable flag is set. 290 | */ 291 | func (this *MBRPartition) IsBootable() bool { 292 | return this.bytes[partitionBootableOffset] == partitionBootableValue 293 | } 294 | 295 | func writeLittleEndianUINT32(buf []byte, val uint32) { 296 | buf[0] = byte(val & 0xFF) 297 | buf[1] = byte(val >> 8 & 0xFF) 298 | buf[2] = byte(val >> 16 & 0xFF) 299 | buf[3] = byte(val >> 24 & 0xFF) 300 | } 301 | 302 | func readLittleEndianUINT32(buf []byte) uint32 { 303 | return uint32(buf[0]) + uint32(buf[1])<<8 + uint32(buf[2])<<16 + uint32(buf[3])<<24 304 | } 305 | -------------------------------------------------------------------------------- /mbr_test.go: -------------------------------------------------------------------------------- 1 | package mbr 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | /* 10 | (parted) print 11 | Model: Msft Virtual Disk (scsi) 12 | Disk /dev/sda: 41943040s 13 | Sector size (logical/physical): 512B/512B 14 | Partition Table: msdos 15 | Disk Flags: 16 | 17 | Number Start End Size Type File system Flags 18 | 1 2048s 39895039s 39892992s primary xfs boot 19 | 2 39895040s 41943039s 2048000s primary linux-swap(v1) 20 | */ 21 | var mbrDump1 = []byte{0xeb, 0x63, 0x90, 0x10, 0x8e, 0xd0, 0xbc, 0x0, 0xb0, 0xb8, 0x0, 0x0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfb, 0xbe, 0x0, 0x7c, 0xbf, 0x0, 0x6, 0xb9, 0x0, 0x2, 0xf3, 0xa4, 0xea, 0x21, 0x6, 0x0, 0x0, 0xbe, 0xbe, 0x7, 0x38, 0x4, 0x75, 0xb, 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, 0x7, 0x75, 0xf3, 0xeb, 0x16, 0xb4, 0x2, 0xb0, 0x1, 0xbb, 0x0, 0x7c, 0xb2, 0x80, 0x8a, 0x74, 0x1, 0x8b, 0x4c, 0x2, 0xcd, 0x13, 0xea, 0x0, 0x7c, 0x0, 0x0, 0xeb, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfa, 0x90, 0x90, 0xf6, 0xc2, 0x80, 0x74, 0x5, 0xf6, 0xc2, 0x70, 0x74, 0x2, 0xb2, 0x80, 0xea, 0x79, 0x7c, 0x0, 0x0, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xd0, 0xbc, 0x0, 0x20, 0xfb, 0xa0, 0x64, 0x7c, 0x3c, 0xff, 0x74, 0x2, 0x88, 0xc2, 0x52, 0xbe, 0x5, 0x7c, 0xb4, 0x41, 0xbb, 0xaa, 0x55, 0xcd, 0x13, 0x5a, 0x52, 0x72, 0x3d, 0x81, 0xfb, 0x55, 0xaa, 0x75, 0x37, 0x83, 0xe1, 0x1, 0x74, 0x32, 0x31, 0xc0, 0x89, 0x44, 0x4, 0x40, 0x88, 0x44, 0xff, 0x89, 0x44, 0x2, 0xc7, 0x4, 0x10, 0x0, 0x66, 0x8b, 0x1e, 0x5c, 0x7c, 0x66, 0x89, 0x5c, 0x8, 0x66, 0x8b, 0x1e, 0x60, 0x7c, 0x66, 0x89, 0x5c, 0xc, 0xc7, 0x44, 0x6, 0x0, 0x70, 0xb4, 0x42, 0xcd, 0x13, 0x72, 0x5, 0xbb, 0x0, 0x70, 0xeb, 0x76, 0xb4, 0x8, 0xcd, 0x13, 0x73, 0xd, 0x5a, 0x84, 0xd2, 0xf, 0x83, 0xde, 0x0, 0xbe, 0x85, 0x7d, 0xe9, 0x82, 0x0, 0x66, 0xf, 0xb6, 0xc6, 0x88, 0x64, 0xff, 0x40, 0x66, 0x89, 0x44, 0x4, 0xf, 0xb6, 0xd1, 0xc1, 0xe2, 0x2, 0x88, 0xe8, 0x88, 0xf4, 0x40, 0x89, 0x44, 0x8, 0xf, 0xb6, 0xc2, 0xc0, 0xe8, 0x2, 0x66, 0x89, 0x4, 0x66, 0xa1, 0x60, 0x7c, 0x66, 0x9, 0xc0, 0x75, 0x4e, 0x66, 0xa1, 0x5c, 0x7c, 0x66, 0x31, 0xd2, 0x66, 0xf7, 0x34, 0x88, 0xd1, 0x31, 0xd2, 0x66, 0xf7, 0x74, 0x4, 0x3b, 0x44, 0x8, 0x7d, 0x37, 0xfe, 0xc1, 0x88, 0xc5, 0x30, 0xc0, 0xc1, 0xe8, 0x2, 0x8, 0xc1, 0x88, 0xd0, 0x5a, 0x88, 0xc6, 0xbb, 0x0, 0x70, 0x8e, 0xc3, 0x31, 0xdb, 0xb8, 0x1, 0x2, 0xcd, 0x13, 0x72, 0x1e, 0x8c, 0xc3, 0x60, 0x1e, 0xb9, 0x0, 0x1, 0x8e, 0xdb, 0x31, 0xf6, 0xbf, 0x0, 0x80, 0x8e, 0xc6, 0xfc, 0xf3, 0xa5, 0x1f, 0x61, 0xff, 0x26, 0x5a, 0x7c, 0xbe, 0x80, 0x7d, 0xeb, 0x3, 0xbe, 0x8f, 0x7d, 0xe8, 0x34, 0x0, 0xbe, 0x94, 0x7d, 0xe8, 0x2e, 0x0, 0xcd, 0x18, 0xeb, 0xfe, 0x47, 0x52, 0x55, 0x42, 0x20, 0x0, 0x47, 0x65, 0x6f, 0x6d, 0x0, 0x48, 0x61, 0x72, 0x64, 0x20, 0x44, 0x69, 0x73, 0x6b, 0x0, 0x52, 0x65, 0x61, 0x64, 0x0, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0xd, 0xa, 0x0, 0xbb, 0x1, 0x0, 0xb4, 0xe, 0xcd, 0x10, 0xac, 0x3c, 0x0, 0x75, 0xf4, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb2, 0x3d, 0xe, 0x0, 0x0, 0x0, 0x80, 0x20, 0x21, 0x0, 0x83, 0xfe, 0xff, 0xff, 0x0, 0x8, 0x0, 0x0, 0x0, 0xb8, 0x60, 0x2, 0x0, 0xfe, 0xff, 0xff, 0x82, 0xfe, 0xff, 0xff, 0x0, 0xc0, 0x60, 0x2, 0x0, 0x40, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0xaa} 22 | 23 | func Test_writeLittleEndianUINT32(t *testing.T){ 24 | buf := make([]byte, 4) 25 | writeLittleEndianUINT32(buf, 67305985) 26 | if buf[0] != 1 || buf[1] != 2 || buf[2] != 3 || buf[3] != 4{ 27 | t.Error("Error") 28 | } 29 | } 30 | 31 | func Test_readLittleEndianUINT32(t *testing.T){ 32 | buf := []byte{1,2,3,4} 33 | if readLittleEndianUINT32(buf) != 67305985 { 34 | t.Error("Error") 35 | } 36 | } 37 | 38 | func Test_fixSignature(t *testing.T){ 39 | if mbrSignOffset != 510 { 40 | t.Error("MBR Offset error") 41 | } 42 | 43 | buf := bytes.NewReader(make([]byte, 512)) 44 | mbr, _ := Read(buf) 45 | mbr.FixSignature() 46 | if mbr.bytes[mbrSignOffset] != 0x55 || mbr.bytes[mbrSignOffset+1] != 0xAA { 47 | t.Error("Error") 48 | } 49 | } 50 | 51 | func Test_readGoodMBR(t *testing.T){ 52 | buf := bytes.NewReader(mbrDump1) 53 | mbr, err := Read(buf) 54 | if err != nil { 55 | t.Error("Can't read: " + err.Error()) 56 | } 57 | if !mbr.GetPartition(1).IsBootable() { 58 | t.Error("partition 1 not bootable") 59 | } 60 | if mbr.GetPartition(1).IsEmpty() { 61 | t.Error("partition 1 not empty") 62 | } 63 | if mbr.GetPartition(1).GetLBAStart() != 2048 { 64 | t.Errorf("LBA start in partition 1: %d", mbr.GetPartition(1).GetLBAStart() ) 65 | } 66 | if mbr.GetPartition(1).GetLBALen() != 39892992 { 67 | t.Errorf("LBA length in partition 1: %d", mbr.GetPartition(1).GetLBALen() ) 68 | } 69 | if mbr.GetPartition(2).IsBootable() { 70 | t.Error("partition 2 is bootable") 71 | } 72 | if mbr.GetPartition(2).IsEmpty() { 73 | t.Error("partition 2 not empty") 74 | } 75 | if mbr.GetPartition(2).GetLBAStart() != 39895040 { 76 | t.Errorf("LBA start in partition 2: %d", mbr.GetPartition(2).GetLBAStart() ) 77 | } 78 | if mbr.GetPartition(2).GetLBALen() != 2048000 { 79 | t.Errorf("LBA length in partition 2: %d", mbr.GetPartition(2).GetLBALen() ) 80 | } 81 | if !mbr.GetPartition(3).IsEmpty() { 82 | t.Error("partition 3 empty") 83 | } 84 | if !mbr.GetPartition(4).IsEmpty() { 85 | t.Error("partition 3 empty") 86 | } 87 | } 88 | 89 | func Test_fixPartitionSize(t *testing.T){ 90 | buf := bytes.NewReader(mbrDump1) 91 | mbr, _ := Read(buf) 92 | mbr.GetPartition(2).SetLBALen(20) 93 | out := bytes.NewBuffer(nil) 94 | mbr.Write(out) 95 | 96 | need := make([]byte, 512) 97 | copy(need, mbrDump1) 98 | 99 | need[474] = 20 // 446 + 16 + 12 100 | need[475] = 0 // 446 + 16 + 13 101 | need[476] = 0 // 446 + 16 + 14 102 | need[477] = 0 // 446 + 16 + 15 103 | 104 | outBytes := out.Bytes() 105 | for i := 0; i < 512; i++{ 106 | if need[i] != outBytes[i] { 107 | t.Errorf("Bad value in byte: %v (%v != %v)", i, need[i], outBytes[i]) 108 | } 109 | } 110 | } 111 | 112 | func Test_fixPartitionStart(t *testing.T){ 113 | buf := bytes.NewReader(mbrDump1) 114 | mbr, _ := Read(buf) 115 | mbr.GetPartition(1).SetLBAStart(20) 116 | out := bytes.NewBuffer(nil) 117 | mbr.Write(out) 118 | 119 | need := make([]byte, 512) 120 | copy(need, mbrDump1) 121 | 122 | 123 | need[454] = 20 // 446 + 8 124 | need[455] = 0 // 446 + 9 125 | need[456] = 0 // 446 + 10 126 | need[457] = 0 // 446 + 11 127 | 128 | outBytes := out.Bytes() 129 | for i := 0; i < 512; i++{ 130 | if need[i] != outBytes[i] { 131 | t.Errorf("Bad value in byte: %d (%d != %d)", i, need[i], outBytes[i]) 132 | } 133 | } 134 | } 135 | 136 | func Test_MakeProtective(t *testing.T) { 137 | ptMap := map[ProtectiveType]string{ 138 | DiskSize: "DiskSize", 139 | DefaultProtective: "Default", 140 | MaxSize: "MaxSize", 141 | } 142 | for _, d := range []struct { 143 | ssize int 144 | diskSize uint64 145 | expected uint32 146 | desc string 147 | }{ 148 | {512, 21474836480, 41943039, "20G x 512"}, 149 | {512, 4398046511104, 0xFFFFFFFF, "4TiB x 512"}, 150 | {4096, 1024209543168, 250051157, "1TB x 4k"}, 151 | {4096, 17592186044416, 0xFFFFFFFF, "16TiB x 4k"}, 152 | } { 153 | 154 | checkMbr := func(exp uint32, pType ProtectiveType) { 155 | desc := fmt.Sprintf("%s [%s]", d.desc, ptMap[pType]) 156 | buf := bytes.NewReader(mbrDump1) 157 | mbr, _ := Read(buf) 158 | mbr.MakeProtective(d.ssize, d.diskSize, pType) 159 | if err := mbr.Check(); err != nil { 160 | t.Errorf("ProtectiveMBR failed check: %s", err) 161 | } 162 | 163 | pt := mbr.GetPartition(1) 164 | if pt.GetType() != PART_GPT { 165 | t.Errorf("%s Partition 1 had type != PART_GPT", desc) 166 | } 167 | 168 | if found := pt.GetLBAStart(); found != 1 { 169 | t.Errorf("%s Partition 1 start at %d expected 1", desc, found) 170 | } 171 | 172 | if found := pt.GetLBALen(); found != exp { 173 | t.Errorf("%s Partition 1 had len %d, expected %d", desc, found, exp) 174 | } 175 | for n := 2; n <= 4; n++ { 176 | if mbr.GetPartition(n).GetType() != PART_EMPTY { 177 | t.Errorf("Partition %d was not empty", n) 178 | } 179 | } 180 | } 181 | 182 | checkMbr(0xFFFFFFFF, MaxSize) 183 | checkMbr(d.expected, DiskSize) 184 | } 185 | 186 | } 187 | --------------------------------------------------------------------------------