Skip to content

Commit

Permalink
add bootsector type
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Feb 3, 2024
1 parent bfeb717 commit 927d393
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 12 deletions.
20 changes: 9 additions & 11 deletions fat.go
Original file line number Diff line number Diff line change
Expand Up @@ -2352,19 +2352,17 @@ func (fsys *FS) gen_numname(dst, src []byte, lfn []uint16, seq uint32) {
}
}

func str(s []byte) string {
if len(s) == 0 {
return ""
func bstr(s []byte) []byte {
i := 0
for i < len(s) && s[i] != 0 {
i++
}
return s[:i]
}

func str(s []byte) string {
var buf []byte
for i := 0; i < len(s); i++ {
b := s[i]
if b == 0 || b >= 0x80 {
return string(buf)
}
buf = append(buf, byte(b))
}
return string(buf)
return string(append(buf, bstr(s)...))
}

func str16(s []uint16) string {
Expand Down
8 changes: 8 additions & 0 deletions fat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,11 @@ var fatInit = map[int64][512]byte{

const rootFileContents = "this is\nthe root file\n"
const dirFileContents = "this is not\nnot the root\nnot the root file\nnope. \nThis file has 5 lines.\n"

func TestBootSector(t *testing.T) {
var bs bootsector
dat := fatInit[0]
bs.data = dat[:]

t.Log(bs.String())
}
175 changes: 174 additions & 1 deletion format.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package fat

import "errors"
import (
"encoding/binary"
"errors"
"strconv"
)

type Format uint8

Expand Down Expand Up @@ -86,3 +90,172 @@ func (f *Formatter) move_window(addr lba) error {
}
return nil
}

type bootsector struct {
data []byte
}

// SectorSize returns the size of a sector in bytes.
func (bs *bootsector) SectorSize() uint16 {
return binary.LittleEndian.Uint16(bs.data[bpbBytsPerSec:])
}

// SectorsPerFAT returns the number of sectors per File Allocation Table.
func (bs *bootsector) SectorsPerFAT() uint32 {
fatsz := uint32(binary.LittleEndian.Uint16(bs.data[bpbFATSz16:]))
if fatsz == 0 {
fatsz = binary.LittleEndian.Uint32(bs.data[bpbFATSz32:])
}
return fatsz
}

// NumberOfFATs returns the number of File Allocation Tables. Should be 1 or 2.
func (bs *bootsector) NumberOfFATs() uint8 {
return bs.data[bpbNumFATs]
}

// SectorsPerCluster returns the number of sectors per cluster.
// Should be a power of 2 and not larger than 128.
func (bs *bootsector) SectorsPerCluster() uint16 {
return uint16(bs.data[bpbSecPerClus])
}

// ReservedSectors returns the number of reserved sectors at the beginning of the volume.
// Should be at least 1.
func (bs *bootsector) ReservedSectors() uint16 {
return binary.LittleEndian.Uint16(bs.data[bpbRsvdSecCnt:])
}

// TotalSectors returns the total number of sectors in the volume that
// can be used by the filesystem.
func (bs *bootsector) TotalSectors() uint32 {
totsec := uint32(binary.LittleEndian.Uint16(bs.data[bpbTotSec16:]))
if totsec == 0 {
totsec = binary.LittleEndian.Uint32(bs.data[bpbTotSec32:])
}
return totsec
}

// RootDirSectors returns the number of sectors occupied by the root directory.
// Should be divisible by SectorSize/32.
func (bs *bootsector) RootDirEntries() uint16 {
return binary.LittleEndian.Uint16(bs.data[bpbRootEntCnt:])
}

// Version returns the filesystem version, should be 0.0 for FAT32.
func (bs *bootsector) Version() (major, minor uint8) {
return bs.data[bpbFSVer32], bs.data[bpbFSVer32+1]
}

// RootCluster returns the first cluster of the root directory.
func (bs *bootsector) RootCluster() uint32 {
return binary.LittleEndian.Uint32(bs.data[bpbRootClus32:])
}

func (bs *bootsector) ExtendedBootSignature() uint8 {
return bs.data[bsBootSig32]
}

// BootSignature returns the boot signature at offset 510 which should be 0xAA55.
func (bs *bootsector) BootSignature() uint16 {
return binary.LittleEndian.Uint16(bs.data[bs55AA:])
}

// FSInfo returns the sector number of the FS Information Sector.
// Expect =1 for FAT32.
func (bs *bootsector) FSInfo() uint16 {
return binary.LittleEndian.Uint16(bs.data[bpbFSInfo32:])
}

// DriveNumber returns the drive number.
func (bs *bootsector) DriveNumber() uint8 {
return bs.data[bsDrvNum32]
}

// VolumeSerialNumber returns the volume serial number.
func (bs *bootsector) VolumeSerialNumber() uint32 {
return binary.LittleEndian.Uint32(bs.data[bsVolID32:])
}

// VolumeLabel returns the volume label string.
func (bs *bootsector) VolumeLabel() [8]byte {
var label [8]byte
copy(label[:], bs.data[bsVolLab32:])
return label
}

// FilesystemType returns the filesystem type string, usually "FAT32 ".
func (bs *bootsector) FilesystemType() [8]byte {
var label [8]byte
copy(label[:], bs.data[bsFilSysType32:])
return label
}

// JumpInstruction returns the x86 jump instruction at the beginning of the boot sector.
func (bs *bootsector) JumpInstruction() [3]byte {
var jmpboot [3]byte
copy(jmpboot[:], bs.data[0:])
return jmpboot
}

// OEMName returns the Original Equipment Manufacturer name at the start of the bootsector.
func (bs *bootsector) OEMName() [8]byte {
var oemname [8]byte
copy(oemname[:], bs.data[bsOEMName:])
return oemname
}

func (bs *bootsector) VolumeOffset() uint32 {
return binary.LittleEndian.Uint32(bs.data[bpbHiddSec:])
}

func (bs *bootsector) String() string {
return string(bs.Appendf(nil, '\n'))
}

func (bs *bootsector) Appendf(dst []byte, separator byte) []byte {
appendData := func(name string, data []byte, sep byte) {
if len(data) == 0 {
return
}
dst = append(dst, name...)
dst = append(dst, ':')
dst = append(dst, data...)
dst = append(dst, sep)
}
appendInt := func(name string, data uint32, sep byte) {
dst = append(dst, name...)
dst = append(dst, ':')
dst = strconv.AppendUint(dst, uint64(data), 10)
dst = append(dst, sep)
}
oem := bs.OEMName()
appendData("OEM", bstr(oem[:]), separator)
fstype := bs.FilesystemType()
appendData("FSType", bstr(fstype[:]), separator)
volLabel := bs.VolumeLabel()
appendData("VolumeLabel", bstr(volLabel[:]), separator)
appendInt("VolumeSerialNumber", bs.VolumeSerialNumber(), separator)
appendInt("VolumeOffset", bs.VolumeOffset(), separator)
appendInt("SectorSize", uint32(bs.SectorSize()), separator)
appendInt("SectorsPerCluster", uint32(bs.SectorsPerCluster()), separator)
appendInt("ReservedSectors", uint32(bs.ReservedSectors()), separator)
appendInt("NumberOfFATs", uint32(bs.NumberOfFATs()), separator)
appendInt("RootDirEntries", uint32(bs.RootDirEntries()), separator)
appendInt("TotalSectors", uint32(bs.TotalSectors()), separator)
appendInt("SectorsPerFAT", uint32(bs.SectorsPerFAT()), separator)
appendInt("RootCluster", uint32(bs.RootCluster()), separator)
appendInt("FSInfo", uint32(bs.FSInfo()), separator)
appendInt("DriveNumber", uint32(bs.DriveNumber()), separator)
major, minor := bs.Version()
if major != 0 || minor != 0 {
appendInt("Version", uint32(major)<<16|uint32(minor), separator)
}
// appendData("BootCode", bstr(bs.BootCode()), separator)
return dst
}

// BootCode returns the boot code at the end of the boot sector.
func (bs *bootsector) BootCode() []byte {
return bs.data[bsBootCode32:bs55AA]
}

0 comments on commit 927d393

Please sign in to comment.