boot: Add xstrdup8/16
This commit is contained in:
+1
-1
@@ -255,7 +255,7 @@ static EFI_STATUS pack_cpio_prefix(
|
||||
if (e > p) {
|
||||
_cleanup_freepool_ CHAR8 *t = NULL;
|
||||
|
||||
t = xstrndup8(path, e - path);
|
||||
t = (CHAR8 *) xstrndup8((const char *) path, e - path);
|
||||
if (!t)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
|
||||
#include "efi-string.h"
|
||||
|
||||
#ifdef SD_BOOT
|
||||
# include "util.h"
|
||||
# define xmalloc(n) xallocate_pool(n)
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# include "macro.h"
|
||||
# define xmalloc(n) ASSERT_SE_PTR(malloc(n))
|
||||
#endif
|
||||
|
||||
/* String functions for both char and char16_t that should behave the same way as their respective
|
||||
* counterpart in userspace. Where it makes sense, these accept NULL and do something sensible whereas
|
||||
* userspace does not allow for this (strlen8(NULL) returns 0 like strlen_ptr(NULL) for example). To make it
|
||||
@@ -138,6 +147,32 @@ DEFINE_STRCPY(char16_t, strcpy16);
|
||||
DEFINE_STRCHR(char, strchr8);
|
||||
DEFINE_STRCHR(char16_t, strchr16);
|
||||
|
||||
#define DEFINE_STRNDUP(type, name, len_func) \
|
||||
type *name(const type *s, size_t n) { \
|
||||
if (!s) \
|
||||
return NULL; \
|
||||
\
|
||||
size_t len = len_func(s, n); \
|
||||
size_t size = len * sizeof(type); \
|
||||
\
|
||||
type *dup = xmalloc(size + sizeof(type)); \
|
||||
efi_memcpy(dup, s, size); \
|
||||
dup[len] = '\0'; \
|
||||
\
|
||||
return dup; \
|
||||
}
|
||||
|
||||
DEFINE_STRNDUP(char, xstrndup8, strnlen8);
|
||||
DEFINE_STRNDUP(char16_t, xstrndup16, strnlen16);
|
||||
|
||||
char *xstrdup8(const char *s) {
|
||||
return xstrndup8(s, SIZE_MAX);
|
||||
}
|
||||
|
||||
char16_t *xstrdup16(const char16_t *s) {
|
||||
return xstrndup16(s, SIZE_MAX);
|
||||
}
|
||||
|
||||
int efi_memcmp(const void *p1, const void *p2, size_t n) {
|
||||
if (!p1 || !p2)
|
||||
return CMP(p1, p2);
|
||||
|
||||
@@ -74,6 +74,12 @@ char16_t *strcpy16(char16_t * restrict dest, const char16_t * restrict src);
|
||||
char *strchr8(const char *s, char c);
|
||||
char16_t *strchr16(const char16_t *s, char16_t c);
|
||||
|
||||
char *xstrndup8(const char *s, size_t n);
|
||||
char16_t *xstrndup16(const char16_t *s, size_t n);
|
||||
|
||||
char *xstrdup8(const char *s);
|
||||
char16_t *xstrdup16(const char16_t *s);
|
||||
|
||||
#ifdef SD_BOOT
|
||||
/* The compiler normaly has knowledge about standard functions such as memcmp, but this is not the case when
|
||||
* compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do
|
||||
|
||||
@@ -240,6 +240,88 @@ TEST(strchr16) {
|
||||
assert_se(strchr16(str, 'B') == &str[4]);
|
||||
}
|
||||
|
||||
TEST(xstrndup8) {
|
||||
char *s = NULL;
|
||||
|
||||
assert_se(xstrndup8(NULL, 0) == NULL);
|
||||
assert_se(xstrndup8(NULL, 10) == NULL);
|
||||
|
||||
assert_se(s = xstrndup8("", 10));
|
||||
assert_se(streq8(s, ""));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrndup8("abc", 0));
|
||||
assert_se(streq8(s, ""));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrndup8("ABC", 3));
|
||||
assert_se(streq8(s, "ABC"));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrndup8("123abcDEF", 5));
|
||||
assert_se(streq8(s, "123ab"));
|
||||
free(s);
|
||||
}
|
||||
|
||||
TEST(xstrdup8) {
|
||||
char *s = NULL;
|
||||
|
||||
assert_se(xstrdup8(NULL) == NULL);
|
||||
|
||||
assert_se(s = xstrdup8(""));
|
||||
assert_se(streq8(s, ""));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrdup8("1"));
|
||||
assert_se(streq8(s, "1"));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrdup8("123abcDEF"));
|
||||
assert_se(streq8(s, "123abcDEF"));
|
||||
free(s);
|
||||
}
|
||||
|
||||
TEST(xstrndup16) {
|
||||
char16_t *s = NULL;
|
||||
|
||||
assert_se(xstrndup16(NULL, 0) == NULL);
|
||||
assert_se(xstrndup16(NULL, 10) == NULL);
|
||||
|
||||
assert_se(s = xstrndup16(u"", 10));
|
||||
assert_se(streq16(s, u""));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrndup16(u"abc", 0));
|
||||
assert_se(streq16(s, u""));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrndup16(u"ABC", 3));
|
||||
assert_se(streq16(s, u"ABC"));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrndup16(u"123abcDEF", 5));
|
||||
assert_se(streq16(s, u"123ab"));
|
||||
free(s);
|
||||
}
|
||||
|
||||
TEST(xstrdup16) {
|
||||
char16_t *s = NULL;
|
||||
|
||||
assert_se(xstrdup16(NULL) == NULL);
|
||||
|
||||
assert_se(s = xstrdup16(u""));
|
||||
assert_se(streq16(s, u""));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrdup16(u"1"));
|
||||
assert_se(streq16(s, u"1"));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrdup16(u"123abcDEF"));
|
||||
assert_se(streq16(s, u"123abcDEF"));
|
||||
free(s);
|
||||
}
|
||||
|
||||
TEST(efi_memcmp) {
|
||||
assert_se(efi_memcmp(NULL, NULL, 0) == 0);
|
||||
assert_se(efi_memcmp(NULL, NULL, 1) == 0);
|
||||
|
||||
@@ -552,26 +552,6 @@ EFI_STATUS readdir_harder(
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
CHAR8 *xstrndup8(const CHAR8 *p, UINTN sz) {
|
||||
CHAR8 *n;
|
||||
|
||||
/* Following efilib's naming scheme this function would be called strndupa(), but we already have a
|
||||
* function named like this in userspace, and it does something different there, hence to minimize
|
||||
* confusion, let's pick a different name here */
|
||||
|
||||
assert(p || sz == 0);
|
||||
|
||||
sz = strnlen8((const char *) p, sz);
|
||||
|
||||
n = xallocate_pool(sz + 1);
|
||||
|
||||
if (sz > 0)
|
||||
memcpy(n, p, sz);
|
||||
n[sz] = 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
BOOLEAN is_ascii(const CHAR16 *f) {
|
||||
if (!f)
|
||||
return FALSE;
|
||||
|
||||
@@ -119,8 +119,6 @@ EFI_STATUS get_file_info_harder(EFI_FILE *handle, EFI_FILE_INFO **ret, UINTN *re
|
||||
|
||||
EFI_STATUS readdir_harder(EFI_FILE *handle, EFI_FILE_INFO **buffer, UINTN *buffer_size);
|
||||
|
||||
CHAR8 *xstrndup8(const CHAR8 *p, UINTN sz);
|
||||
|
||||
BOOLEAN is_ascii(const CHAR16 *f);
|
||||
|
||||
CHAR16 **strv_free(CHAR16 **l);
|
||||
|
||||
Reference in New Issue
Block a user