]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/efi-string.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "efi-string.h"
10 # define xmalloc(n) xallocate_pool(n)
14 # define xmalloc(n) ASSERT_SE_PTR(malloc(n))
17 /* String functions for both char and char16_t that should behave the same way as their respective
18 * counterpart in userspace. Where it makes sense, these accept NULL and do something sensible whereas
19 * userspace does not allow for this (strlen8(NULL) returns 0 like strlen_ptr(NULL) for example). To make it
20 * easier to tell in code which kind of string they work on, we use 8/16 suffixes. This also makes is easier
21 * to unit test them. */
23 #define DEFINE_STRNLEN(type, name) \
24 size_t name(const type *s, size_t n) { \
29 while (len < n && *s) { \
37 DEFINE_STRNLEN(char, strnlen8
);
38 DEFINE_STRNLEN(char16_t
, strnlen16
);
43 (_c >= 'A' && _c <= 'Z') ? _c + ('a' - 'A') : _c; \
46 #define DEFINE_STRTOLOWER(type, name) \
47 void name(type *s) { \
54 DEFINE_STRTOLOWER(char, strtolower8
);
55 DEFINE_STRTOLOWER(char16_t
, strtolower16
);
57 #define DEFINE_STRNCASECMP(type, name, tolower) \
58 int name(const type *s1, const type *s2, size_t n) { \
63 type c1 = *s1, c2 = *s2; \
68 if (!c1 || c1 != c2) \
79 DEFINE_STRNCASECMP(char, strncmp8
, false);
80 DEFINE_STRNCASECMP(char16_t
, strncmp16
, false);
81 DEFINE_STRNCASECMP(char, strncasecmp8
, true);
82 DEFINE_STRNCASECMP(char16_t
, strncasecmp16
, true);
84 #define DEFINE_STRCPY(type, name) \
85 type *name(type * restrict dest, const type * restrict src) { \
104 DEFINE_STRCPY(char, strcpy8
);
105 DEFINE_STRCPY(char16_t
, strcpy16
);
107 #define DEFINE_STRCHR(type, name) \
108 type *name(const type *s, type c) { \
121 DEFINE_STRCHR(char, strchr8
);
122 DEFINE_STRCHR(char16_t
, strchr16
);
124 #define DEFINE_STRNDUP(type, name, len_func) \
125 type *name(const type *s, size_t n) { \
129 size_t len = len_func(s, n); \
130 size_t size = len * sizeof(type); \
132 type *dup = xmalloc(size + sizeof(type)); \
133 efi_memcpy(dup, s, size); \
139 DEFINE_STRNDUP(char, xstrndup8
, strnlen8
);
140 DEFINE_STRNDUP(char16_t
, xstrndup16
, strnlen16
);
142 /* Patterns are fnmatch-compatible (with reduced feature support). */
143 static bool efi_fnmatch_internal(const char16_t
*p
, const char16_t
*h
, int max_depth
) {
153 /* End of pattern. Check that haystack is now empty. */
158 if (*p
== '\0' || *p
!= *h
)
159 /* Trailing escape or no match. */
165 /* Early end of haystack. */
170 /* No need to recurse for consecutive '*'. */
175 /* Try matching haystack with remaining pattern. */
176 if (efi_fnmatch_internal(p
, h
, max_depth
- 1))
179 /* Otherwise, we match one char here. */
181 } while (*h
!= '\0');
183 /* End of haystack. Pattern needs to be empty too for a match. */
188 /* Early end of haystack. */
191 bool first
= true, can_range
= true, match
= false;
192 for (;; first
= false) {
206 /* End of set unless it's the first char. */
207 if (*p
== ']' && !first
)
210 /* Range pattern if '-' is not first or last in set. */
211 if (*p
== '-' && can_range
&& !first
&& *(p
+ 1) != ']') {
212 char16_t low
= *(p
- 1);
219 if (low
<= *h
&& *h
<= *p
)
222 /* Ranges cannot be chained: [a-c-f] == [-abcf] */
238 /* Single char mismatch. */
243 bool efi_fnmatch(const char16_t
*pattern
, const char16_t
*haystack
) {
244 return efi_fnmatch_internal(pattern
, haystack
, 32);
247 int efi_memcmp(const void *p1
, const void *p2
, size_t n
) {
248 const uint8_t *up1
= p1
, *up2
= p2
;
267 void *efi_memcpy(void * restrict dest
, const void * restrict src
, size_t n
) {
268 if (!dest
|| !src
|| n
== 0)
272 const uint8_t *s
= src
;
284 void *efi_memset(void *p
, int c
, size_t n
) {
302 /* Provide the actual implementation for the builtins. To prevent a linker error, we mark memcpy/memset as
303 * weak, because gnu-efi is currently providing them. */
304 __attribute__((alias("efi_memcmp"))) int memcmp(const void *p1
, const void *p2
, size_t n
);
305 __attribute__((weak
, alias("efi_memcpy"))) void *memcpy(void * restrict dest
, const void * restrict src
, size_t n
);
306 __attribute__((weak
, alias("efi_memset"))) void *memset(void *p
, int c
, size_t n
);