wincmd/ntfs/bootsect/bootsect.go
starainrt 7e6cc73106
完善 Windows 运维封装与 NTFS 索引解析
- 新增自启动幂等配置、统一错误语义、进程等待和进程树终止能力
- 增强服务生命周期管理,支持等待状态、重启、幂等创建和配置更新
- 新增 NTFS 卷索引、文件 ID 解析、文件遍历、USN 变更监听和 bookmark 持久化
- 修复 NTFS boot sector、fragment、MFT、USN 解析边界和路径重建问题
- 补充权限、进程、服务、NTFS 解析和工作流回归测试
- 增加 Windows 测试脚本和管理员 NTFS smoke 验证脚本
- 升级 Go 兼容版本到 1.18,并更新 stario、win32api 及相关间接依赖
2026-06-09 15:59:31 +08:00

68 lines
2.4 KiB
Go

/*
Package bootsect provides functions to parse the boot sector (also sometimes called Volume Boot Record, VBR, or
$Boot file) of an NTFS volume.
*/
package bootsect
import (
"fmt"
"b612.me/wincmd/ntfs/binutil"
)
// BootSector represents the parsed data of an NTFS boot sector. The OemId should typically be "NTFS " ("NTFS"
// followed by 4 trailing spaces) for a valid NTFS boot sector.
type BootSector struct {
OemId string
BytesPerSector int
SectorsPerCluster int
MediaDescriptor byte
SectorsPerTrack int
NumberofHeads int
HiddenSectors int
TotalSectors uint64
MftClusterNumber uint64
MftMirrorClusterNumber uint64
FileRecordSegmentSizeInBytes int
IndexBufferSizeInBytes int
VolumeSerialNumber []byte
}
// Parse parses the data of an NTFS boot sector into a BootSector structure.
func Parse(data []byte) (BootSector, error) {
if len(data) < 80 {
return BootSector{}, fmt.Errorf("boot sector data should be at least 80 bytes but is %d", len(data))
}
r := binutil.NewLittleEndianReader(data)
bytesPerSector := int(r.Uint16(0x0B))
sectorsPerCluster := int(r.Byte(0x0D))
bytesPerCluster := bytesPerSector * sectorsPerCluster
return BootSector{
OemId: string(r.Read(0x03, 8)),
BytesPerSector: bytesPerSector,
SectorsPerCluster: sectorsPerCluster,
MediaDescriptor: r.Byte(0x15),
SectorsPerTrack: int(r.Uint16(0x18)),
NumberofHeads: int(r.Uint16(0x1A)),
HiddenSectors: int(r.Uint32(0x1C)),
TotalSectors: r.Uint64(0x28),
MftClusterNumber: r.Uint64(0x30),
MftMirrorClusterNumber: r.Uint64(0x38),
FileRecordSegmentSizeInBytes: bytesOrClustersToBytes(r.Byte(0x40), bytesPerCluster),
IndexBufferSizeInBytes: bytesOrClustersToBytes(r.Byte(0x44), bytesPerCluster),
VolumeSerialNumber: binutil.Duplicate(r.Read(0x48, 8)),
}, nil
}
func bytesOrClustersToBytes(b byte, bytesPerCluster int) int {
// From Wikipedia:
// A positive value denotes the number of clusters in a File Record Segment. A negative value denotes the amount of
// bytes in a File Record Segment, in which case the size is 2 to the power of the absolute value.
// (0xF6 = -10 → 210 = 1024).
i := int(int8(b))
if i < 0 {
return 1 << -i
}
return i * bytesPerCluster
}