Skip to content

Commit

Permalink
refactor: use interface types for custom metadata
Browse files Browse the repository at this point in the history
Switch to encoding.BinaryUnmarshaler/encoding.BinaryMarshaler for
GetMetadata/OptMetadata rather than "any" type.
  • Loading branch information
tri-adam committed Mar 6, 2023
1 parent 59a5446 commit 6e2497e
Showing 5 changed files with 58 additions and 50 deletions.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ linters:
- typecheck
- unconvert
- unparam
- unused
# - unused
- whitespace

linters-settings:
4 changes: 2 additions & 2 deletions pkg/sif/create.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2018-2022, Sylabs Inc. All rights reserved.
// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved.
// Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
// Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
@@ -69,7 +69,7 @@ func (f *FileImage) writeDataObject(i int, di DescriptorInput, t time.Time) erro

// If this is a primary partition, verify there isn't another primary partition, and update the
// architecture in the global header.
if p, ok := di.opts.extra.(partition); ok && p.Parttype == PartPrimSys {
if p, ok := di.opts.md.(partition); ok && p.Parttype == PartPrimSys {
if ds, err := f.GetDescriptors(WithPartitionType(PartPrimSys)); err == nil && len(ds) > 0 {
return errPrimaryPartition
}
74 changes: 41 additions & 33 deletions pkg/sif/descriptor.go
Original file line number Diff line number Diff line change
@@ -45,6 +45,11 @@ type partition struct {
Arch archType
}

// MarshalBinary encodes p into binary format.
func (p partition) MarshalBinary() ([]byte, error) {
return binaryMarshaler{p}.MarshalBinary()
}

// signature represents the SIF signature data object descriptor.
type signature struct {
Hashtype hashType
@@ -62,6 +67,26 @@ type sbom struct {
Format SBOMFormat
}

// The binaryMarshaler type is an adapter that allows a type suitable for use with the
// encoding/binary package to be used as an encoding.BinaryMarshaler.
type binaryMarshaler struct{ any }

// MarshalBinary encodes m into binary format.
func (m binaryMarshaler) MarshalBinary() ([]byte, error) {
var b bytes.Buffer
err := binary.Write(&b, binary.LittleEndian, m.any)
return b.Bytes(), err
}

// The binaryUnmarshaler type is an adapter that allows a type suitable for use with the
// encoding/binary package to be used as an encoding.BinaryUnmarshaler.
type binaryUnmarshaler struct{ any }

// UnmarshalBinary decodes b into u.
func (u binaryUnmarshaler) UnmarshalBinary(b []byte) error {
return binary.Read(bytes.NewReader(b), binary.LittleEndian, u.any)
}

var errNameTooLarge = errors.New("name value too large")

// setName encodes name into the name field of d.
@@ -79,27 +104,15 @@ func (d *rawDescriptor) setName(name string) error {

var errExtraTooLarge = errors.New("extra value too large")

// setExtra encodes v into the extra field of d. If the encoding.BinaryMarshaler interface is
// implemented by v, it is used for marshaling. Otherwise, binary.Write() is used.
func (d *rawDescriptor) setExtra(v any) error {
if v == nil {
// setExtra marshals metadata from md into the "extra" field of d.
func (d *rawDescriptor) setExtra(md encoding.BinaryMarshaler) error {
if md == nil {
return nil
}

var extra []byte

if m, ok := v.(encoding.BinaryMarshaler); ok {
b, err := m.MarshalBinary()
if err != nil {
return err
}
extra = b
} else {
b := new(bytes.Buffer)
if err := binary.Write(b, binary.LittleEndian, v); err != nil {
return err
}
extra = b.Bytes()
extra, err := md.MarshalBinary()
if err != nil {
return err
}

if len(extra) > len(d.Extra) {
@@ -113,13 +126,9 @@ func (d *rawDescriptor) setExtra(v any) error {
return nil
}

// getExtra decodes the extra fields of d into v. If the encoding.BinaryUnmarshaler interface is
// implemented by v, it is used for unmarshaling. Otherwise, binary.Read() is used.
func (d *rawDescriptor) getExtra(v any) error {
if u, ok := v.(encoding.BinaryUnmarshaler); ok {
return u.UnmarshalBinary(d.Extra[:])
}
return binary.Read(bytes.NewReader(d.Extra[:]), binary.LittleEndian, v)
// getExtra unmarshals metadata from the "extra" field of d into md.
func (d *rawDescriptor) getExtra(md encoding.BinaryUnmarshaler) error {
return md.UnmarshalBinary(d.Extra[:])
}

// getPartitionMetadata gets metadata for a partition data object.
@@ -130,7 +139,7 @@ func (d rawDescriptor) getPartitionMetadata() (FSType, PartType, string, error)

var p partition

if err := d.getExtra(&p); err != nil {
if err := d.getExtra(binaryUnmarshaler{&p}); err != nil {
return 0, 0, "", err
}

@@ -189,10 +198,9 @@ func (d Descriptor) ModifiedAt() time.Time { return time.Unix(d.raw.ModifiedAt,
// Name returns the name of the data object.
func (d Descriptor) Name() string { return strings.TrimRight(string(d.raw.Name[:]), "\000") }

// GetMetadata reads metadata from d into v. If the encoding.BinaryUnmarshaler interface is
// implemented by v, it is used for unmarshaling. Otherwise, binary.Read() is used.
func (d Descriptor) GetMetadata(v any) error {
if err := d.raw.getExtra(v); err != nil {
// GetMetadata unmarshals metadata from the "extra" field of d into md.
func (d Descriptor) GetMetadata(md encoding.BinaryUnmarshaler) error {
if err := d.raw.getExtra(md); err != nil {
return fmt.Errorf("%w", err)
}
return nil
@@ -238,7 +246,7 @@ func (d Descriptor) SignatureMetadata() (ht crypto.Hash, fp []byte, err error) {

var s signature

if err := d.raw.getExtra(&s); err != nil {
if err := d.raw.getExtra(binaryUnmarshaler{&s}); err != nil {
return ht, fp, fmt.Errorf("%w", err)
}

@@ -265,7 +273,7 @@ func (d Descriptor) CryptoMessageMetadata() (FormatType, MessageType, error) {

var m cryptoMessage

if err := d.raw.getExtra(&m); err != nil {
if err := d.raw.getExtra(binaryUnmarshaler{&m}); err != nil {
return 0, 0, fmt.Errorf("%w", err)
}

@@ -280,7 +288,7 @@ func (d Descriptor) SBOMMetadata() (SBOMFormat, error) {

var s sbom

if err := d.raw.getExtra(&s); err != nil {
if err := d.raw.getExtra(binaryUnmarshaler{&s}); err != nil {
return 0, fmt.Errorf("%w", err)
}

20 changes: 10 additions & 10 deletions pkg/sif/descriptor_input.go
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ package sif

import (
"crypto"
"encoding"
"errors"
"fmt"
"io"
@@ -19,7 +20,7 @@ type descriptorOpts struct {
linkID uint32
alignment int
name string
extra any
md encoding.BinaryMarshaler
t time.Time
}

@@ -92,11 +93,10 @@ func OptObjectTime(t time.Time) DescriptorInputOpt {
}
}

// OptMetadata sets v as the metadata for a data object. If the encoding.BinaryMarshaler interface
// is implemented by v, it is used for marshaling. Otherwise, binary.Write() is used.
func OptMetadata(v any) DescriptorInputOpt {
// OptMetadata marshals metadata from md into the "extra" field of d.
func OptMetadata(md encoding.BinaryMarshaler) DescriptorInputOpt {
return func(t DataType, opts *descriptorOpts) error {
opts.extra = v
opts.md = md
return nil
}
}
@@ -164,7 +164,7 @@ func OptCryptoMessageMetadata(ft FormatType, mt MessageType) DescriptorInputOpt
Messagetype: mt,
}

opts.extra = m
opts.md = binaryMarshaler{m}
return nil
}
}
@@ -193,7 +193,7 @@ func OptPartitionMetadata(fs FSType, pt PartType, arch string) DescriptorInputOp
Arch: sifarch,
}

opts.extra = p
opts.md = p
return nil
}
}
@@ -230,7 +230,7 @@ func OptSignatureMetadata(ht crypto.Hash, fp []byte) DescriptorInputOpt {
}
copy(s.Entity[:], fp)

opts.extra = s
opts.md = binaryMarshaler{s}
return nil
}
}
@@ -248,7 +248,7 @@ func OptSBOMMetadata(f SBOMFormat) DescriptorInputOpt {
Format: f,
}

opts.extra = s
opts.md = binaryMarshaler{s}
return nil
}
}
@@ -327,5 +327,5 @@ func (di DescriptorInput) fillDescriptor(t time.Time, d *rawDescriptor) error {
return err
}

return d.setExtra(di.opts.extra)
return d.setExtra(di.opts.md)
}
8 changes: 4 additions & 4 deletions pkg/sif/descriptor_test.go
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ func TestDescriptor_GetMetadata(t *testing.T) {
tests := []struct {
name string
rd rawDescriptor
wantMD any
wantMD testMetadata
wantErr error
}{
{
@@ -261,7 +261,7 @@ func TestDescriptor_SignatureMetadata(t *testing.T) {
rd := rawDescriptor{
DataType: tt.dt,
}
if err := rd.setExtra(sig); err != nil {
if err := rd.setExtra(binaryMarshaler{sig}); err != nil {
t.Fatal(err)
}

@@ -295,7 +295,7 @@ func TestDescriptor_CryptoMessageMetadata(t *testing.T) {
rd := rawDescriptor{
DataType: DataCryptoMessage,
}
if err := rd.setExtra(m); err != nil {
if err := rd.setExtra(binaryMarshaler{m}); err != nil {
t.Fatal(err)
}

@@ -351,7 +351,7 @@ func TestDescriptor_SBOMMetadata(t *testing.T) {
rd := rawDescriptor{
DataType: DataSBOM,
}
if err := rd.setExtra(m); err != nil {
if err := rd.setExtra(binaryMarshaler{m}); err != nil {
t.Fatal(err)
}

0 comments on commit 6e2497e

Please sign in to comment.