diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2018-06-04 12:18:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-06-04 12:18:40 +0100 |
commit | ca55adaa4d754b0b15b19db185bba13123cb960a (patch) | |
tree | 877ad8462fcafea094e6a824cb2c7f0bb75efdaf | |
parent | b55bb43d0a733e6100d4eb52719b619281550a00 (diff) | |
parent | 9fcd4772fcabb7446aaca8eb7868665649e30ecb (diff) | |
download | libgit2-ca55adaa4d754b0b15b19db185bba13123cb960a.tar.gz |
Merge pull request #4666 from pks-t/pks/v0.26.4v0.26.4
Release v0.26.4
-rw-r--r-- | CHANGELOG.md | 20 | ||||
-rw-r--r-- | include/git2/version.h | 4 | ||||
-rw-r--r-- | src/checkout.c | 4 | ||||
-rw-r--r-- | src/index.c | 40 | ||||
-rw-r--r-- | src/path.c | 202 | ||||
-rw-r--r-- | src/path.h | 73 | ||||
-rw-r--r-- | src/refdb_fs.c | 4 | ||||
-rw-r--r-- | src/submodule.c | 61 | ||||
-rw-r--r-- | src/submodule.h | 13 | ||||
-rw-r--r-- | src/tree.c | 2 | ||||
-rw-r--r-- | tests/checkout/nasty.c | 12 | ||||
-rw-r--r-- | tests/online/clone.c | 40 | ||||
-rw-r--r-- | tests/path/core.c | 394 | ||||
-rw-r--r-- | tests/path/dotgit.c | 119 | ||||
-rw-r--r-- | tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 | bin | 0 -> 93 bytes | |||
-rw-r--r-- | tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a | bin | 0 -> 26 bytes | |||
-rw-r--r-- | tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94 | bin | 0 -> 21 bytes | |||
-rw-r--r-- | tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 | bin | 0 -> 146 bytes | |||
-rw-r--r-- | tests/resources/nasty/.gitted/refs/heads/gitmodules-symlink | 1 | ||||
-rw-r--r-- | tests/submodule/escape.c | 98 |
20 files changed, 841 insertions, 246 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index ef5347c06..c52e6ce90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +v0.26.4 +------- + +This is a security release fixing insufficient validation of submodule names +(CVE-2018-11235, reported by Etienne Stalmans) and disallows `.gitmodules` files +as symlinks. + +While submodule names come from the untrusted ".gitmodules" file, we blindly +append the name to "$GIT_DIR/modules" to construct the final path of the +submodule repository. In case the name contains e.g. "../", an adversary would +be able to escape your repository and write data at arbitrary paths. In +accordance with git, we now enforce some rules for submodule names which will +cause libgit2 to ignore these malicious names. + +Adding a symlink as `.gitmodules` into the index from the workdir or checking +out such files is not allowed as this can make a Git implementation write +outside of the repository and bypass the `fsck` checks for CVE-2018-11235. + +libgit2 is not susceptible to CVE-2018-11233. + v0.26.3 ------- diff --git a/include/git2/version.h b/include/git2/version.h index 689c51d27..354307e8c 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,10 +7,10 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.26.3" +#define LIBGIT2_VERSION "0.26.4" #define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MINOR 26 -#define LIBGIT2_VER_REVISION 3 +#define LIBGIT2_VER_REVISION 4 #define LIBGIT2_VER_PATCH 0 #define LIBGIT2_SOVERSION 26 diff --git a/src/checkout.c b/src/checkout.c index cb9a7b3a9..11386bb9e 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1272,14 +1272,14 @@ static int checkout_verify_paths( unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS; if (action & CHECKOUT_ACTION__REMOVE) { - if (!git_path_isvalid(repo, delta->old_file.path, flags)) { + if (!git_path_isvalid(repo, delta->old_file.path, delta->old_file.mode, flags)) { giterr_set(GITERR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path); return -1; } } if (action & ~CHECKOUT_ACTION__REMOVE) { - if (!git_path_isvalid(repo, delta->new_file.path, flags)) { + if (!git_path_isvalid(repo, delta->new_file.path, delta->new_file.mode, flags)) { giterr_set(GITERR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path); return -1; } diff --git a/src/index.c b/src/index.c index 3ce7b0f6f..c5f6550d6 100644 --- a/src/index.c +++ b/src/index.c @@ -884,11 +884,13 @@ static int index_entry_create( git_index_entry **out, git_repository *repo, const char *path, + struct stat *st, bool from_workdir) { size_t pathlen = strlen(path), alloclen; struct entry_internal *entry; unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS; + uint16_t mode = 0; /* always reject placing `.git` in the index and directory traversal. * when requested, disallow platform-specific filenames and upgrade to @@ -896,8 +898,10 @@ static int index_entry_create( */ if (from_workdir) path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS; + if (st) + mode = st->st_mode; - if (!git_path_isvalid(repo, path, path_valid_flags)) { + if (!git_path_isvalid(repo, path, mode, path_valid_flags)) { giterr_set(GITERR_INDEX, "invalid path: '%s'", path); return -1; } @@ -922,15 +926,35 @@ static int index_entry_init( { int error = 0; git_index_entry *entry = NULL; + git_buf path = GIT_BUF_INIT; struct stat st; git_oid oid; + git_repository *repo; if (INDEX_OWNER(index) == NULL) return create_index_error(-1, "could not initialize index entry. " "Index is not backed up by an existing repository."); - if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, true) < 0) + /* + * FIXME: this is duplicated with the work in + * git_blob__create_from_paths. It should accept an optional stat + * structure so we can pass in the one we have to do here. + */ + repo = INDEX_OWNER(index); + if (git_repository__ensure_not_bare(repo, "create blob from file") < 0) + return GIT_EBAREREPO; + + if (git_buf_joinpath(&path, git_repository_workdir(repo), rel_path) < 0) + return -1; + + error = git_path_lstat(path.ptr, &st); + git_buf_free(&path); + + if (error < 0) + return error; + + if (index_entry_create(&entry, INDEX_OWNER(index), rel_path, &st, true) < 0) return -1; /* write the blob to disk and get the oid and stat info */ @@ -1016,7 +1040,7 @@ static int index_entry_dup( git_index *index, const git_index_entry *src) { - if (index_entry_create(out, INDEX_OWNER(index), src->path, false) < 0) + if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0) return -1; index_entry_cpy(*out, src); @@ -1038,7 +1062,7 @@ static int index_entry_dup_nocache( git_index *index, const git_index_entry *src) { - if (index_entry_create(out, INDEX_OWNER(index), src->path, false) < 0) + if (index_entry_create(out, INDEX_OWNER(index), src->path, NULL, false) < 0) return -1; index_entry_cpy_nocache(*out, src); @@ -1457,9 +1481,6 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const struct stat st; int error; - if (index_entry_create(&entry, INDEX_OWNER(index), path, true) < 0) - return -1; - if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0) return error; @@ -1468,6 +1489,9 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const return -1; } + if (index_entry_create(&entry, INDEX_OWNER(index), path, &st, true) < 0) + return -1; + git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode); if ((error = git_repository_open(&sub, abspath.ptr)) < 0) @@ -2961,7 +2985,7 @@ static int read_tree_cb( if (git_buf_joinpath(&path, root, tentry->filename) < 0) return -1; - if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, false) < 0) + if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr, NULL, false) < 0) return -1; entry->mode = tentry->attr; diff --git a/src/path.c b/src/path.c index 5fc7a055b..e68455b70 100644 --- a/src/path.c +++ b/src/path.c @@ -1560,18 +1560,31 @@ static int32_t next_hfs_char(const char **in, size_t *len) return 0; /* NULL byte -- end of string */ } -static bool verify_dotgit_hfs(const char *path, size_t len) +static bool verify_dotgit_hfs_generic(const char *path, size_t len, const char *needle, size_t needle_len) { - if (next_hfs_char(&path, &len) != '.' || - next_hfs_char(&path, &len) != 'g' || - next_hfs_char(&path, &len) != 'i' || - next_hfs_char(&path, &len) != 't' || - next_hfs_char(&path, &len) != 0) + size_t i; + char c; + + if (next_hfs_char(&path, &len) != '.') + return true; + + for (i = 0; i < needle_len; i++) { + c = next_hfs_char(&path, &len); + if (c != needle[i]) + return true; + } + + if (next_hfs_char(&path, &len) != '\0') return true; return false; } +static bool verify_dotgit_hfs(const char *path, size_t len) +{ + return verify_dotgit_hfs_generic(path, len, "git", CONST_STRLEN("git")); +} + GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size_t len) { git_buf *reserved = git_repository__reserved_names_win32; @@ -1607,6 +1620,57 @@ GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size return false; } +GIT_INLINE(bool) only_spaces_and_dots(const char *path) +{ + const char *c = path; + + for (;; c++) { + if (*c == '\0') + return true; + if (*c != ' ' && *c != '.') + return false; + } + + return true; +} + +GIT_INLINE(bool) verify_dotgit_ntfs_generic(const char *name, size_t len, const char *dotgit_name, size_t dotgit_len, const char *shortname_pfix) +{ + int i, saw_tilde; + + if (name[0] == '.' && len >= dotgit_len && + !strncasecmp(name + 1, dotgit_name, dotgit_len)) { + return !only_spaces_and_dots(name + dotgit_len + 1); + } + + /* Detect the basic NTFS shortname with the first six chars */ + if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' && + name[7] >= '1' && name[7] <= '4') + return !only_spaces_and_dots(name + 8); + + /* Catch fallback names */ + for (i = 0, saw_tilde = 0; i < 8; i++) { + if (name[i] == '\0') { + return true; + } else if (saw_tilde) { + if (name[i] < '0' || name[i] > '9') + return true; + } else if (name[i] == '~') { + if (name[i+1] < '1' || name[i+1] > '9') + return true; + saw_tilde = 1; + } else if (i >= 6) { + return true; + } else if (name[i] < 0) { + return true; + } else if (git__tolower(name[i]) != shortname_pfix[i]) { + return true; + } + } + + return !only_spaces_and_dots(name + i); +} + GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags) { if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\') @@ -1635,6 +1699,24 @@ GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags) } /* + * Return the length of the common prefix between str and prefix, comparing them + * case-insensitively (must be ASCII to match). + */ +GIT_INLINE(size_t) common_prefix_icase(const char *str, size_t len, const char *prefix) +{ + size_t count = 0; + + while (len >0 && tolower(*str) == tolower(*prefix)) { + count++; + str++; + prefix++; + len--; + } + + return count; +} + +/* * We fundamentally don't like some paths when dealing with user-inputted * strings (in checkout or ref names): we don't want dot or dot-dot * anywhere, we want to avoid writing weird paths on Windows that can't @@ -1647,6 +1729,7 @@ static bool verify_component( git_repository *repo, const char *component, size_t len, + uint16_t mode, unsigned int flags) { if (len == 0) @@ -1679,26 +1762,38 @@ static bool verify_component( return false; } - if (flags & GIT_PATH_REJECT_DOT_GIT_HFS && - !verify_dotgit_hfs(component, len)) - return false; + if (flags & GIT_PATH_REJECT_DOT_GIT_HFS) { + if (!verify_dotgit_hfs(component, len)) + return false; + if (S_ISLNK(mode) && git_path_is_hfs_dotgit_modules(component, len)) + return false; + } - if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS && - !verify_dotgit_ntfs(repo, component, len)) - return false; + if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) { + if (!verify_dotgit_ntfs(repo, component, len)) + return false; + if (S_ISLNK(mode) && git_path_is_ntfs_dotgit_modules(component, len)) + return false; + } /* don't bother rerunning the `.git` test if we ran the HFS or NTFS * specific tests, they would have already rejected `.git`. */ if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 && - (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 && - (flags & GIT_PATH_REJECT_DOT_GIT_LITERAL) && - len == 4 && - component[0] == '.' && - (component[1] == 'g' || component[1] == 'G') && - (component[2] == 'i' || component[2] == 'I') && - (component[3] == 't' || component[3] == 'T')) - return false; + (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 && + (flags & GIT_PATH_REJECT_DOT_GIT_LITERAL)) { + if (len >= 4 && + component[0] == '.' && + (component[1] == 'g' || component[1] == 'G') && + (component[2] == 'i' || component[2] == 'I') && + (component[3] == 't' || component[3] == 'T')) { + if (len == 4) + return false; + + if (S_ISLNK(mode) && common_prefix_icase(component, len, ".gitmodules") == len) + return false; + } + } return true; } @@ -1736,6 +1831,7 @@ GIT_INLINE(unsigned int) dotgit_flags( bool git_path_isvalid( git_repository *repo, const char *path, + uint16_t mode, unsigned int flags) { const char *start, *c; @@ -1749,14 +1845,14 @@ bool git_path_isvalid( return false; if (*c == '/') { - if (!verify_component(repo, start, (c - start), flags)) + if (!verify_component(repo, start, (c - start), mode, flags)) return false; start = c+1; } } - return verify_component(repo, start, (c - start), flags); + return verify_component(repo, start, (c - start), mode, flags); } int git_path_normalize_slashes(git_buf *out, const char *path) @@ -1774,3 +1870,65 @@ int git_path_normalize_slashes(git_buf *out, const char *path) return 0; } + +static int verify_dotgit_generic(const char *name, size_t len, const char *dotgit_name, size_t dotgit_len, const char *shortname_pfix) +{ + if (!verify_dotgit_ntfs_generic(name, len, dotgit_name, dotgit_len, shortname_pfix)) + return false; + + return verify_dotgit_hfs_generic(name, len, dotgit_name, dotgit_len); +} + +int git_path_is_ntfs_dotgit_modules(const char *name, size_t len) +{ + return !verify_dotgit_ntfs_generic(name, len, "gitmodules", CONST_STRLEN("gitmodules"), "gi7eba"); +} + +int git_path_is_hfs_dotgit_modules(const char *name, size_t len) +{ + return !verify_dotgit_hfs_generic(name, len, "gitmodules", CONST_STRLEN("gitmodules")); +} + +int git_path_is_dotgit_modules(const char *name, size_t len) +{ + if (git_path_is_hfs_dotgit_modules(name, len)) + return 1; + + return git_path_is_ntfs_dotgit_modules(name, len); +} + +int git_path_is_ntfs_dotgit_ignore(const char *name, size_t len) +{ + return !verify_dotgit_ntfs_generic(name, len, "gitignore", CONST_STRLEN("gitignore"), "gi250a"); +} + +int git_path_is_hfs_dotgit_ignore(const char *name, size_t len) +{ + return !verify_dotgit_hfs_generic(name, len, "gitignore", CONST_STRLEN("gitignore")); +} + +int git_path_is_dotgit_ignore(const char *name, size_t len) +{ + if (git_path_is_hfs_dotgit_ignore(name, len)) + return 1; + + return git_path_is_ntfs_dotgit_ignore(name, len); +} + +int git_path_is_hfs_dotgit_attributes(const char *name, size_t len) +{ + return !verify_dotgit_hfs_generic(name, len, "gitattributes", CONST_STRLEN("gitattributes")); +} + +int git_path_is_ntfs_dotgit_attributes(const char *name, size_t len) +{ + return !verify_dotgit_ntfs_generic(name, len, "gitattributes", CONST_STRLEN("gitattributes"), "gi7d29"); +} + +int git_path_is_dotgit_attributes(const char *name, size_t len) +{ + if (git_path_is_hfs_dotgit_attributes(name, len)) + return 1; + + return git_path_is_ntfs_dotgit_attributes(name, len); +} diff --git a/src/path.h b/src/path.h index fb45a6534..5b3fff8ee 100644 --- a/src/path.h +++ b/src/path.h @@ -623,6 +623,7 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or extern bool git_path_isvalid( git_repository *repo, const char *path, + uint16_t mode, unsigned int flags); /** @@ -630,4 +631,76 @@ extern bool git_path_isvalid( */ int git_path_normalize_slashes(git_buf *out, const char *path); +/** + * Check whether a path component corresponds to a .gitmodules file + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_dotgit_modules(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitmodules file in NTFS + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_ntfs_dotgit_modules(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitmodules file in HFS+ + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_hfs_dotgit_modules(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitignore file + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_dotgit_ignore(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitignore file in NTFS + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_ntfs_dotgit_ignore(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitignore file in HFS+ + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_hfs_dotgit_ignore(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitignore file + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_dotgit_attributes(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitattributes file in NTFS + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_ntfs_dotgit_attributes(const char *name, size_t len); + +/** + * Check whether a path component corresponds to a .gitattributes file in HFS+ + * + * @param name the path component to check + * @param len the length of `name` + */ +extern int git_path_is_hfs_dotgit_attributes(const char *name, size_t len); + #endif diff --git a/src/refdb_fs.c b/src/refdb_fs.c index eb135dc01..f8a1d409c 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -743,7 +743,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * assert(file && backend && name); - if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { + if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { giterr_set(GITERR_INVALID, "invalid reference name '%s'", name); return GIT_EINVALIDSPEC; } @@ -1739,7 +1739,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char repo = backend->repo; - if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { + if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { giterr_set(GITERR_INVALID, "invalid reference name '%s'", refname); return GIT_EINVALIDSPEC; } diff --git a/src/submodule.c b/src/submodule.c index ddd4b0663..96c8e6675 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -169,13 +169,13 @@ static void free_submodule_names(git_strmap *names) * TODO: for some use-cases, this might need case-folding on a * case-insensitive filesystem */ -static int load_submodule_names(git_strmap *out, git_config *cfg) +static int load_submodule_names(git_strmap *out, git_repository *repo, git_config *cfg) { const char *key = "submodule\\..*\\.path"; git_config_iterator *iter; git_config_entry *entry; git_buf buf = GIT_BUF_INIT; - int rval; + int rval, isvalid; int error = 0; if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0) @@ -186,16 +186,29 @@ static int load_submodule_names(git_strmap *out, git_config *cfg) fdot = strchr(entry->name, '.'); ldot = strrchr(entry->name, '.'); + git_buf_clear(&buf); git_buf_put(&buf, fdot + 1, ldot - fdot - 1); + isvalid = git_submodule_name_is_valid(repo, buf.ptr, 0); + if (isvalid < 0) { + error = isvalid; + goto out; + } + if (!isvalid) + continue; + git_strmap_insert(out, entry->value, git_buf_detach(&buf), &rval); if (rval < 0) { giterr_set(GITERR_NOMEMORY, "error inserting submodule into hash table"); return -1; } } + if (error == GIT_ITEROVER) + error = 0; +out: + git_buf_free(&buf); git_config_iterator_free(iter); - return 0; + return error; } int git_submodule_lookup( @@ -309,6 +322,28 @@ int git_submodule_lookup( return 0; } +int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags) +{ + git_buf buf = GIT_BUF_INIT; + int error, isvalid; + + if (flags == 0) + flags = GIT_PATH_REJECT_FILESYSTEM_DEFAULTS; + + /* Avoid allocating a new string if we can avoid it */ + if (strchr(name, '\\') != NULL) { + if ((error = git_path_normalize_slashes(&buf, name)) < 0) + return error; + } else { + git_buf_attach_notowned(&buf, name, strlen(name)); + } + + isvalid = git_path_isvalid(repo, buf.ptr, 0, flags); + git_buf_free(&buf); + + return isvalid; +} + static void submodule_free_dup(void *sm) { git_submodule_free(sm); @@ -354,7 +389,7 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf git_strmap *names = 0; git_strmap_alloc(&names); - if ((error = load_submodule_names(names, cfg))) + if ((error = load_submodule_names(names, git_index_owner(idx), cfg))) goto done; if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0) @@ -406,7 +441,7 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg const git_index_entry *entry; git_strmap *names = 0; git_strmap_alloc(&names); - if ((error = load_submodule_names(names, cfg))) + if ((error = load_submodule_names(names, git_tree_owner(head), cfg))) goto done; if ((error = git_iterator_for_tree(&i, head, NULL)) < 0) @@ -1492,13 +1527,19 @@ static int submodule_update_head(git_submodule *submodule) int git_submodule_reload(git_submodule *sm, int force) { - int error = 0; + int error = 0, isvalid; git_config *mods; GIT_UNUSED(force); assert(sm); + isvalid = git_submodule_name_is_valid(sm->repo, sm->name, 0); + if (isvalid <= 0) { + /* This should come with a warning, but we've no API for that */ + return isvalid; + } + if (!git_repository_is_bare(sm->repo)) { /* refresh config data */ mods = gitmodules_snapshot(sm->repo); @@ -1839,7 +1880,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) git_strmap *map = data->map; git_buf name = GIT_BUF_INIT; git_submodule *sm; - int error; + int error, isvalid; if (git__prefixcmp(entry->name, "submodule.") != 0) return 0; @@ -1855,6 +1896,12 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0) return error; + isvalid = git_submodule_name_is_valid(data->repo, name.ptr, 0); + if (isvalid <= 0) { + error = isvalid; + goto done; + } + /* * Now that we have the submodule's name, we can use that to * figure out whether it's in the map. If it's not, we create diff --git a/src/submodule.h b/src/submodule.h index 456a93979..2d60b3c7e 100644 --- a/src/submodule.h +++ b/src/submodule.h @@ -146,4 +146,17 @@ extern int git_submodule_parse_update( extern int git_submodule__map( git_repository *repo, git_strmap *map); + +/** + * Check whether a submodule's name is valid. + * + * Check the path against the path validity rules, either the filesystem + * defaults (like checkout does) or whichever you want to compare against. + * + * @param repo the repository which contains the submodule + * @param name the name to check + * @param flags the `GIT_PATH` flags to use for the check (0 to use filesystem defaults) + */ +extern int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags); + #endif diff --git a/src/tree.c b/src/tree.c index 6b1d1b238..6d3e7fe6c 100644 --- a/src/tree.c +++ b/src/tree.c @@ -54,7 +54,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) static int valid_entry_name(git_repository *repo, const char *filename) { return *filename != '\0' && - git_path_isvalid(repo, filename, + git_path_isvalid(repo, filename, 0, GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH); } diff --git a/tests/checkout/nasty.c b/tests/checkout/nasty.c index 952a6a112..d4d3c8fa4 100644 --- a/tests/checkout/nasty.c +++ b/tests/checkout/nasty.c @@ -364,3 +364,15 @@ void test_checkout_nasty__symlink3(void) test_checkout_passes("refs/heads/symlink3", ".git/foobar"); } +void test_checkout_nasty__gitmodules_symlink(void) +{ + cl_repo_set_bool(repo, "core.protectHFS", true); + test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules"); + cl_repo_set_bool(repo, "core.protectHFS", false); + + cl_repo_set_bool(repo, "core.protectNTFS", true); + test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules"); + cl_repo_set_bool(repo, "core.protectNTFS", false); + + test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules"); +} diff --git a/tests/online/clone.c b/tests/online/clone.c index 04fd22d45..c5d2ab188 100644 --- a/tests/online/clone.c +++ b/tests/online/clone.c @@ -348,7 +348,7 @@ void test_online_clone__credentials(void) void test_online_clone__bitbucket_style(void) { git_cred_userpass_payload user_pass = { - "libgit2", "libgit2" + "libgit3", "libgit3" }; g_options.fetch_opts.callbacks.credentials = git_cred_userpass; @@ -357,15 +357,45 @@ void test_online_clone__bitbucket_style(void) cl_git_pass(git_clone(&g_repo, BB_REPO_URL, "./foo", &g_options)); git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("./foo"); +} - /* User and pass from URL */ - user_pass.password = "wrong"; +void test_online_clone__bitbucket_uses_creds_in_url(void) +{ + git_cred_userpass_payload user_pass = { + "libgit2", "wrong" + }; + + g_options.fetch_opts.callbacks.credentials = git_cred_userpass; + g_options.fetch_opts.callbacks.payload = &user_pass; + + /* + * Correct user and pass are in the URL; the (incorrect) creds in + * the `git_cred_userpass_payload` should be ignored. + */ cl_git_pass(git_clone(&g_repo, BB_REPO_URL_WITH_PASS, "./foo", &g_options)); git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("./foo"); +} - /* Wrong password in URL, fall back to user_pass */ - user_pass.password = "libgit2"; +void test_online_clone__bitbucket_falls_back_to_specified_creds(void) +{ + git_cred_userpass_payload user_pass = { + "libgit2", "libgit2" + }; + + g_options.fetch_opts.callbacks.credentials = git_cred_userpass; + g_options.fetch_opts.callbacks.payload = &user_pass; + + /* + * TODO: as of March 2018, bitbucket sporadically fails with + * 403s instead of replying with a 401 - but only sometimes. + */ + cl_skip(); + + /* + * Incorrect user and pass are in the URL; the (correct) creds in + * the `git_cred_userpass_payload` should be used as a fallback. + */ cl_git_pass(git_clone(&g_repo, BB_REPO_URL_WITH_WRONG_PASS, "./foo", &g_options)); git_repository_free(g_repo); g_repo = NULL; cl_fixture_cleanup("./foo"); diff --git a/tests/path/core.c b/tests/path/core.c index 3dccfe5fb..0ab41ea50 100644 --- a/tests/path/core.c +++ b/tests/path/core.c @@ -54,256 +54,256 @@ void test_path_core__make_relative(void) void test_path_core__isvalid_standard(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/file.txt", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.file", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/file.txt", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.file", 0, 0)); } void test_path_core__isvalid_empty_dir_component(void) { - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo//bar", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo//bar", 0, 0)); /* leading slash */ - cl_assert_equal_b(false, git_path_isvalid(NULL, "/", 0)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo", 0)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo/bar", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "/", 0, 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo", 0, 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo/bar", 0, 0)); /* trailing slash */ - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/", 0)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/", 0, 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/", 0, 0)); } void test_path_core__isvalid_dot_and_dotdot(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "..", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/..", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, ".", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", GIT_PATH_REJECT_TRAVERSAL)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "..", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/..", GIT_PATH_REJECT_TRAVERSAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0, 0)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "..", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/..", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, ".", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", 0, GIT_PATH_REJECT_TRAVERSAL)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "..", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/..", 0, GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", 0, GIT_PATH_REJECT_TRAVERSAL)); } void test_path_core__isvalid_dot_git(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git/foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git/bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.GIT/bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", GIT_PATH_REJECT_DOT_GIT_LITERAL)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "!git/bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.tig", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig/bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git/foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git/bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.GIT/bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", 0, GIT_PATH_REJECT_DOT_GIT_LITERAL)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "!git/bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.tig", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig/bar", 0, 0)); } void test_path_core__isvalid_backslash(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo\\file.txt", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\file.txt", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo\\file.txt", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\file.txt", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\", 0, 0)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo\\file.txt", GIT_PATH_REJECT_BACKSLASH)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\file.txt", GIT_PATH_REJECT_BACKSLASH)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\", GIT_PATH_REJECT_BACKSLASH)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo\\file.txt", 0, GIT_PATH_REJECT_BACKSLASH)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\file.txt", 0, GIT_PATH_REJECT_BACKSLASH)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\", 0, GIT_PATH_REJECT_BACKSLASH)); } void test_path_core__isvalid_trailing_dot(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo...", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo./bar", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo.", GIT_PATH_REJECT_TRAILING_DOT)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo...", GIT_PATH_REJECT_TRAILING_DOT)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar.", GIT_PATH_REJECT_TRAILING_DOT)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo./bar", GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo...", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo./bar", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo.", 0, GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo...", 0, GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar.", 0, GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo./bar", 0, GIT_PATH_REJECT_TRAILING_DOT)); } void test_path_core__isvalid_trailing_space(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, " ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo /bar", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", GIT_PATH_REJECT_TRAILING_SPACE)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", GIT_PATH_REJECT_TRAILING_SPACE)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar ", GIT_PATH_REJECT_TRAILING_SPACE)); - cl_assert_equal_b(false, git_path_isvalid(NULL, " ", GIT_PATH_REJECT_TRAILING_SPACE)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo /bar", GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, " ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo /bar", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", 0, GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", 0, GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar ", 0, GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, " ", 0, GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo /bar", 0, GIT_PATH_REJECT_TRAILING_SPACE)); } void test_path_core__isvalid_trailing_colon(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar:", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ":", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:/bar", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:", GIT_PATH_REJECT_TRAILING_COLON)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar:", GIT_PATH_REJECT_TRAILING_COLON)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ":", GIT_PATH_REJECT_TRAILING_COLON)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:/bar", GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar:", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ":", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:/bar", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:", 0, GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar:", 0, GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ":", 0, GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:/bar", 0, GIT_PATH_REJECT_TRAILING_COLON)); } void test_path_core__isvalid_dotgit_ntfs(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.. .", 0)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1 ", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.. .", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git ", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.. .", GIT_PATH_REJECT_DOT_GIT_NTFS)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1 ", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.", GIT_PATH_REJECT_DOT_GIT_NTFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.. .", GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.. .", 0, 0)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1 ", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.. .", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git ", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1 ", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS)); } void test_path_core__isvalid_dos_paths(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf\\zippy", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:asdf\\foobar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "con", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "prn", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "nul", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf\\zippy", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:asdf\\foobar", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "con", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "prn", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "nul", GIT_PATH_REJECT_DOS_PATHS)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "auxn", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "aux\\foo", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf\\zippy", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:asdf\\foobar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "con", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "prn", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "nul", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf\\zippy", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:asdf\\foobar", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "con", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "prn", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "nul", 0, GIT_PATH_REJECT_DOS_PATHS)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "auxn", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux\\foo", 0, GIT_PATH_REJECT_DOS_PATHS)); } void test_path_core__isvalid_dos_paths_withnum(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf\\zippy", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:asdf\\foobar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt1", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf\\zippy", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:asdf\\foobar", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "com1/foo", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "lpt1", GIT_PATH_REJECT_DOS_PATHS)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "comn", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt0", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt10", GIT_PATH_REJECT_DOS_PATHS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "lptn", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf\\zippy", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:asdf\\foobar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt1", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf\\zippy", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:asdf\\foobar", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1/foo", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "lpt1", 0, GIT_PATH_REJECT_DOS_PATHS)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "comn", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt0", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt10", 0, GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "lptn", 0, GIT_PATH_REJECT_DOS_PATHS)); } void test_path_core__isvalid_nt_chars(void) { - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\001foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\037bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf<bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf>foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf:foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\"bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf|foo", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf?bar", 0)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf*bar", 0)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\001foo", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\037bar", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf<bar", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf>foo", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf:foo", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\"bar", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf|foo", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf?bar", GIT_PATH_REJECT_NT_CHARS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf*bar", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\001foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\037bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf<bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf>foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf:foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\"bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf|foo", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf?bar", 0, 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf*bar", 0, 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\001foo", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\037bar", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf<bar", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf>foo", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf:foo", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\"bar", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf|foo", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf?bar", 0, GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf*bar", 0, GIT_PATH_REJECT_NT_CHARS)); } void test_path_core__isvalid_dotgit_with_hfs_ignorables(void) { - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".git\xe2\x80\x8c", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".g\xe2\x80\x8eIt", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, ".\xe2\x80\x8fgIt", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xaa.gIt", GIT_PATH_REJECT_DOT_GIT_HFS)); - - cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xab.\xe2\x80\xacG\xe2\x80\xadI\xe2\x80\xaet", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xab.\xe2\x80\xaaG\xe2\x81\xabI\xe2\x80\xact", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xad.\xe2\x80\xaeG\xef\xbb\xbfIT", GIT_PATH_REJECT_DOT_GIT_HFS)); - - cl_assert_equal_b(true, git_path_isvalid(NULL, ".", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".g", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, " .git", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "..git\xe2\x80\x8c", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT.", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2\x80It", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".\xe2gIt", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, "\xe2\x80\xaa.gi", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x80\x8dT", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x8dT", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2i\x80T\x8e", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\x80\xbf", GIT_PATH_REJECT_DOT_GIT_HFS)); - cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\xab\x81", GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git\xe2\x80\x8c", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".g\xe2\x80\x8eIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".\xe2\x80\x8fgIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xaa.gIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x80\xab.\xe2\x80\xacG\xe2\x80\xadI\xe2\x80\xaet", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xab.\xe2\x80\xaaG\xe2\x81\xabI\xe2\x80\xact", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "\xe2\x81\xad.\xe2\x80\xaeG\xef\xbb\xbfIT", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".g", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, " .git", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "..git\xe2\x80\x8c", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\xe2\x80\x8dT.", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2\x80It", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".\xe2gIt", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "\xe2\x80\xaa.gi", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x80\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gi\x8dT", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".g\xe2i\x80T\x8e", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\x80\xbf", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\xab\x81", 0, GIT_PATH_REJECT_DOT_GIT_HFS)); } static void test_join_unrooted( diff --git a/tests/path/dotgit.c b/tests/path/dotgit.c new file mode 100644 index 000000000..20e585edb --- /dev/null +++ b/tests/path/dotgit.c @@ -0,0 +1,119 @@ +#include "clar_libgit2.h" +#include "path.h" + +static char *gitmodules_altnames[] = { + ".gitmodules", + + /* + * Equivalent to the ".git\u200cmodules" string from git but hard-coded + * as a UTF-8 sequence + */ + ".git\xe2\x80\x8cmodules", + + ".Gitmodules", + ".gitmoduleS", + + ".gitmodules ", + ".gitmodules.", + ".gitmodules ", + ".gitmodules. ", + ".gitmodules .", + ".gitmodules..", + ".gitmodules ", + ".gitmodules. ", + ".gitmodules . ", + ".gitmodules .", + + ".Gitmodules ", + ".Gitmodules.", + ".Gitmodules ", + ".Gitmodules. ", + ".Gitmodules .", + ".Gitmodules..", + ".Gitmodules ", + ".Gitmodules. ", + ".Gitmodules . ", + ".Gitmodules .", + + "GITMOD~1", + "gitmod~1", + "GITMOD~2", + "gitmod~3", + "GITMOD~4", + + "GITMOD~1 ", + "gitmod~2.", + "GITMOD~3 ", + "gitmod~4. ", + "GITMOD~1 .", + "gitmod~2 ", + "GITMOD~3. ", + "gitmod~4 . ", + + "GI7EBA~1", + "gi7eba~9", + + "GI7EB~10", + "GI7EB~11", + "GI7EB~99", + "GI7EB~10", + "GI7E~100", + "GI7E~101", + "GI7E~999", + "~1000000", + "~9999999", +}; + +static char *gitmodules_not_altnames[] = { + ".gitmodules x", + ".gitmodules .x", + + " .gitmodules", + + "..gitmodules", + + "gitmodules", + + ".gitmodule", + + ".gitmodules x ", + ".gitmodules .x", + + "GI7EBA~", + "GI7EBA~0", + "GI7EBA~~1", + "GI7EBA~X", + "Gx7EBA~1", + "GI7EBX~1", + + "GI7EB~1", + "GI7EB~01", + "GI7EB~1", +}; + +void test_path_dotgit__dotgit_modules(void) +{ + size_t i; + cl_assert_equal_i(1, git_path_is_dotgit_modules(".gitmodules", strlen(".gitmodules"))); + cl_assert_equal_i(1, git_path_is_dotgit_modules(".git\xe2\x80\x8cmodules", strlen(".git\xe2\x80\x8cmodules"))); + + for (i = 0; i < ARRAY_SIZE(gitmodules_altnames); i++) { + const char *name = gitmodules_altnames[i]; + if (!git_path_is_dotgit_modules(name, strlen(name))) + cl_fail(name); + } + + for (i = 0; i < ARRAY_SIZE(gitmodules_not_altnames); i++) { + const char *name = gitmodules_not_altnames[i]; + if (git_path_is_dotgit_modules(name, strlen(name))) + cl_fail(name); + } + +} + +void test_path_dotgit__dotgit_modules_symlink(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, ".gitmodules", 0, GIT_PATH_REJECT_DOT_GIT_HFS|GIT_PATH_REJECT_DOT_GIT_NTFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_HFS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_NTFS)); +} diff --git a/tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 b/tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 Binary files differnew file mode 100644 index 000000000..f040922a4 --- /dev/null +++ b/tests/resources/nasty/.gitted/objects/07/f9d4d85b75187e4db5b9cbcad3e6218582bd57 diff --git a/tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a b/tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a Binary files differnew file mode 100644 index 000000000..c4717d5ce --- /dev/null +++ b/tests/resources/nasty/.gitted/objects/2a/9eb82c733e31ae312cee349084dcbc6f69639a diff --git a/tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94 b/tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94 Binary files differnew file mode 100644 index 000000000..0666ba796 --- /dev/null +++ b/tests/resources/nasty/.gitted/objects/42/1376db9e8aee847e9d774891e73098a7415e94 diff --git a/tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 b/tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 Binary files differnew file mode 100644 index 000000000..1c1be161d --- /dev/null +++ b/tests/resources/nasty/.gitted/objects/e3/0b60b120761f44ebd0f0a7b0e9445ce8e11d68 diff --git a/tests/resources/nasty/.gitted/refs/heads/gitmodules-symlink b/tests/resources/nasty/.gitted/refs/heads/gitmodules-symlink new file mode 100644 index 000000000..3a2499fab --- /dev/null +++ b/tests/resources/nasty/.gitted/refs/heads/gitmodules-symlink @@ -0,0 +1 @@ +e30b60b120761f44ebd0f0a7b0e9445ce8e11d68 diff --git a/tests/submodule/escape.c b/tests/submodule/escape.c new file mode 100644 index 000000000..f5c3cd4cd --- /dev/null +++ b/tests/submodule/escape.c @@ -0,0 +1,98 @@ +#include "clar_libgit2.h" +#include "posix.h" +#include "path.h" +#include "submodule_helpers.h" +#include "fileops.h" +#include "repository.h" + +static git_repository *g_repo = NULL; + +void test_submodule_escape__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +#define EVIL_SM_NAME "../../modules/evil" +#define EVIL_SM_NAME_WINDOWS "..\\\\..\\\\modules\\\\evil" +#define EVIL_SM_NAME_WINDOWS_UNESC "..\\..\\modules\\evil" + +static int find_evil(git_submodule *sm, const char *name, void *payload) +{ + int *foundit = (int *) payload; + + GIT_UNUSED(sm); + + if (!git__strcmp(EVIL_SM_NAME, name) || + !git__strcmp(EVIL_SM_NAME_WINDOWS_UNESC, name)) + *foundit = true; + + return 0; +} + +void test_submodule_escape__from_gitdir(void) +{ + int foundit; + git_submodule *sm; + git_buf buf = GIT_BUF_INIT; + unsigned int sm_location; + + g_repo = setup_fixture_submodule_simple(); + + cl_git_pass(git_buf_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules")); + cl_git_rewritefile(buf.ptr, + "[submodule \"" EVIL_SM_NAME "\"]\n" + " path = testrepo\n" + " url = ../testrepo.git\n"); + git_buf_free(&buf); + + /* Find it all the different ways we know about it */ + foundit = 0; + cl_git_pass(git_submodule_foreach(g_repo, find_evil, &foundit)); + cl_assert_equal_i(0, foundit); + cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, EVIL_SM_NAME)); + /* + * We do know about this as it's in the index and HEAD, but the data is + * incomplete as there is no configured data for it (we pretend it + * doesn't exist). This leaves us with an odd situation but it's + * consistent with what we would do if we did add a submodule with no + * configuration. + */ + cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); + cl_git_pass(git_submodule_location(&sm_location, sm)); + cl_assert_equal_i(GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_HEAD, sm_location); + git_submodule_free(sm); +} + +void test_submodule_escape__from_gitdir_windows(void) +{ + int foundit; + git_submodule *sm; + git_buf buf = GIT_BUF_INIT; + unsigned int sm_location; + + g_repo = setup_fixture_submodule_simple(); + + cl_git_pass(git_buf_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules")); + cl_git_rewritefile(buf.ptr, + "[submodule \"" EVIL_SM_NAME_WINDOWS "\"]\n" + " path = testrepo\n" + " url = ../testrepo.git\n"); + git_buf_free(&buf); + + /* Find it all the different ways we know about it */ + foundit = 0; + cl_git_pass(git_submodule_foreach(g_repo, find_evil, &foundit)); + cl_assert_equal_i(0, foundit); + cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, EVIL_SM_NAME_WINDOWS_UNESC)); + /* + * We do know about this as it's in the index and HEAD, but the data is + * incomplete as there is no configured data for it (we pretend it + * doesn't exist). This leaves us with an odd situation but it's + * consistent with what we would do if we did add a submodule with no + * configuration. + */ + cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo")); + cl_git_pass(git_submodule_location(&sm_location, sm)); + cl_assert_equal_i(GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_HEAD, sm_location); + git_submodule_free(sm); +} |