From dd748dbede1a36f1e929461ecbfcde749eb685bb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 1 Nov 2021 13:04:40 -0400 Subject: fs_path: make empty component validation optional --- src/fs_path.c | 5 ++++- src/fs_path.h | 5 ++++- tests/path/core.c | 43 ++++++++++++++++++++++++++++++------------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/fs_path.c b/src/fs_path.c index fa27a6e73..483b21c1e 100644 --- a/src/fs_path.c +++ b/src/fs_path.c @@ -1599,7 +1599,7 @@ static bool validate_component( unsigned int flags) { if (len == 0) - return false; + return !(flags & GIT_FS_PATH_REJECT_EMPTY_COMPONENT); if ((flags & GIT_FS_PATH_REJECT_TRAVERSAL) && len == 1 && component[0] == '.') @@ -1644,6 +1644,9 @@ bool git_fs_path_is_valid_str_ext( const char *start, *c; size_t len = 0; + if (!flags) + return true; + for (start = c = path->ptr; *c && len < path->size; c++, len++) { if (!validate_char(*c, flags)) return false; diff --git a/src/fs_path.h b/src/fs_path.h index 2f4bc9f79..275b3d857 100644 --- a/src/fs_path.h +++ b/src/fs_path.h @@ -591,7 +591,8 @@ extern bool git_fs_path_is_local_file_url(const char *file_url); extern int git_fs_path_from_url_or_path(git_str *local_path_out, const char *url_or_path); /* Flags to determine path validity in `git_fs_path_isvalid` */ -#define GIT_FS_PATH_REJECT_TRAVERSAL (1 << 0) +#define GIT_FS_PATH_REJECT_EMPTY_COMPONENT (1 << 0) +#define GIT_FS_PATH_REJECT_TRAVERSAL (1 << 1) #define GIT_FS_PATH_REJECT_SLASH (1 << 2) #define GIT_FS_PATH_REJECT_BACKSLASH (1 << 3) #define GIT_FS_PATH_REJECT_TRAILING_DOT (1 << 4) @@ -608,6 +609,7 @@ extern int git_fs_path_from_url_or_path(git_str *local_path_out, const char *url */ #ifdef GIT_WIN32 # define GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS \ + GIT_FS_PATH_REJECT_EMPTY_COMPONENT | \ GIT_FS_PATH_REJECT_TRAVERSAL | \ GIT_FS_PATH_REJECT_BACKSLASH | \ GIT_FS_PATH_REJECT_TRAILING_DOT | \ @@ -617,6 +619,7 @@ extern int git_fs_path_from_url_or_path(git_str *local_path_out, const char *url GIT_FS_PATH_REJECT_NT_CHARS #else # define GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS \ + GIT_FS_PATH_REJECT_EMPTY_COMPONENT | \ GIT_FS_PATH_REJECT_TRAVERSAL #endif diff --git a/tests/path/core.c b/tests/path/core.c index 6fa0450ca..ccb328b10 100644 --- a/tests/path/core.c +++ b/tests/path/core.c @@ -68,41 +68,58 @@ void test_path_core__isvalid_standard(void) void test_path_core__isvalid_standard_str(void) { git_str str = GIT_STR_INIT_CONST("foo/bar//zap", 0); + unsigned int flags = GIT_FS_PATH_REJECT_EMPTY_COMPONENT; str.size = 0; - cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, 0)); + cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, flags)); str.size = 3; - cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, 0)); + cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, flags)); str.size = 4; - cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, 0)); + cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, flags)); str.size = 5; - cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, 0)); + cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, flags)); str.size = 7; - cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, 0)); + cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, flags)); str.size = 8; - cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, 0)); + cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, flags)); str.size = strlen(str.ptr); - cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, 0)); + cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, flags)); } void test_path_core__isvalid_empty_dir_component(void) { - cl_assert_equal_b(false, git_fs_path_is_valid("foo//bar", 0)); + unsigned int flags = GIT_FS_PATH_REJECT_EMPTY_COMPONENT; + + /* empty component */ + cl_assert_equal_b(true, git_fs_path_is_valid("foo//bar", 0)); + + /* leading slash */ + cl_assert_equal_b(true, git_fs_path_is_valid("/", 0)); + cl_assert_equal_b(true, git_fs_path_is_valid("/foo", 0)); + cl_assert_equal_b(true, git_fs_path_is_valid("/foo/bar", 0)); + + /* trailing slash */ + cl_assert_equal_b(true, git_fs_path_is_valid("foo/", 0)); + cl_assert_equal_b(true, git_fs_path_is_valid("foo/bar/", 0)); + + + /* empty component */ + cl_assert_equal_b(false, git_fs_path_is_valid("foo//bar", flags)); /* leading slash */ - cl_assert_equal_b(false, git_fs_path_is_valid("/", 0)); - cl_assert_equal_b(false, git_fs_path_is_valid("/foo", 0)); - cl_assert_equal_b(false, git_fs_path_is_valid("/foo/bar", 0)); + cl_assert_equal_b(false, git_fs_path_is_valid("/", flags)); + cl_assert_equal_b(false, git_fs_path_is_valid("/foo", flags)); + cl_assert_equal_b(false, git_fs_path_is_valid("/foo/bar", flags)); /* trailing slash */ - cl_assert_equal_b(false, git_fs_path_is_valid("foo/", 0)); - cl_assert_equal_b(false, git_fs_path_is_valid("foo/bar/", 0)); + cl_assert_equal_b(false, git_fs_path_is_valid("foo/", flags)); + cl_assert_equal_b(false, git_fs_path_is_valid("foo/bar/", flags)); } void test_path_core__isvalid_dot_and_dotdot(void) -- cgit v1.2.1