Various useful helpers (#41684)
Split out of #41543. These don't make too much sense on their own, but they also don't really hurt. They are preparation for #41543, but in order to make things either to review I split these four commits out, since they are not directly part of what the PR shall achieve
This commit is contained in:
@@ -83,6 +83,11 @@ static inline int safe_atou64(const char *s, uint64_t *ret_u) {
|
||||
return safe_atollu(s, (unsigned long long*) ret_u);
|
||||
}
|
||||
|
||||
static inline int safe_atou64_full(const char *s, unsigned base, uint64_t *ret_u) {
|
||||
assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
|
||||
return safe_atollu_full(s, base, (unsigned long long*) ret_u);
|
||||
}
|
||||
|
||||
static inline int safe_atoi64(const char *s, int64_t *ret_i) {
|
||||
assert_cc(sizeof(int64_t) == sizeof(long long));
|
||||
return safe_atolli(s, (long long*) ret_i);
|
||||
|
||||
@@ -898,3 +898,20 @@ mode_t inode_type_from_string(const char *s) {
|
||||
|
||||
return MODE_INVALID;
|
||||
}
|
||||
|
||||
int vfs_free_bytes(int fd, uint64_t *ret) {
|
||||
assert(fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
/* Safely returns the current available disk space (for root, i.e. including any space reserved for
|
||||
* root) of the disk referenced by the fd, converted to bytes. */
|
||||
|
||||
struct statvfs sv;
|
||||
if (fstatvfs(fd, &sv) < 0)
|
||||
return -errno;
|
||||
|
||||
if (!MUL_SAFE(ret, (uint64_t) sv.f_frsize, (uint64_t) sv.f_bfree))
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -161,3 +161,5 @@ static inline bool inode_type_can_hardlink(mode_t m) {
|
||||
* type). */
|
||||
return IN_SET(m & S_IFMT, S_IFSOCK, S_IFLNK, S_IFREG, S_IFBLK, S_IFCHR, S_IFIFO);
|
||||
}
|
||||
|
||||
int vfs_free_bytes(int fd, uint64_t *ret);
|
||||
|
||||
+17
-2
@@ -1519,17 +1519,32 @@ char* strrstr_internal(const char *haystack, const char *needle) {
|
||||
|
||||
/* Special case: for the empty string we return the very last possible occurrence, i.e. *after* the
|
||||
* last char, not before. */
|
||||
if (*needle == 0)
|
||||
if (needle[0] == 0)
|
||||
return (char*) strchr(haystack, 0);
|
||||
|
||||
/* Special case: for single character strings, just use optimized strrchr() */
|
||||
if (needle[1] == 0)
|
||||
return (char*) strrchr(haystack, needle[0]);
|
||||
|
||||
for (const char *p = strstr(haystack, needle), *q; p; p = q) {
|
||||
q = strstr(p + 1, needle);
|
||||
if (!q)
|
||||
return (char *) p;
|
||||
return (char*) p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* strrstr_no_case_internal(const char *haystack, const char *needle) {
|
||||
if (!haystack || !needle)
|
||||
return NULL;
|
||||
|
||||
for (const char *p = strchr(haystack, 0); p > haystack; p--)
|
||||
if (startswith_no_case(p, needle))
|
||||
return (char*) p;
|
||||
|
||||
return startswith_no_case(haystack, needle) ? (char*) haystack : NULL;
|
||||
}
|
||||
|
||||
size_t str_common_prefix(const char *a, const char *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
@@ -312,4 +312,8 @@ char* strrstr_internal(const char *haystack, const char *needle) _pure_;
|
||||
#define strrstr(haystack, needle) \
|
||||
const_generic(haystack, strrstr_internal(haystack, needle))
|
||||
|
||||
char* strrstr_no_case_internal(const char *haystack, const char *needle) _pure_;
|
||||
#define strrstr_no_case(haystack, needle) \
|
||||
const_generic(haystack, strrstr_no_case_internal(haystack, needle))
|
||||
|
||||
size_t str_common_prefix(const char *a, const char *b) _pure_;
|
||||
|
||||
@@ -305,7 +305,6 @@ static int save_external_coredump(
|
||||
if (storage_on_tmpfs && config->compress) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
uint64_t cgroup_limit = UINT64_MAX;
|
||||
struct statvfs sv;
|
||||
|
||||
/* If we can't get the cgroup limit, just ignore it, but don't fail,
|
||||
* try anyway with the config settings. */
|
||||
@@ -335,8 +334,9 @@ static int save_external_coredump(
|
||||
/* tmpfs might get full quickly, so check the available space too. But don't worry about
|
||||
* errors here, failing to access the storage location will be better logged when writing to
|
||||
* it. */
|
||||
if (fstatvfs(fd, &sv) >= 0)
|
||||
max_size = MIN((uint64_t)sv.f_frsize * (uint64_t)sv.f_bfree, max_size);
|
||||
uint64_t free_bytes;
|
||||
if (vfs_free_bytes(fd, &free_bytes) >= 0)
|
||||
max_size = MIN(free_bytes, max_size);
|
||||
/* Impose a lower minimum, otherwise we will miss the basic headers. */
|
||||
max_size = MAX(PROCESS_SIZE_MIN, max_size);
|
||||
/* Ensure we can always switch to compressing on the fly in case we are running out of space
|
||||
|
||||
@@ -535,6 +535,29 @@ TEST(endswith_no_case) {
|
||||
assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO"));
|
||||
}
|
||||
|
||||
TEST(strrstr_no_case) {
|
||||
ASSERT_STREQ(strrstr_no_case("fooBARfoobar", "bar"), "bar");
|
||||
ASSERT_STREQ(strrstr_no_case("fooBARfoobar", "BAR"), "bar");
|
||||
ASSERT_STREQ(strrstr_no_case("fooBARfoobar", "bAR"), "bar");
|
||||
ASSERT_STREQ(strrstr_no_case("fooBARfoobar", "FOO"), "foobar");
|
||||
ASSERT_STREQ(strrstr_no_case("fooBARfoobar", "foo"), "foobar");
|
||||
ASSERT_STREQ(strrstr_no_case("fooBARfoobar", "FoO"), "foobar");
|
||||
ASSERT_STREQ(strrstr_no_case("aXaXa", "x"), "Xa");
|
||||
ASSERT_STREQ(strrstr_no_case("aXaXa", "X"), "Xa");
|
||||
ASSERT_STREQ(strrstr_no_case("xHello", "hello"), "Hello");
|
||||
ASSERT_STREQ(strrstr_no_case("Hello", "l"), "lo");
|
||||
ASSERT_STREQ(strrstr_no_case("Hello", ""), "");
|
||||
ASSERT_STREQ(strrstr_no_case("", ""), "");
|
||||
ASSERT_STREQ(strrstr_no_case("FOO", "foo"), "FOO");
|
||||
ASSERT_STREQ(strrstr_no_case("hello", "hello"), "hello");
|
||||
ASSERT_STREQ(strrstr_no_case("X", "x"), "X");
|
||||
|
||||
ASSERT_NULL(strrstr_no_case("hello", "xyz"));
|
||||
ASSERT_NULL(strrstr_no_case("", "x"));
|
||||
ASSERT_NULL(strrstr_no_case(NULL, "x"));
|
||||
ASSERT_NULL(strrstr_no_case("x", NULL));
|
||||
}
|
||||
|
||||
TEST(delete_chars) {
|
||||
char *s, input[] = " hello, waldo. abc";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user