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
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "device-path-util.h"
#include "util.h"
EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp) {
EFI_STATUS err;
EFI_DEVICE_PATH *dp;
assert(file);
assert(ret_dp);
err = BS->HandleProtocol(device, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp);
if (err != EFI_SUCCESS)
return err;
EFI_DEVICE_PATH *end_node = dp;
while (!device_path_is_end(end_node))
end_node = device_path_next_node(end_node);
size_t file_size = strsize16(file);
size_t dp_size = (uint8_t *) end_node - (uint8_t *) dp;
/* Make a copy that can also hold a file media device path. */
*ret_dp = xmalloc(dp_size + file_size + sizeof(FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH));
dp = mempcpy(*ret_dp, dp, dp_size);
FILEPATH_DEVICE_PATH *file_dp = (FILEPATH_DEVICE_PATH *) dp;
file_dp->Header = (EFI_DEVICE_PATH) {
.Type = MEDIA_DEVICE_PATH,
.SubType = MEDIA_FILEPATH_DP,
.Length = sizeof(FILEPATH_DEVICE_PATH) + file_size,
};
memcpy(file_dp->PathName, file, file_size);
dp = device_path_next_node(dp);
*dp = DEVICE_PATH_END_NODE;
return EFI_SUCCESS;
}
EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret) {
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *dp_to_text;
EFI_STATUS err;
_cleanup_free_ char16_t *str = NULL;
assert(dp);
assert(ret);
err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_DEVICE_PATH_TO_TEXT_PROTOCOL), NULL, (void **) &dp_to_text);
if (err != EFI_SUCCESS) {
/* If the device path to text protocol is not available we can still do a best-effort attempt
* to convert it ourselves if we are given filepath-only device path. */
size_t size = 0;
for (const EFI_DEVICE_PATH *node = dp; !device_path_is_end(node);
node = device_path_next_node(node)) {
if (node->Type != MEDIA_DEVICE_PATH || node->SubType != MEDIA_FILEPATH_DP)
return err;
size_t path_size = node->Length;
if (path_size <= offsetof(FILEPATH_DEVICE_PATH, PathName) || path_size % sizeof(char16_t))
return EFI_INVALID_PARAMETER;
path_size -= offsetof(FILEPATH_DEVICE_PATH, PathName);
_cleanup_free_ char16_t *old = str;
str = xmalloc(size + path_size);
if (old) {
memcpy(str, old, size);
str[size / sizeof(char16_t) - 1] = '\\';
}
memcpy(str + (size / sizeof(char16_t)),
((uint8_t *) node) + offsetof(FILEPATH_DEVICE_PATH, PathName),
path_size);
size += path_size;
}
*ret = TAKE_PTR(str);
return EFI_SUCCESS;
}
str = dp_to_text->ConvertDevicePathToText(dp, false, false);
if (!str)
return EFI_OUT_OF_RESOURCES;
*ret = TAKE_PTR(str);
return EFI_SUCCESS;
}
bool device_path_startswith(const EFI_DEVICE_PATH *dp, const EFI_DEVICE_PATH *start) {
if (!start)
return true;
if (!dp)
return false;
for (;;) {
if (device_path_is_end(start))
return true;
if (device_path_is_end(dp))
return false;
if (start->Length != dp->Length)
return false;
if (memcmp(dp, start, start->Length) != 0)
return false;
start = device_path_next_node(start);
dp = device_path_next_node(dp);
}
}
EFI_DEVICE_PATH *device_path_replace_node(
const EFI_DEVICE_PATH *path, const EFI_DEVICE_PATH *node, const EFI_DEVICE_PATH *new_node) {
/* Create a new device path as a copy of path, while chopping off the remainder starting at the given
* node. If new_node is provided, it is appended at the end of the new path. */
assert(path);
assert(node);
size_t len = (uint8_t *) node - (uint8_t *) path;
EFI_DEVICE_PATH *ret = xmalloc(len + (new_node ? new_node->Length : 0) + sizeof(EFI_DEVICE_PATH));
EFI_DEVICE_PATH *end = mempcpy(ret, path, len);
if (new_node)
end = mempcpy(end, new_node, new_node->Length);
*end = DEVICE_PATH_END_NODE;
return ret;
}
|