1- // Copyright (c) 2018-2022 , Sylabs Inc. All rights reserved.
1+ // Copyright (c) 2018-2023 , Sylabs Inc. All rights reserved.
22// Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
33// Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
44// This software is licensed under a 3-clause BSD license. Please consult the
@@ -10,6 +10,7 @@ package sif
1010import (
1111"bytes"
1212"crypto"
13+ "encoding"
1314"encoding/binary"
1415"errors"
1516"fmt"
@@ -78,28 +79,49 @@ func (d *rawDescriptor) setName(name string) error {
7879
7980var errExtraTooLarge = errors .New ("extra value too large" )
8081
81- // setExtra encodes v into the extra field of d.
82- func (d * rawDescriptor ) setExtra (v interface {}) error {
82+ // setExtra encodes v into the extra field of d. If the encoding.BinaryMarshaler interface is
83+ // implemented by v, it is used for marshaling. Otherwise, binary.Write() is used.
84+ func (d * rawDescriptor ) setExtra (v any ) error {
8385if v == nil {
8486return nil
8587}
8688
87- if binary .Size (v ) > len (d .Extra ) {
88- return errExtraTooLarge
89+ var extra []byte
90+
91+ if m , ok := v .(encoding.BinaryMarshaler ); ok {
92+ b , err := m .MarshalBinary ()
93+ if err != nil {
94+ return err
95+ }
96+ extra = b
97+ } else {
98+ b := new (bytes.Buffer )
99+ if err := binary .Write (b , binary .LittleEndian , v ); err != nil {
100+ return err
101+ }
102+ extra = b .Bytes ()
89103}
90104
91- b := new (bytes.Buffer )
92- if err := binary .Write (b , binary .LittleEndian , v ); err != nil {
93- return err
105+ if len (extra ) > len (d .Extra ) {
106+ return errExtraTooLarge
94107}
95108
96- for i := copy (d .Extra [:], b . Bytes () ); i < len (d .Extra ); i ++ {
109+ for i := copy (d .Extra [:], extra ); i < len (d .Extra ); i ++ {
97110d .Extra [i ] = 0
98111}
99112
100113return nil
101114}
102115
116+ // getExtra decodes the extra fields of d into v. If the encoding.BinaryUnmarshaler interface is
117+ // implemented by v, it is used for unmarshaling. Otherwise, binary.Read() is used.
118+ func (d * rawDescriptor ) getExtra (v any ) error {
119+ if u , ok := v .(encoding.BinaryUnmarshaler ); ok {
120+ return u .UnmarshalBinary (d .Extra [:])
121+ }
122+ return binary .Read (bytes .NewReader (d .Extra [:]), binary .LittleEndian , v )
123+ }
124+
103125// getPartitionMetadata gets metadata for a partition data object.
104126func (d rawDescriptor ) getPartitionMetadata () (FSType , PartType , string , error ) {
105127if got , want := d .DataType , DataPartition ; got != want {
@@ -108,9 +130,8 @@ func (d rawDescriptor) getPartitionMetadata() (FSType, PartType, string, error)
108130
109131var p partition
110132
111- b := bytes .NewReader (d .Extra [:])
112- if err := binary .Read (b , binary .LittleEndian , & p ); err != nil {
113- return 0 , 0 , "" , fmt .Errorf ("%w" , err )
133+ if err := d .getExtra (& p ); err != nil {
134+ return 0 , 0 , "" , err
114135}
115136
116137return p .Fstype , p .Parttype , p .Arch .GoArch (), nil
@@ -168,11 +189,24 @@ func (d Descriptor) ModifiedAt() time.Time { return time.Unix(d.raw.ModifiedAt,
168189// Name returns the name of the data object.
169190func (d Descriptor ) Name () string { return strings .TrimRight (string (d .raw .Name [:]), "\000 " ) }
170191
192+ // GetMetadata reads metadata from d into v. If the encoding.BinaryUnmarshaler interface is
193+ // implemented by v, it is used for unmarshaling. Otherwise, binary.Read() is used.
194+ func (d Descriptor ) GetMetadata (v any ) error {
195+ if err := d .raw .getExtra (v ); err != nil {
196+ return fmt .Errorf ("%w" , err )
197+ }
198+ return nil
199+ }
200+
171201// PartitionMetadata gets metadata for a partition data object.
172202//
173203//nolint:nonamedreturns // Named returns effective as documentation.
174204func (d Descriptor ) PartitionMetadata () (fs FSType , pt PartType , arch string , err error ) {
175- return d .raw .getPartitionMetadata ()
205+ fs , pt , arch , err = d .raw .getPartitionMetadata ()
206+ if err != nil {
207+ return 0 , 0 , "" , fmt .Errorf ("%w" , err )
208+ }
209+ return fs , pt , arch , err
176210}
177211
178212var errHashUnsupported = errors .New ("hash algorithm unsupported" )
@@ -204,8 +238,7 @@ func (d Descriptor) SignatureMetadata() (ht crypto.Hash, fp []byte, err error) {
204238
205239var s signature
206240
207- b := bytes .NewReader (d .raw .Extra [:])
208- if err := binary .Read (b , binary .LittleEndian , & s ); err != nil {
241+ if err := d .raw .getExtra (& s ); err != nil {
209242return ht , fp , fmt .Errorf ("%w" , err )
210243}
211244
@@ -232,8 +265,7 @@ func (d Descriptor) CryptoMessageMetadata() (FormatType, MessageType, error) {
232265
233266var m cryptoMessage
234267
235- b := bytes .NewReader (d .raw .Extra [:])
236- if err := binary .Read (b , binary .LittleEndian , & m ); err != nil {
268+ if err := d .raw .getExtra (& m ); err != nil {
237269return 0 , 0 , fmt .Errorf ("%w" , err )
238270}
239271
@@ -248,8 +280,7 @@ func (d Descriptor) SBOMMetadata() (SBOMFormat, error) {
248280
249281var s sbom
250282
251- b := bytes .NewReader (d .raw .Extra [:])
252- if err := binary .Read (b , binary .LittleEndian , & s ); err != nil {
283+ if err := d .raw .getExtra (& s ); err != nil {
253284return 0 , fmt .Errorf ("%w" , err )
254285}
255286
0 commit comments