Skip to content

Commit

Permalink
feat: support probing FAT12/FAT16 filesystems
Browse files Browse the repository at this point in the history
We always supported FAT32, but for small disk sizes (like the one you
might create for a config partition), `mkfs.vfat` would default to
FAT16/32 which Tails fails to discover.

Fixes #57

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
  • Loading branch information
smira committed Apr 5, 2022
1 parent b374eb4 commit d9c3a27
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 23 deletions.
2 changes: 2 additions & 0 deletions blockdevice/filesystem/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/iso9660"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/luks"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/msdos"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/vfat"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/xfs"
)
Expand Down Expand Up @@ -59,6 +60,7 @@ func Probe(path string) (sb SuperBlocker, err error) {
superblocks := []SuperBlocker{
&iso9660.SuperBlock{},
&vfat.SuperBlock{},
&msdos.SuperBlock{},
&xfs.SuperBlock{},
&luks.SuperBlock{},
}
Expand Down
6 changes: 6 additions & 0 deletions blockdevice/filesystem/msdos/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Package msdos provides functions for working with the FAT12/16 filesystems.
package msdos
49 changes: 49 additions & 0 deletions blockdevice/filesystem/msdos/superblock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package msdos

import (
"bytes"
)

const (
// Magic12 is the FAT12 magic signature.
Magic12 = "FAT12"
// Magic16 is the FAT16 magic signature.
Magic16 = "FAT16"
)

// SuperBlock represents the vfat super block.
//
// See https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Extended_BIOS_Parameter_Block for the reference.
type SuperBlock struct {
_ [0x2b]uint8
Label [11]uint8
Magic [8]uint8
_ [0x1cd]uint8
}

// Is implements the SuperBlocker interface.
func (sb *SuperBlock) Is() bool {
trimmed := bytes.Trim(sb.Magic[:], " ")

return bytes.Equal(trimmed, []byte(Magic12)) || bytes.Equal(trimmed, []byte(Magic16))
}

// Offset implements the SuperBlocker interface.
func (sb *SuperBlock) Offset() int64 {
return 0x0
}

// Type implements the SuperBlocker interface.
func (sb *SuperBlock) Type() string {
// using `vfat` here, as it's the filesystem type in Linux
return "vfat"
}

// Encrypted implements the SuperBlocker interface.
func (sb *SuperBlock) Encrypted() bool {
return false
}
6 changes: 6 additions & 0 deletions blockdevice/probe/probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/talos-systems/go-blockdevice/blockdevice"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/iso9660"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/msdos"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/vfat"
"github.com/talos-systems/go-blockdevice/blockdevice/filesystem/xfs"
"github.com/talos-systems/go-blockdevice/blockdevice/partition/gpt"
Expand Down Expand Up @@ -63,6 +64,11 @@ func WithFileSystemLabel(label string) SelectOption {
if bytes.Equal(trimmed, []byte(label)) {
return true, nil
}
case *msdos.SuperBlock:
trimmed := bytes.Trim(sb.Label[:], " \x00")
if bytes.Equal(trimmed, []byte(label)) {
return true, nil
}
case *xfs.SuperBlock:
trimmed := bytes.Trim(sb.Fname[:], " \x00")
if bytes.Equal(trimmed, []byte(label)) {
Expand Down
73 changes: 50 additions & 23 deletions blockdevice/probe/probe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ package probe_test

import (
"errors"
"fmt"
"os"
"os/exec"
"strconv"
"testing"

"github.com/stretchr/testify/suite"
Expand All @@ -25,7 +27,7 @@ func (suite *ProbeSuite) SetupTest() {
suite.CreateBlockDevice(1024 * 1024 * 1024)
}

func (suite *ProbeSuite) addPartition(name string, size uint64) *gpt.Partition {
func (suite *ProbeSuite) addPartition(name string, size uint64, fatBits int) *gpt.Partition {
var (
g *gpt.GPT
err error
Expand All @@ -48,31 +50,48 @@ func (suite *ProbeSuite) addPartition(name string, size uint64) *gpt.Partition {
partPath, err := partition.Path()
suite.Require().NoError(err)

cmd := exec.Command("mkfs.vfat", "-F", "32", "-n", name, partPath)
cmd := exec.Command("mkfs.vfat", "-F", strconv.Itoa(fatBits), "-n", name, partPath)
suite.Require().NoError(cmd.Run())

return partition
}

func (suite *ProbeSuite) setSystemLabel(name string) {
cmd := exec.Command("mkfs.vfat", "-F", "32", "-n", name, suite.LoopbackDevice.Name())
func (suite *ProbeSuite) setSystemLabel(name string, fatBits int) {
cmd := exec.Command("mkfs.vfat", "-F", strconv.Itoa(fatBits), "-n", name, suite.LoopbackDevice.Name())
suite.Require().NoError(cmd.Run())
}

func (suite *ProbeSuite) TestDevForPartitionLabel() {
size := uint64(1024 * 1024 * 256)
part := suite.addPartition("devpart1", size)

dev, err := probe.DevForPartitionLabel(suite.LoopbackDevice.Name(), "devpart1")
suite.Require().NoError(err)
path, err := part.Path()
suite.Require().NoError(err)
suite.Require().Equal(path, dev.Device().Name())
part12 := suite.addPartition("devpart12", 1024*1024, 12)
part32 := suite.addPartition("devpart32", 1024*1024*256, 32)

for _, tc := range []struct {
part *gpt.Partition
label string
}{
{
label: "devpart12",
part: part12,
},
{
label: "devpart32",
part: part32,
},
} {
suite.T().Run(tc.label, func(t *testing.T) {
dev, err := probe.DevForPartitionLabel(suite.LoopbackDevice.Name(), tc.label)
suite.Require().NoError(err)

path, err := tc.part.Path()
suite.Require().NoError(err)
suite.Require().Equal(path, dev.Device().Name())
})
}
}

func (suite *ProbeSuite) TestGetDevWithPartitionName() {
size := uint64(1024 * 1024 * 512)
part := suite.addPartition("devlabel", size)
part := suite.addPartition("devlabel", size, 32)

dev, err := probe.GetDevWithPartitionName("devlabel")
suite.Require().NoError(err)
Expand All @@ -81,18 +100,27 @@ func (suite *ProbeSuite) TestGetDevWithPartitionName() {
suite.Require().Equal(devpath, dev.Path)
}

func (suite *ProbeSuite) TestGetDevWithFileSystemLabel() {
suite.setSystemLabel("GETLABELSYS")
func (suite *ProbeSuite) testGetDevWithFileSystemLabel(fatBits int) {
label := fmt.Sprintf("LABELSYS%d", fatBits)

suite.setSystemLabel(label, fatBits)

dev, err := probe.GetDevWithFileSystemLabel("GETLABELSYS")
dev, err := probe.GetDevWithFileSystemLabel(label)
suite.Require().NoError(err)
suite.Require().Equal(suite.LoopbackDevice.Name(), dev.Path)
}

func (suite *ProbeSuite) TestGetDevWithFileSystemLabel16() {
suite.testGetDevWithFileSystemLabel(16)
}

func (suite *ProbeSuite) TestGetDevWithFileSystemLabel32() {
suite.testGetDevWithFileSystemLabel(32)
}

func (suite *ProbeSuite) TestProbeByPartitionLabel() {
size := uint64(1024 * 1024 * 256)
suite.addPartition("test", size)
suite.addPartition("test2", size)
suite.addPartition("test", 1024*1024, 12)
suite.addPartition("test2", 1024*1024*256, 32)

probed, err := probe.All(probe.WithPartitionLabel("test"), probe.WithSingleResult())
suite.Require().NoError(err)
Expand All @@ -102,7 +130,7 @@ func (suite *ProbeSuite) TestProbeByPartitionLabel() {
}

func (suite *ProbeSuite) TestProbeByFilesystemLabelBlockdevice() {
suite.setSystemLabel("FSLBABELBD")
suite.setSystemLabel("FSLBABELBD", 32)

probed, err := probe.All(probe.WithFileSystemLabel("FSLBABELBD"))
suite.Require().NoError(err)
Expand All @@ -113,9 +141,8 @@ func (suite *ProbeSuite) TestProbeByFilesystemLabelBlockdevice() {
}

func (suite *ProbeSuite) TestProbeByFilesystemLabelPartition() {
size := uint64(1024 * 1024 * 256)
suite.addPartition("FOO", size)
suite.addPartition("FSLABELPART", size)
suite.addPartition("FOO", 1024*1024*256, 16)
suite.addPartition("FSLABELPART", 1024*1024*2, 12)

probed, err := probe.All(probe.WithFileSystemLabel("FSLABELPART"))
suite.Require().NoError(err)
Expand Down
2 changes: 2 additions & 0 deletions blockdevice/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ func (suite *BlockDeviceSuite) TearDownTest() {
suite.T().Logf("Freeing %s", suite.LoopbackDevice.Name())

suite.Assert().NoError(loopback.Unloop(suite.LoopbackDevice))
suite.Assert().NoError(suite.LoopbackDevice.Close())

suite.LoopbackDevice = nil
}

Expand Down

0 comments on commit d9c3a27

Please sign in to comment.