1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// Copyright 2021 Canonical Ltd.
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
package efi
import (
"bytes"
"errors"
"fmt"
"io"
"math"
"github.com/canonical/go-efilib/internal/uefi"
)
// LoadOptionAttributes corresponds to the attributes of a load option
type LoadOptionAttributes uint32
const (
LoadOptionActive LoadOptionAttributes = uefi.LOAD_OPTION_ACTIVE
LoadOptionForceReconnect LoadOptionAttributes = uefi.LOAD_OPTION_FORCE_RECONNECT
LoadOptionHidden LoadOptionAttributes = uefi.LOAD_OPTION_HIDDEN
LoadOptionCategory LoadOptionAttributes = uefi.LOAD_OPTION_CATEGORY
LoadOptionCategoryBoot LoadOptionAttributes = uefi.LOAD_OPTION_CATEGORY_BOOT
LoadOptionCategoryApp LoadOptionAttributes = uefi.LOAD_OPTION_CATEGORY_APP
)
// IsBootCategory indicates whether the attributes has the LOAD_OPTION_CATEGORY_BOOT
// flag set. These applications are typically part of the boot process.
func (a LoadOptionAttributes) IsBootCategory() bool {
return a&LoadOptionCategory == LoadOptionCategoryBoot
}
// IsAppCategory indicates whether the attributes has the LOAD_OPTION_CATEGORY_APP
// flag set.
func (a LoadOptionAttributes) IsAppCategory() bool {
return a&LoadOptionCategory == LoadOptionCategoryApp
}
// LoadOption corresponds to the EFI_LOAD_OPTION type.
type LoadOption struct {
Attributes LoadOptionAttributes
Description string
FilePath DevicePath
OptionalData []byte
}
// String implements [fmt.Stringer].
func (o *LoadOption) String() string {
return fmt.Sprintf(`EFI_LOAD_OPTION {
Attributes: %d,
Description: %q,
FilePath: %s,
OptionalData: %x,
}`, o.Attributes, o.Description, o.FilePath, o.OptionalData)
}
// Bytes returns the serialized form of this load option.
func (o *LoadOption) Bytes() ([]byte, error) {
var buf bytes.Buffer
if err := o.Write(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// Write serializes this load option to the supplied io.Writer.
func (o *LoadOption) Write(w io.Writer) error {
opt := uefi.EFI_LOAD_OPTION{
Attributes: uint32(o.Attributes),
Description: ConvertUTF8ToUCS2(o.Description + "\x00"),
OptionalData: o.OptionalData}
var dp bytes.Buffer
if err := o.FilePath.Write(&dp); err != nil {
return err
}
if dp.Len() > math.MaxUint16 {
return errors.New("FilePath too long")
}
opt.FilePathList = dp.Bytes()
opt.FilePathListLength = uint16(dp.Len())
return opt.Write(w)
}
// IsActive indicates whether the attributes has the LOAD_OPTION_ACTIVE flag set.
// These will be tried automatically if they are in BootOrder.
func (o *LoadOption) IsActive() bool {
return o.Attributes&LoadOptionActive > 0
}
// IsVisible indicates whether the attributes does not have the LOAD_OPTION_HIDDEN
// flag set.
func (o *LoadOption) IsVisible() bool {
return o.Attributes&LoadOptionHidden == 0
}
// IsBootCategory indicates whether the attributes has the LOAD_OPTION_CATEGORY_BOOT
// flag set. These applications are typically part of the boot process.
func (o *LoadOption) IsBootCategory() bool {
return o.Attributes.IsBootCategory()
}
// IsAppCategory indicates whether the attributes has the LOAD_OPTION_CATEGORY_APP
// flag set.
func (o *LoadOption) IsAppCategory() bool {
return o.Attributes.IsAppCategory()
}
// ReadLoadOption reads a LoadOption from the supplied io.Reader. Due to the
// way that EFI_LOAD_OPTION is defined, where there is no size encoded for the
// OptionalData field, this function will consume all of the bytes available
// from the supplied reader.
func ReadLoadOption(r io.Reader) (out *LoadOption, err error) {
opt, err := uefi.Read_EFI_LOAD_OPTION(r)
if err != nil {
return nil, err
}
out = &LoadOption{
Attributes: LoadOptionAttributes(opt.Attributes),
Description: ConvertUTF16ToUTF8(opt.Description),
OptionalData: opt.OptionalData}
dp, err := ReadDevicePath(bytes.NewReader(opt.FilePathList))
if err != nil {
return nil, fmt.Errorf("cannot read device path: %w", err)
}
out.FilePath = dp
return out, nil
}
|