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_;
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));