File: loadoption.go

package info (click to toggle)
golang-github-canonical-go-efilib 1.6.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,836 kB
  • sloc: makefile: 3
file content (135 lines) | stat: -rw-r--r-- 4,055 bytes parent folder | download
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
}