string-util: introduce STRING_FILENAME_PART flag for string_is_safe()

Whenever we are validating a string that shall appear in a filename
eventually we want to use filename_part_is_valid() rather than file
filename_is_valid(). Let's add explicit support for that to
string_is_safe(), since it's actually a really common case.
This commit is contained in:
Lennart Poettering
2026-06-22 14:41:16 +02:00
parent 90d285ade7
commit dbd35fdc81
3 changed files with 19 additions and 1 deletions
+3
View File
@@ -1139,6 +1139,9 @@ bool string_is_safe(const char *p, StringSafeFlags flags) {
if (FLAGS_SET(flags, STRING_FILENAME) && !filename_is_valid(p))
return false;
if (FLAGS_SET(flags, STRING_FILENAME_PART) && !filename_part_is_valid(p))
return false;
return true;
}
+2 -1
View File
@@ -229,7 +229,8 @@ typedef enum StringSafeFlags {
STRING_ALLOW_QUOTES = 1 << 4, /* Allow quotes (" or ') */
STRING_ALLOW_GLOBS = 1 << 5, /* Allow globs (?, * or [) */
STRING_FILENAME = 1 << 6, /* Verify the string is valid as regular filename */
STRING_DISALLOW_WHITESPACE = 1 << 7, /* Refuse whitespace (space, tab, newline, …) */
STRING_FILENAME_PART = 1 << 7, /* Verify the string is valid as part of a regular filename */
STRING_DISALLOW_WHITESPACE = 1 << 8, /* Refuse whitespace (space, tab, newline, …) */
} StringSafeFlags;
bool string_is_safe(const char *p, StringSafeFlags flags) _pure_;
+14
View File
@@ -1622,6 +1622,20 @@ TEST(string_is_safe) {
ASSERT_TRUE(string_is_safe("a\nb", STRING_ALLOW_NEWLINES));
ASSERT_FALSE(string_is_safe("a\nb", STRING_ALLOW_NEWLINES | STRING_DISALLOW_WHITESPACE));
/* STRING_FILENAME_PART: like STRING_FILENAME, but "." and ".." are accepted; '/' still rejected. */
ASSERT_TRUE(string_is_safe("hello", STRING_FILENAME_PART));
ASSERT_TRUE(string_is_safe("hello.txt", STRING_FILENAME_PART));
ASSERT_TRUE(string_is_safe("...", STRING_FILENAME_PART));
ASSERT_TRUE(string_is_safe(".hidden", STRING_FILENAME_PART));
ASSERT_TRUE(string_is_safe(".", STRING_FILENAME_PART)); /* accepted, unlike STRING_FILENAME */
ASSERT_TRUE(string_is_safe("..", STRING_FILENAME_PART)); /* accepted, unlike STRING_FILENAME */
ASSERT_FALSE(string_is_safe("", STRING_FILENAME_PART)); /* empty still rejected by default */
ASSERT_TRUE(string_is_safe("", STRING_FILENAME_PART | STRING_ALLOW_EMPTY)); /* ... unless explicitly allowed */
ASSERT_FALSE(string_is_safe("/", STRING_FILENAME_PART));
ASSERT_FALSE(string_is_safe("/foo", STRING_FILENAME_PART));
ASSERT_FALSE(string_is_safe("foo/bar", STRING_FILENAME_PART));
ASSERT_FALSE(string_is_safe("foo/", STRING_FILENAME_PART));
/* Pairwise combinations. */
ASSERT_TRUE(string_is_safe("", STRING_ALLOW_EMPTY | STRING_ASCII));
ASSERT_FALSE(string_is_safe("über", STRING_ALLOW_EMPTY | STRING_ASCII));