Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use read full when reading data #95

Merged
merged 1 commit into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion blkid/blkid_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func Probe(f *os.File, opts ...ProbeOption) (*Info, error) {
defer wholeDisk.Unlock() //nolint:errcheck
}

if err := info.fillProbeResult(f); err != nil {
if err := info.fillProbeResult(f, options); err != nil {
return nil, fmt.Errorf("failed to probe: %w", err)
}

Expand Down
13 changes: 10 additions & 3 deletions blkid/blkid_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/siderolabs/go-pointer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"

"github.com/siderolabs/go-blockdevice/v2/blkid"
"github.com/siderolabs/go-blockdevice/v2/block"
Expand Down Expand Up @@ -437,7 +438,9 @@ func TestProbePathFilesystems(t *testing.T) {

test.setup(t, probePath)

info, err := blkid.ProbePath(probePath)
logger := zaptest.NewLogger(t)

info, err := blkid.ProbePath(probePath, blkid.WithProbeLogger(logger))
require.NoError(t, err)

if useLoopDevice {
Expand Down Expand Up @@ -652,7 +655,9 @@ func TestProbePathGPT(t *testing.T) {

test.setup(t, probePath)

info, err := blkid.ProbePath(probePath)
logger := zaptest.NewLogger(t)

info, err := blkid.ProbePath(probePath, blkid.WithProbeLogger(logger))
require.NoError(t, err)

if useLoopDevice {
Expand Down Expand Up @@ -745,7 +750,9 @@ func TestProbePathNested(t *testing.T) {

test.setup(t, probePath)

info, err := blkid.ProbePath(probePath)
logger := zaptest.NewLogger(t)

info, err := blkid.ProbePath(probePath, blkid.WithProbeLogger(logger))
require.NoError(t, err)

assert.NotNil(t, info.BlockDevice)
Expand Down
2 changes: 1 addition & 1 deletion blkid/internal/filesystems/ext/ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (p *Probe) Name() string {
func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
buf := make([]byte, SUPERBLOCK_SIZE)

if _, err := r.ReadAt(buf, sbOffset); err != nil {
if err := utils.ReadFullAt(r, buf, sbOffset); err != nil {
return nil, err
}

Expand Down
3 changes: 2 additions & 1 deletion blkid/internal/filesystems/iso9660/iso9660.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

const (
Expand Down Expand Up @@ -61,7 +62,7 @@ vdLoop:
for i := range vdMax {
buf := make([]byte, VOLUMEDESCRIPTOR_SIZE)

if _, err := r.ReadAt(buf, superblockOffset+sectorSize*int64(i)); err != nil {
if err := utils.ReadFullAt(r, buf, superblockOffset+sectorSize*int64(i)); err != nil {
break
}

Expand Down
3 changes: 2 additions & 1 deletion blkid/internal/filesystems/luks/luks.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

var luksMagic = magic.Magic{
Expand All @@ -39,7 +40,7 @@ func (p *Probe) Name() string {
func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
buf := make([]byte, LUKS2HEADER_SIZE)

if _, err := r.ReadAt(buf, 0); err != nil {
if err := utils.ReadFullAt(r, buf, 0); err != nil {
return nil, err
}

Expand Down
3 changes: 2 additions & 1 deletion blkid/internal/filesystems/lvm2/lvm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package lvm2
import (
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

var (
Expand Down Expand Up @@ -43,7 +44,7 @@ func (p *Probe) Name() string {
func (p *Probe) probe(r probe.Reader, offset int64) (LVM2Header, error) {
buf := make([]byte, LVM2HEADER_SIZE)

if _, err := r.ReadAt(buf, offset); err != nil {
if err := utils.ReadFullAt(r, buf, offset); err != nil {
return nil, err
}

Expand Down
3 changes: 2 additions & 1 deletion blkid/internal/filesystems/squashfs/squashfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package squashfs
import (
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

var squashfsMagic1 = magic.Magic{ // big endian
Expand Down Expand Up @@ -42,7 +43,7 @@ func (p *Probe) Name() string {
func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
buf := make([]byte, SUPERBLOCK_SIZE)

if _, err := r.ReadAt(buf, 0); err != nil {
if err := utils.ReadFullAt(r, buf, 0); err != nil {
return nil, err
}

Expand Down
3 changes: 2 additions & 1 deletion blkid/internal/filesystems/swap/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

var (
Expand Down Expand Up @@ -98,7 +99,7 @@ func (p *Probe) Name() string {
func (p *Probe) Probe(r probe.Reader, m magic.Magic) (*probe.Result, error) {
buf := make([]byte, SWAPHEADER_SIZE)

if _, err := r.ReadAt(buf, 1024); err != nil {
if err := utils.ReadFullAt(r, buf, 1024); err != nil {
return nil, err
}

Expand Down
5 changes: 3 additions & 2 deletions blkid/internal/filesystems/talosmeta/talosmeta.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

// META constants, from talos/internal/pkg/meta/internal/adv/talos.
Expand Down Expand Up @@ -44,15 +45,15 @@ func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
buf := make([]byte, 4)

for _, offset := range []int64{0, length} {
if _, err := r.ReadAt(buf, offset); err != nil {
if err := utils.ReadFullAt(r, buf, offset); err != nil {
return nil, err
}

if binary.BigEndian.Uint32(buf) != magic1 {
continue
}

if _, err := r.ReadAt(buf, offset+length-4); err != nil {
if err := utils.ReadFullAt(r, buf, offset+length-4); err != nil {
return nil, err
}

Expand Down
4 changes: 2 additions & 2 deletions blkid/internal/filesystems/vfat/vfat.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
vfatBuf := make([]byte, VFATSB_SIZE)
msdosBuf := make([]byte, MSDOSSB_SIZE)

if _, err := r.ReadAt(vfatBuf, 0); err != nil {
if err := utils.ReadFullAt(r, vfatBuf, 0); err != nil {
return nil, err
}

if _, err := r.ReadAt(msdosBuf, 0); err != nil {
if err := utils.ReadFullAt(r, msdosBuf, 0); err != nil {
return nil, err
}

Expand Down
6 changes: 4 additions & 2 deletions blkid/internal/filesystems/xfs/xfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ package xfs

import (
"bytes"
"fmt"

"github.com/google/uuid"
"github.com/siderolabs/go-pointer"

"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

var xfsMagic = magic.Magic{
Expand All @@ -39,13 +41,13 @@ func (p *Probe) Name() string {
func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
buf := make([]byte, SUPERBLOCK_SIZE)

if _, err := r.ReadAt(buf, 0); err != nil {
if err := utils.ReadFullAt(r, buf, 0); err != nil {
return nil, err
}

sb := SuperBlock(buf)
if !sb.Valid() {
return nil, nil //nolint:nilnil
return nil, fmt.Errorf("xfs superblock is not valid")
}

uuid, err := uuid.FromBytes(sb.Get_sb_uuid())
Expand Down
3 changes: 2 additions & 1 deletion blkid/internal/filesystems/zfs/zfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

// https://github.com/util-linux/util-linux/blob/c0207d354ee47fb56acfa64b03b5b559bb301280/libblkid/src/superblocks/zfs.c
Expand Down Expand Up @@ -65,7 +66,7 @@ func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
size - zfsStartOffset - lastLabelOffset,
} {
labelBuf := make([]byte, zfsVdevLabelSize)
if _, err := r.ReadAt(labelBuf, int64(labelOffset)); err != nil {
if err := utils.ReadFullAt(r, labelBuf, int64(labelOffset)); err != nil {
return nil, err
}

Expand Down
5 changes: 3 additions & 2 deletions blkid/internal/partitions/gpt/gpt.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

//go:generate go run ../../cstruct/cstruct.go -pkg gpt -struct Header -input header.h -endianness LittleEndian
Expand Down Expand Up @@ -144,7 +145,7 @@ func readHeader(r probe.Reader, lba, lastLBA uint64) (*Header, []Entry, error) {
sectorSize := r.GetSectorSize()
buf := make([]byte, sectorSize)

if _, err := r.ReadAt(buf, int64(lba)*int64(sectorSize)); err != nil {
if err := utils.ReadFullAt(r, buf, int64(lba)*int64(sectorSize)); err != nil {
return nil, nil, err
}

Expand Down Expand Up @@ -196,7 +197,7 @@ func readHeader(r probe.Reader, lba, lastLBA uint64) (*Header, []Entry, error) {
// read partition entries, verify checksum
entriesBuffer := make([]byte, hdr.Get_num_partition_entries()*ENTRY_SIZE)

if _, err := r.ReadAt(entriesBuffer, int64(hdr.Get_partition_entries_lba())*int64(sectorSize)); err != nil {
if err := utils.ReadFullAt(r, entriesBuffer, int64(hdr.Get_partition_entries_lba())*int64(sectorSize)); err != nil {
return nil, nil, err
}

Expand Down
25 changes: 25 additions & 0 deletions blkid/internal/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package utils

import (
"hash/crc32"
"io"
"sync"
)

Expand All @@ -23,3 +24,27 @@ func CRC32c(buf []byte) uint32 {
func IsPowerOf2[T uint8 | uint16 | uint32 | uint64](num T) bool {
return (num != 0 && ((num & (num - 1)) == 0))
}

// ReadFullAt is io.ReadFull for io.ReaderAt.
func ReadFullAt(r io.ReaderAt, buf []byte, offset int64) error {
for n := 0; n < len(buf); {
m, err := r.ReadAt(buf[n:], offset)

n += m
offset += int64(m)

if err != nil {
if err == io.EOF && n == len(buf) {
return nil
}

if err == io.EOF {
err = io.ErrUnexpectedEOF
}

return err
}
}

return nil
}
26 changes: 17 additions & 9 deletions blkid/probe_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import (
"io"
"os"

"go.uber.org/zap"

"github.com/siderolabs/go-blockdevice/v2/blkid/internal/chain"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/utils"
)

type probeReader struct {
Expand All @@ -30,10 +33,10 @@ func (r *probeReader) GetSize() uint64 {
return r.size
}

func (i *Info) fillProbeResult(f *os.File) error {
func (i *Info) fillProbeResult(f *os.File, options ProbeOptions) error {
chain := chain.Default()

res, matched, err := i.probe(f, chain, 0, i.Size)
res, matched, err := i.probe(f, chain, 0, i.Size, options)
if err != nil {
return fmt.Errorf("error probing: %w", err)
}
Expand All @@ -49,14 +52,14 @@ func (i *Info) fillProbeResult(f *os.File) error {
i.ProbedSize = res.ProbedSize
i.Label = res.Label

if err = i.fillNested(f, chain, 0, &i.Parts, res.Parts); err != nil {
if err = i.fillNested(f, chain, 0, &i.Parts, res.Parts, options); err != nil {
return fmt.Errorf("error probing nested: %w", err)
}

return nil
}

func (i *Info) fillNested(f *os.File, chain chain.Chain, offset uint64, out *[]NestedProbeResult, parts []probe.Partition) error {
func (i *Info) fillNested(f *os.File, chain chain.Chain, offset uint64, out *[]NestedProbeResult, parts []probe.Partition, options ProbeOptions) error {
if len(parts) == 0 {
return nil
}
Expand All @@ -72,7 +75,7 @@ func (i *Info) fillNested(f *os.File, chain chain.Chain, offset uint64, out *[]N
(*out)[idx].PartitionOffset = part.Offset
(*out)[idx].PartitionSize = part.Size

res, matched, err := i.probe(f, chain, offset+part.Offset, part.Size)
res, matched, err := i.probe(f, chain, offset+part.Offset, part.Size, options)
if err != nil {
return fmt.Errorf("error probing nested: %w", err)
}
Expand All @@ -88,15 +91,15 @@ func (i *Info) fillNested(f *os.File, chain chain.Chain, offset uint64, out *[]N
(*out)[idx].ProbedSize = res.ProbedSize
(*out)[idx].Label = res.Label

if err = i.fillNested(f, chain, offset+part.Offset, &(*out)[idx].Parts, res.Parts); err != nil {
if err = i.fillNested(f, chain, offset+part.Offset, &(*out)[idx].Parts, res.Parts, options); err != nil {
return fmt.Errorf("error probing nested: %w", err)
}
}

return nil
}

func (i *Info) probe(f *os.File, chain chain.Chain, offset, length uint64) (*probe.Result, probe.Prober, error) {
func (i *Info) probe(f *os.File, chain chain.Chain, offset, length uint64, options ProbeOptions) (*probe.Result, probe.Prober, error) {
if offset+length > i.Size {
return nil, nil, fmt.Errorf("probing range is out of bounds: offset %d + len %d > size %d", offset, length, i.Size)
}
Expand All @@ -113,8 +116,7 @@ func (i *Info) probe(f *os.File, chain chain.Chain, offset, length uint64) (*pro

buf := make([]byte, magicReadSize)

_, err := f.ReadAt(buf, int64(offset))
if err != nil {
if err := utils.ReadFullAt(f, buf, int64(offset)); err != nil {
return nil, nil, fmt.Errorf("error reading magic buffer: %w", err)
}

Expand All @@ -128,6 +130,12 @@ func (i *Info) probe(f *os.File, chain chain.Chain, offset, length uint64) (*pro
for _, matched := range chain.MagicMatches(buf) {
res, err := matched.Prober.Probe(pR, matched.Magic)
if err != nil || res == nil {
if err != nil {
options.Logger.Debug("magic matched, but probe failed", zap.Uint64("offset", offset), zap.String("name", matched.Prober.Name()), zap.Error(err))
} else {
options.Logger.Debug("magic matched, but probe returned no result", zap.Uint64("offset", offset), zap.String("name", matched.Prober.Name()))
}

// skip failed probes
continue
}
Expand Down