[PATCH v2 089/113] efi: devicepath: implement device_path_to_str_buf variant
Ahmad Fatoum
a.fatoum at pengutronix.de
Mon Mar 4 11:00:14 PST 2024
Existing device_path_to_str() formats a buffer once to determines the amount
of space necessary and then allocates it and formats it again.
To make this functionality available as printf format specifier, we need
a variant that doesn't allocate memory and that's preferably single
pass, which we add here.
No functional change for users of device_path_to_str().
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
efi/devicepath.c | 71 +++++++++++++++++++++++++++++++++++-------------
include/efi.h | 1 +
2 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/efi/devicepath.c b/efi/devicepath.c
index d562bf482955..0c2fc4d86927 100644
--- a/efi/devicepath.c
+++ b/efi/devicepath.c
@@ -6,11 +6,13 @@
#include <malloc.h>
#include <string.h>
#include <wchar.h>
+#include <linux/overflow.h>
#include <efi/device-path.h>
struct string {
char *str;
- int len;
+ unsigned allocated;
+ unsigned used;
};
char *cprintf(struct string *str, const char *fmt, ...)
@@ -18,17 +20,22 @@ char *cprintf(struct string *str, const char *fmt, ...)
char *cprintf(struct string *str, const char *fmt, ...)
{
+ void *buf = str->str;
+ unsigned bufsize = 0;
va_list args;
int len;
+ if (str->str) {
+ buf += str->used;
+ if (check_sub_overflow(str->allocated, str->used, &bufsize))
+ bufsize = 0;
+ }
+
va_start(args, fmt);
- if (str->str)
- len = vsprintf(str->str + str->len, fmt, args);
- else
- len = vsnprintf(NULL, 0, fmt, args);
+ len = vsnprintf(buf, bufsize, fmt, args);
va_end(args);
- str->len += len;
+ str->used += len;
return NULL;
}
@@ -717,8 +724,8 @@ struct {
0, 0, NULL}
};
-static int __device_path_to_str(struct string *str,
- const struct efi_device_path *dev_path)
+static void __device_path_to_str(struct string *str,
+ const struct efi_device_path *dev_path)
{
const struct efi_device_path *dev_path_node;
void (*dump_node) (struct string *, const void *);
@@ -743,32 +750,58 @@ static int __device_path_to_str(struct string *str,
if (!dump_node)
dump_node = dev_path_node_unknown;
- if (str->len && dump_node != dev_path_end_instance)
+ if (str->used && dump_node != dev_path_end_instance)
cprintf(str, "/");
dump_node(str, dev_path_node);
dev_path_node = next_device_path_node(dev_path_node);
}
-
- return 0;
}
+/**
+ * device_path_to_str_buf() - formats a device path into a preallocated buffer
+ *
+ * @dev_path: The EFI device path to format
+ * @buf: The buffer to format into or optionally NULL if @len is zero
+ * @len: The number of bytes that may be written into @buf
+ * Return: total number of bytes that are required to store the formatted
+ * result, excluding the terminating NUL byte, which is always
+ * written.
+ */
+size_t device_path_to_str_buf(const struct efi_device_path *dev_path,
+ char *buf, size_t len)
+{
+ struct string str = {
+ .str = buf,
+ .allocated = len,
+ };
+
+ __device_path_to_str(&str, dev_path);
+
+ return str.used;
+}
+
+/**
+ * device_path_to_str() - formats a device path into a newly allocated buffer
+ *
+ * @dev_path: The EFI device path to format
+ * Return: A pointer to the nul-terminated formatted device path.
+ */
char *device_path_to_str(const struct efi_device_path *dev_path)
{
- struct string str = {};
+ void *buf;
+ size_t size;
- __device_path_to_str(&str, dev_path);
+ size = device_path_to_str_buf(dev_path, NULL, 0);
- str.str = malloc(str.len + 1);
- if (!str.str)
+ buf = malloc(size + 1);
+ if (!buf)
return NULL;
- str.len = 0;
+ device_path_to_str_buf(dev_path, buf, size + 1);
- __device_path_to_str(&str, dev_path);
-
- return str.str;
+ return buf;
}
u8 device_path_to_type(const struct efi_device_path *dev_path)
diff --git a/include/efi.h b/include/efi.h
index 6795dc414c3c..45e4080fac08 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -880,6 +880,7 @@ struct efi_simple_text_input_protocol {
const struct efi_device_path *device_path_from_handle(efi_handle_t handle);
char *device_path_to_str(const struct efi_device_path *dev_path);
+size_t device_path_to_str_buf(const struct efi_device_path *dev_path, char buf[], size_t size);
u8 device_path_to_type(const struct efi_device_path *dev_path);
u8 device_path_to_subtype(const struct efi_device_path *dev_path);
char *device_path_to_partuuid(const struct efi_device_path *dev_path);
--
2.39.2
More information about the barebox
mailing list