fs_path: make empty component validation optional
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
diff --git a/src/fs_path.c b/src/fs_path.c
index fa27a6e..483b21c 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 2f4bc9f..275b3d8 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 6fa0450..ccb328b 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)