Unverified Commit 7f6c1ce9 by Carlos Martín Nieto Committed by GitHub

Merge pull request #4660 from libgit2/cmn/submodule-traversal

Fixes for CVE 2018-11235
parents d050acf7 491722e8
...@@ -6,6 +6,11 @@ v0.27 + 1 ...@@ -6,6 +6,11 @@ v0.27 + 1
* The line-ending filtering logic - when checking out files - has been * The line-ending filtering logic - when checking out files - has been
updated to match newer git (>= git 2.9) for proper interoperability. updated to match newer git (>= git 2.9) for proper interoperability.
* Submodules with names which attempt to perform path traversal now have their
configuration ignored. Such names were blindly appended to the
`$GIT_DIR/modules` and a malicious name could lead to an attacker writing to
an arbitrary location. This matches git's handling of CVE-2018-11235.
### API additions ### API additions
### API removals ### API removals
...@@ -14,6 +19,10 @@ v0.27 + 1 ...@@ -14,6 +19,10 @@ v0.27 + 1
* The default checkout strategy changed from `DRY_RUN` to `SAFE` (#4531). * The default checkout strategy changed from `DRY_RUN` to `SAFE` (#4531).
* 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.
v0.27 v0.27
--------- ---------
......
...@@ -1276,14 +1276,14 @@ static int checkout_verify_paths( ...@@ -1276,14 +1276,14 @@ static int checkout_verify_paths(
unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS; unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
if (action & CHECKOUT_ACTION__REMOVE) { 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); giterr_set(GITERR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path);
return -1; return -1;
} }
} }
if (action & ~CHECKOUT_ACTION__REMOVE) { 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); giterr_set(GITERR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path);
return -1; return -1;
} }
......
...@@ -884,11 +884,13 @@ static int index_entry_create( ...@@ -884,11 +884,13 @@ static int index_entry_create(
git_index_entry **out, git_index_entry **out,
git_repository *repo, git_repository *repo,
const char *path, const char *path,
struct stat *st,
bool from_workdir) bool from_workdir)
{ {
size_t pathlen = strlen(path), alloclen; size_t pathlen = strlen(path), alloclen;
struct entry_internal *entry; struct entry_internal *entry;
unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS; unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
uint16_t mode = 0;
/* always reject placing `.git` in the index and directory traversal. /* always reject placing `.git` in the index and directory traversal.
* when requested, disallow platform-specific filenames and upgrade to * when requested, disallow platform-specific filenames and upgrade to
...@@ -896,8 +898,10 @@ static int index_entry_create( ...@@ -896,8 +898,10 @@ static int index_entry_create(
*/ */
if (from_workdir) if (from_workdir)
path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS; 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); giterr_set(GITERR_INDEX, "invalid path: '%s'", path);
return -1; return -1;
} }
...@@ -922,15 +926,35 @@ static int index_entry_init( ...@@ -922,15 +926,35 @@ static int index_entry_init(
{ {
int error = 0; int error = 0;
git_index_entry *entry = NULL; git_index_entry *entry = NULL;
git_buf path = GIT_BUF_INIT;
struct stat st; struct stat st;
git_oid oid; git_oid oid;
git_repository *repo;
if (INDEX_OWNER(index) == NULL) if (INDEX_OWNER(index) == NULL)
return create_index_error(-1, return create_index_error(-1,
"could not initialize index entry. " "could not initialize index entry. "
"Index is not backed up by an existing repository."); "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; return -1;
/* write the blob to disk and get the oid and stat info */ /* write the blob to disk and get the oid and stat info */
...@@ -1016,7 +1040,7 @@ static int index_entry_dup( ...@@ -1016,7 +1040,7 @@ static int index_entry_dup(
git_index *index, git_index *index,
const git_index_entry *src) 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; return -1;
index_entry_cpy(*out, src); index_entry_cpy(*out, src);
...@@ -1038,7 +1062,7 @@ static int index_entry_dup_nocache( ...@@ -1038,7 +1062,7 @@ static int index_entry_dup_nocache(
git_index *index, git_index *index,
const git_index_entry *src) 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; return -1;
index_entry_cpy_nocache(*out, src); index_entry_cpy_nocache(*out, src);
...@@ -1461,9 +1485,6 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const ...@@ -1461,9 +1485,6 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const
struct stat st; struct stat st;
int error; 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) if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0)
return error; return error;
...@@ -1472,6 +1493,9 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const ...@@ -1472,6 +1493,9 @@ static int add_repo_as_submodule(git_index_entry **out, git_index *index, const
return -1; 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); git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
if ((error = git_repository_open(&sub, abspath.ptr)) < 0) if ((error = git_repository_open(&sub, abspath.ptr)) < 0)
...@@ -2965,7 +2989,7 @@ static int read_tree_cb( ...@@ -2965,7 +2989,7 @@ static int read_tree_cb(
if (git_buf_joinpath(&path, root, tentry->filename) < 0) if (git_buf_joinpath(&path, root, tentry->filename) < 0)
return -1; 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; return -1;
entry->mode = tentry->attr; entry->mode = tentry->attr;
......
...@@ -1561,18 +1561,31 @@ static int32_t next_hfs_char(const char **in, size_t *len) ...@@ -1561,18 +1561,31 @@ static int32_t next_hfs_char(const char **in, size_t *len)
return 0; /* NULL byte -- end of string */ 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) != '.' || size_t i;
next_hfs_char(&path, &len) != 'g' || char c;
next_hfs_char(&path, &len) != 'i' ||
next_hfs_char(&path, &len) != 't' || if (next_hfs_char(&path, &len) != '.')
next_hfs_char(&path, &len) != 0) 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 true;
return false; 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_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size_t len)
{ {
git_buf *reserved = git_repository__reserved_names_win32; git_buf *reserved = git_repository__reserved_names_win32;
...@@ -1608,6 +1621,57 @@ GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size ...@@ -1608,6 +1621,57 @@ GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size
return false; 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) GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags)
{ {
if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\') if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\')
...@@ -1636,6 +1700,24 @@ GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags) ...@@ -1636,6 +1700,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 * 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 * 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 * anywhere, we want to avoid writing weird paths on Windows that can't
...@@ -1648,6 +1730,7 @@ static bool verify_component( ...@@ -1648,6 +1730,7 @@ static bool verify_component(
git_repository *repo, git_repository *repo,
const char *component, const char *component,
size_t len, size_t len,
uint16_t mode,
unsigned int flags) unsigned int flags)
{ {
if (len == 0) if (len == 0)
...@@ -1680,26 +1763,38 @@ static bool verify_component( ...@@ -1680,26 +1763,38 @@ static bool verify_component(
return false; return false;
} }
if (flags & GIT_PATH_REJECT_DOT_GIT_HFS && if (flags & GIT_PATH_REJECT_DOT_GIT_HFS) {
!verify_dotgit_hfs(component, len)) if (!verify_dotgit_hfs(component, len))
return false; return false;
if (S_ISLNK(mode) && git_path_is_hfs_dotgit_modules(component, len))
return false;
}
if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS && if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) {
!verify_dotgit_ntfs(repo, component, len)) if (!verify_dotgit_ntfs(repo, component, len))
return false; 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 /* don't bother rerunning the `.git` test if we ran the HFS or NTFS
* specific tests, they would have already rejected `.git`. * specific tests, they would have already rejected `.git`.
*/ */
if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 && if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 &&
(flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 && (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 &&
(flags & GIT_PATH_REJECT_DOT_GIT_LITERAL) && (flags & GIT_PATH_REJECT_DOT_GIT_LITERAL)) {
len == 4 && if (len >= 4 &&
component[0] == '.' && component[0] == '.' &&
(component[1] == 'g' || component[1] == 'G') && (component[1] == 'g' || component[1] == 'G') &&
(component[2] == 'i' || component[2] == 'I') && (component[2] == 'i' || component[2] == 'I') &&
(component[3] == 't' || component[3] == 'T')) (component[3] == 't' || component[3] == 'T')) {
return false; if (len == 4)
return false;
if (S_ISLNK(mode) && common_prefix_icase(component, len, ".gitmodules") == len)
return false;
}
}
return true; return true;
} }
...@@ -1737,6 +1832,7 @@ GIT_INLINE(unsigned int) dotgit_flags( ...@@ -1737,6 +1832,7 @@ GIT_INLINE(unsigned int) dotgit_flags(
bool git_path_isvalid( bool git_path_isvalid(
git_repository *repo, git_repository *repo,
const char *path, const char *path,
uint16_t mode,
unsigned int flags) unsigned int flags)
{ {
const char *start, *c; const char *start, *c;
...@@ -1750,14 +1846,14 @@ bool git_path_isvalid( ...@@ -1750,14 +1846,14 @@ bool git_path_isvalid(
return false; return false;
if (*c == '/') { if (*c == '/') {
if (!verify_component(repo, start, (c - start), flags)) if (!verify_component(repo, start, (c - start), mode, flags))
return false; return false;
start = c+1; 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) int git_path_normalize_slashes(git_buf *out, const char *path)
...@@ -1775,3 +1871,65 @@ int git_path_normalize_slashes(git_buf *out, const char *path) ...@@ -1775,3 +1871,65 @@ int git_path_normalize_slashes(git_buf *out, const char *path)
return 0; 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);
}
...@@ -637,6 +637,7 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or ...@@ -637,6 +637,7 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
extern bool git_path_isvalid( extern bool git_path_isvalid(
git_repository *repo, git_repository *repo,
const char *path, const char *path,
uint16_t mode,
unsigned int flags); unsigned int flags);
/** /**
...@@ -644,4 +645,76 @@ extern bool git_path_isvalid( ...@@ -644,4 +645,76 @@ extern bool git_path_isvalid(
*/ */
int git_path_normalize_slashes(git_buf *out, const char *path); 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 #endif
...@@ -771,7 +771,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * ...@@ -771,7 +771,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
assert(file && backend && name); 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); giterr_set(GITERR_INVALID, "invalid reference name '%s'", name);
return GIT_EINVALIDSPEC; return GIT_EINVALIDSPEC;
} }
...@@ -1769,7 +1769,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char ...@@ -1769,7 +1769,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
repo = backend->repo; 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); giterr_set(GITERR_INVALID, "invalid reference name '%s'", refname);
return GIT_EINVALIDSPEC; return GIT_EINVALIDSPEC;
} }
......
...@@ -214,13 +214,13 @@ static void free_submodule_names(git_strmap *names) ...@@ -214,13 +214,13 @@ static void free_submodule_names(git_strmap *names)
* TODO: for some use-cases, this might need case-folding on a * TODO: for some use-cases, this might need case-folding on a
* case-insensitive filesystem * 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"; const char *key = "submodule\\..*\\.path";
git_config_iterator *iter; git_config_iterator *iter;
git_config_entry *entry; git_config_entry *entry;
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
int rval; int rval, isvalid;
int error = 0; int error = 0;
if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0) if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
...@@ -231,16 +231,29 @@ static int load_submodule_names(git_strmap *out, git_config *cfg) ...@@ -231,16 +231,29 @@ static int load_submodule_names(git_strmap *out, git_config *cfg)
fdot = strchr(entry->name, '.'); fdot = strchr(entry->name, '.');
ldot = strrchr(entry->name, '.'); ldot = strrchr(entry->name, '.');
git_buf_clear(&buf);
git_buf_put(&buf, fdot + 1, ldot - fdot - 1); 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); git_strmap_insert(out, entry->value, git_buf_detach(&buf), &rval);
if (rval < 0) { if (rval < 0) {
giterr_set(GITERR_NOMEMORY, "error inserting submodule into hash table"); giterr_set(GITERR_NOMEMORY, "error inserting submodule into hash table");
return -1; return -1;
} }
} }
if (error == GIT_ITEROVER)
error = 0;
out:
git_buf_free(&buf);
git_config_iterator_free(iter); git_config_iterator_free(iter);
return 0; return error;
} }
int git_submodule_lookup( int git_submodule_lookup(
...@@ -359,6 +372,28 @@ int git_submodule_lookup( ...@@ -359,6 +372,28 @@ int git_submodule_lookup(
return 0; 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) static void submodule_free_dup(void *sm)
{ {
git_submodule_free(sm); git_submodule_free(sm);
...@@ -404,7 +439,7 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf ...@@ -404,7 +439,7 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf
git_strmap *names = 0; git_strmap *names = 0;
git_strmap_alloc(&names); git_strmap_alloc(&names);
if ((error = load_submodule_names(names, cfg))) if ((error = load_submodule_names(names, git_index_owner(idx), cfg)))
goto done; goto done;
if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0) if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
...@@ -456,7 +491,7 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg ...@@ -456,7 +491,7 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg
const git_index_entry *entry; const git_index_entry *entry;
git_strmap *names = 0; git_strmap *names = 0;
git_strmap_alloc(&names); git_strmap_alloc(&names);
if ((error = load_submodule_names(names, cfg))) if ((error = load_submodule_names(names, git_tree_owner(head), cfg)))
goto done; goto done;
if ((error = git_iterator_for_tree(&i, head, NULL)) < 0) if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
...@@ -1559,13 +1594,19 @@ static int submodule_update_head(git_submodule *submodule) ...@@ -1559,13 +1594,19 @@ static int submodule_update_head(git_submodule *submodule)
int git_submodule_reload(git_submodule *sm, int force) int git_submodule_reload(git_submodule *sm, int force)
{ {
int error = 0; int error = 0, isvalid;
git_config *mods; git_config *mods;
GIT_UNUSED(force); GIT_UNUSED(force);
assert(sm); 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)) { if (!git_repository_is_bare(sm->repo)) {
/* refresh config data */ /* refresh config data */
if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND) if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
...@@ -1907,7 +1948,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) ...@@ -1907,7 +1948,7 @@ static int submodule_load_each(const git_config_entry *entry, void *payload)
git_strmap *map = data->map; git_strmap *map = data->map;
git_buf name = GIT_BUF_INIT; git_buf name = GIT_BUF_INIT;
git_submodule *sm; git_submodule *sm;
int error; int error, isvalid;
if (git__prefixcmp(entry->name, "submodule.") != 0) if (git__prefixcmp(entry->name, "submodule.") != 0)
return 0; return 0;
...@@ -1923,6 +1964,12 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) ...@@ -1923,6 +1964,12 @@ static int submodule_load_each(const git_config_entry *entry, void *payload)
if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0) if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
return error; 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 * 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 * figure out whether it's in the map. If it's not, we create
......
...@@ -148,4 +148,17 @@ extern int git_submodule_parse_update( ...@@ -148,4 +148,17 @@ extern int git_submodule_parse_update(
extern int git_submodule__map( extern int git_submodule__map(
git_repository *repo, git_repository *repo,
git_strmap *map); 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 #endif
...@@ -54,7 +54,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) ...@@ -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) static int valid_entry_name(git_repository *repo, const char *filename)
{ {
return *filename != '\0' && 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); GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH);
} }
......
...@@ -364,3 +364,15 @@ void test_checkout_nasty__symlink3(void) ...@@ -364,3 +364,15 @@ void test_checkout_nasty__symlink3(void)
test_checkout_passes("refs/heads/symlink3", ".git/foobar"); 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");
}
...@@ -54,256 +54,256 @@ void test_path_core__make_relative(void) ...@@ -54,256 +54,256 @@ void test_path_core__make_relative(void)
void test_path_core__isvalid_standard(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", 0, 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.txt", 0, 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/.file", 0, 0));
} }
void test_path_core__isvalid_empty_dir_component(void) 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 */ /* leading slash */
cl_assert_equal_b(false, git_path_isvalid(NULL, "/", 0)); cl_assert_equal_b(false, git_path_isvalid(NULL, "/", 0, 0));
cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo", 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)); cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo/bar", 0, 0));
/* trailing slash */ /* trailing slash */
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/", 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)); cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/", 0, 0));
} }
void test_path_core__isvalid_dot_and_dotdot(void) 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, ".", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "..", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "..", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/..", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/..", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0, 0));
cl_assert_equal_b(false, git_path_isvalid(NULL, ".", 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", 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/.", 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", 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, "..", 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", 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/..", 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", 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) 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", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git/foo", 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)); 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)); 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)); 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0, 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", 0, 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, ".git/foo", 0, 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", 0, 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", 0, 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", 0, 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(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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "!git/bar", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig", 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)); 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig/bar", 0, 0));
} }
void test_path_core__isvalid_backslash(void) 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\\file.txt", 0, 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.txt", 0, 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, 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\\file.txt", 0, 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\\file.txt", 0, 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/bar\\", 0, GIT_PATH_REJECT_BACKSLASH));
} }
void test_path_core__isvalid_trailing_dot(void) 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, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo...", 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)); 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "foo./bar", 0, 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.", 0, 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...", 0, 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.", 0, 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", 0, GIT_PATH_REJECT_TRAILING_DOT));
} }
void test_path_core__isvalid_trailing_space(void) 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, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar ", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, " ", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, " ", 0, 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, 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 ", 0, 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 ", 0, 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, "foo/bar ", 0, 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, " ", 0, 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, "foo /bar", 0, GIT_PATH_REJECT_TRAILING_SPACE));
} }
void test_path_core__isvalid_trailing_colon(void) 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:", 0, 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, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, ":", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, ":", 0, 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, 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:", 0, 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, "foo/bar:", 0, 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, ":", 0, 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, "foo:/bar", 0, GIT_PATH_REJECT_TRAILING_COLON));
} }
void test_path_core__isvalid_dotgit_ntfs(void) 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, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git ", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, ".git ", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.. .", 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)); 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)); 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)); 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.. .", 0, 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", 0, 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 ", 0, 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.", 0, 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.. .", 0, 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", 0, 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 ", 0, 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.", 0, 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.. .", 0, GIT_PATH_REJECT_DOT_GIT_NTFS));
} }
void test_path_core__isvalid_dos_paths(void) 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, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:", 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)); 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)); 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)); 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "con", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "prn", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "prn", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "nul", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "nul", 0, 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", 0, 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.", 0, 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:", 0, 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", 0, 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\\zippy", 0, 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, "aux:asdf\\foobar", 0, 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, "con", 0, 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, "prn", 0, GIT_PATH_REJECT_DOS_PATHS));
cl_assert_equal_b(false, git_path_isvalid(NULL, "nul", 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0, 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, "aux1", 0, 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, "auxn", 0, 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\\foo", 0, GIT_PATH_REJECT_DOS_PATHS));
} }
void test_path_core__isvalid_dos_paths_withnum(void) 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, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:", 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)); 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)); 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)); 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt1", 0)); cl_assert_equal_b(true, git_path_isvalid(NULL, "lpt1", 0, 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", 0, 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.", 0, 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:", 0, 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", 0, 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\\zippy", 0, 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:asdf\\foobar", 0, 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, "com1/foo", 0, GIT_PATH_REJECT_DOS_PATHS));
cl_assert_equal_b(false, git_path_isvalid(NULL, "lpt1", 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "com0", 0, 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, "com0", 0, 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", 0, 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, "com10", 0, 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, "comn", 0, 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, "com1\\foo", 0, 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, "lpt0", 0, 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, "lpt10", 0, 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, "lptn", 0, GIT_PATH_REJECT_DOS_PATHS));
} }
void test_path_core__isvalid_nt_chars(void) 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\001foo", 0, 0));
cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\037bar", 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)); 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)); 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)); 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)); 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)); 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)); 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)); cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf*bar", 0, 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\001foo", 0, 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\037bar", 0, 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", 0, 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", 0, 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", 0, 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", 0, 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", 0, 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", 0, 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", 0, GIT_PATH_REJECT_NT_CHARS));
} }
void test_path_core__isvalid_dotgit_with_hfs_ignorables(void) 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", 0, 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, ".git\xe2\x80\x8c", 0, 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, ".gi\xe2\x80\x8dT", 0, 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, ".g\xe2\x80\x8eIt", 0, 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\x8fgIt", 0, 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\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", 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", 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", 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, ".", 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", 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", 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", 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", 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.", 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", 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", 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", 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", 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", 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", 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", 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", 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( static void test_join_unrooted(
......
#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));
}
#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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment