mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-21 18:24:43 +00:00
checkout: disallow bad paths on win32
Disallow: 1. paths with trailing dot 2. paths with trailing space 3. paths with trailing colon 4. paths that are 8.3 short names of .git folders ("GIT~1") 5. paths that are reserved path names (COM1, LPT1, etc). 6. paths with reserved DOS characters (colons, asterisks, etc) These paths would (without \\?\ syntax) be elided to other paths - for example, ".git." would be written as ".git". As a result, writing these paths literally (using \\?\ syntax) makes them hard to operate with from the shell, Windows Explorer or other tools. Disallow these.
This commit is contained in:
parent
0d388adc86
commit
a64119e396
@ -1172,6 +1172,30 @@ static int checkout_get_remove_conflicts(
|
|||||||
return checkout_conflicts_foreach(data, data->index, workdir, pathspec, checkout_conflict_append_remove, data);
|
return checkout_conflicts_foreach(data, data->index, workdir, pathspec, checkout_conflict_append_remove, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int checkout_verify_paths(
|
||||||
|
git_repository *repo,
|
||||||
|
int action,
|
||||||
|
git_diff_delta *delta)
|
||||||
|
{
|
||||||
|
unsigned int flags = GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT;
|
||||||
|
|
||||||
|
if (action & CHECKOUT_ACTION__REMOVE) {
|
||||||
|
if (!git_path_isvalid(repo, delta->old_file.path, 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)) {
|
||||||
|
giterr_set(GITERR_CHECKOUT, "Cannot checkout to invalid path '%s'", delta->old_file.path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int checkout_get_actions(
|
static int checkout_get_actions(
|
||||||
uint32_t **actions_ptr,
|
uint32_t **actions_ptr,
|
||||||
size_t **counts_ptr,
|
size_t **counts_ptr,
|
||||||
@ -1205,7 +1229,9 @@ static int checkout_get_actions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
git_vector_foreach(deltas, i, delta) {
|
git_vector_foreach(deltas, i, delta) {
|
||||||
error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec);
|
if ((error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec)) == 0)
|
||||||
|
error = checkout_verify_paths(data->repo, act, delta);
|
||||||
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
119
src/index.c
119
src/index.c
@ -762,86 +762,19 @@ void git_index_entry__init_from_stat(
|
|||||||
entry->file_size = st->st_size;
|
entry->file_size = st->st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int index_entry_create(
|
||||||
* We fundamentally don't like some paths: we don't want
|
git_index_entry **out,
|
||||||
* dot or dot-dot anywhere, and for obvious reasons don't
|
git_repository *repo,
|
||||||
* want to recurse into ".git" either.
|
const char *path)
|
||||||
*
|
|
||||||
* Also, we don't want double slashes or slashes at the
|
|
||||||
* end that can make pathnames ambiguous.
|
|
||||||
*/
|
|
||||||
static int verify_dotfile(const char *rest)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The first character was '.', but that
|
|
||||||
* has already been discarded, we now test
|
|
||||||
* the rest.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* "." is not allowed */
|
|
||||||
if (*rest == '\0' || *rest == '/')
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
switch (*rest) {
|
|
||||||
/*
|
|
||||||
* ".git" followed by NUL or slash is bad. This
|
|
||||||
* shares the path end test with the ".." case.
|
|
||||||
*/
|
|
||||||
case 'g':
|
|
||||||
case 'G':
|
|
||||||
if (rest[1] != 'i' && rest[1] != 'I')
|
|
||||||
break;
|
|
||||||
if (rest[2] != 't' && rest[2] != 'T')
|
|
||||||
break;
|
|
||||||
rest += 2;
|
|
||||||
/* fallthrough */
|
|
||||||
case '.':
|
|
||||||
if (rest[1] == '\0' || rest[1] == '/')
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int verify_component(char c, const char *rest)
|
|
||||||
{
|
|
||||||
if ((c == '.' && verify_dotfile(rest)) < 0 || c == '/' || c == '\0') {
|
|
||||||
giterr_set(GITERR_INDEX, "Invalid path component in index: '%c%s'", c, rest);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int verify_path(const char *path)
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
|
|
||||||
/* TODO: should we check this? */
|
|
||||||
/*
|
|
||||||
if (has_dos_drive_prefix(path))
|
|
||||||
return -1;
|
|
||||||
*/
|
|
||||||
|
|
||||||
c = *path++;
|
|
||||||
if (verify_component(c, path) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
while ((c = *path++) != '\0') {
|
|
||||||
if (c == '/') {
|
|
||||||
c = *path++;
|
|
||||||
if (verify_component(c, path) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int index_entry_create(git_index_entry **out, const char *path)
|
|
||||||
{
|
{
|
||||||
size_t pathlen = strlen(path);
|
size_t pathlen = strlen(path);
|
||||||
struct entry_internal *entry;
|
struct entry_internal *entry;
|
||||||
|
|
||||||
if (verify_path(path) < 0)
|
if (!git_path_isvalid(repo, path,
|
||||||
|
GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT)) {
|
||||||
|
giterr_set(GITERR_INDEX, "Invalid path: '%s'", path);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
entry = git__calloc(sizeof(struct entry_internal) + pathlen + 1, 1);
|
entry = git__calloc(sizeof(struct entry_internal) + pathlen + 1, 1);
|
||||||
GITERR_CHECK_ALLOC(entry);
|
GITERR_CHECK_ALLOC(entry);
|
||||||
@ -855,7 +788,9 @@ static int index_entry_create(git_index_entry **out, const char *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int index_entry_init(
|
static int index_entry_init(
|
||||||
git_index_entry **entry_out, git_index *index, const char *rel_path)
|
git_index_entry **entry_out,
|
||||||
|
git_index *index,
|
||||||
|
const char *rel_path)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
git_index_entry *entry = NULL;
|
git_index_entry *entry = NULL;
|
||||||
@ -867,7 +802,7 @@ static int index_entry_init(
|
|||||||
"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, rel_path) < 0)
|
if (index_entry_create(&entry, INDEX_OWNER(index), rel_path) < 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 */
|
||||||
@ -933,7 +868,10 @@ static void index_entry_cpy(git_index_entry *tgt, const git_index_entry *src)
|
|||||||
tgt->path = tgt_path; /* reset to existing path data */
|
tgt->path = tgt_path; /* reset to existing path data */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int index_entry_dup(git_index_entry **out, const git_index_entry *src)
|
static int index_entry_dup(
|
||||||
|
git_index_entry **out,
|
||||||
|
git_repository *repo,
|
||||||
|
const git_index_entry *src)
|
||||||
{
|
{
|
||||||
git_index_entry *entry;
|
git_index_entry *entry;
|
||||||
|
|
||||||
@ -942,7 +880,7 @@ static int index_entry_dup(git_index_entry **out, const git_index_entry *src)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index_entry_create(&entry, src->path) < 0)
|
if (index_entry_create(&entry, repo, src->path) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
index_entry_cpy(entry, src);
|
index_entry_cpy(entry, src);
|
||||||
@ -1211,7 +1149,7 @@ int git_index_add(git_index *index, const git_index_entry *source_entry)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = index_entry_dup(&entry, source_entry)) < 0 ||
|
if ((ret = index_entry_dup(&entry, INDEX_OWNER(index), source_entry)) < 0 ||
|
||||||
(ret = index_insert(index, &entry, 1)) < 0)
|
(ret = index_insert(index, &entry, 1)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -1331,9 +1269,9 @@ int git_index_conflict_add(git_index *index,
|
|||||||
|
|
||||||
assert (index);
|
assert (index);
|
||||||
|
|
||||||
if ((ret = index_entry_dup(&entries[0], ancestor_entry)) < 0 ||
|
if ((ret = index_entry_dup(&entries[0], INDEX_OWNER(index), ancestor_entry)) < 0 ||
|
||||||
(ret = index_entry_dup(&entries[1], our_entry)) < 0 ||
|
(ret = index_entry_dup(&entries[1], INDEX_OWNER(index), our_entry)) < 0 ||
|
||||||
(ret = index_entry_dup(&entries[2], their_entry)) < 0)
|
(ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0)
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
@ -1850,7 +1788,10 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size_t read_entry(
|
static size_t read_entry(
|
||||||
git_index_entry **out, const void *buffer, size_t buffer_size)
|
git_index_entry **out,
|
||||||
|
git_index *index,
|
||||||
|
const void *buffer,
|
||||||
|
size_t buffer_size)
|
||||||
{
|
{
|
||||||
size_t path_length, entry_size;
|
size_t path_length, entry_size;
|
||||||
const char *path_ptr;
|
const char *path_ptr;
|
||||||
@ -1914,7 +1855,7 @@ static size_t read_entry(
|
|||||||
|
|
||||||
entry.path = (char *)path_ptr;
|
entry.path = (char *)path_ptr;
|
||||||
|
|
||||||
if (index_entry_dup(out, &entry) < 0)
|
if (index_entry_dup(out, INDEX_OWNER(index), &entry) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return entry_size;
|
return entry_size;
|
||||||
@ -2015,7 +1956,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
|
|||||||
/* Parse all the entries */
|
/* Parse all the entries */
|
||||||
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
|
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
|
||||||
git_index_entry *entry;
|
git_index_entry *entry;
|
||||||
size_t entry_size = read_entry(&entry, buffer, buffer_size);
|
size_t entry_size = read_entry(&entry, index, buffer, buffer_size);
|
||||||
|
|
||||||
/* 0 bytes read means an object corruption */
|
/* 0 bytes read means an object corruption */
|
||||||
if (entry_size == 0) {
|
if (entry_size == 0) {
|
||||||
@ -2376,6 +2317,7 @@ int git_index_entry_stage(const git_index_entry *entry)
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef struct read_tree_data {
|
typedef struct read_tree_data {
|
||||||
|
git_index *index;
|
||||||
git_vector *old_entries;
|
git_vector *old_entries;
|
||||||
git_vector *new_entries;
|
git_vector *new_entries;
|
||||||
git_vector_cmp entry_cmp;
|
git_vector_cmp entry_cmp;
|
||||||
@ -2396,7 +2338,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, path.ptr) < 0)
|
if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
entry->mode = tentry->attr;
|
entry->mode = tentry->attr;
|
||||||
@ -2437,6 +2379,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
|
|||||||
|
|
||||||
git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
|
git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
|
||||||
|
|
||||||
|
data.index = index;
|
||||||
data.old_entries = &index->entries;
|
data.old_entries = &index->entries;
|
||||||
data.new_entries = &entries;
|
data.new_entries = &entries;
|
||||||
data.entry_cmp = index->entries_search;
|
data.entry_cmp = index->entries_search;
|
||||||
@ -2556,7 +2499,7 @@ int git_index_add_all(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* make the new entry to insert */
|
/* make the new entry to insert */
|
||||||
if ((error = index_entry_dup(&entry, wd)) < 0)
|
if ((error = index_entry_dup(&entry, INDEX_OWNER(index), wd)) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
entry->id = blobid;
|
entry->id = blobid;
|
||||||
|
148
src/path.c
148
src/path.c
@ -7,6 +7,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
|
#include "repository.h"
|
||||||
#ifdef GIT_WIN32
|
#ifdef GIT_WIN32
|
||||||
#include "win32/posix.h"
|
#include "win32/posix.h"
|
||||||
#include "win32/w32_util.h"
|
#include "win32/w32_util.h"
|
||||||
@ -1238,3 +1239,150 @@ int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path)
|
|||||||
else
|
else
|
||||||
return git_buf_sets(local_path_out, url_or_path);
|
return git_buf_sets(local_path_out, url_or_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GIT_INLINE(bool) verify_shortname(
|
||||||
|
git_repository *repo,
|
||||||
|
const char *component,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
const char *shortname_repo;
|
||||||
|
|
||||||
|
if (len == git_repository__8dot3_default_len &&
|
||||||
|
strncasecmp(git_repository__8dot3_default, component, len) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (repo &&
|
||||||
|
(shortname_repo = git_repository__8dot3_name(repo)) &&
|
||||||
|
shortname_repo != git_repository__8dot3_default &&
|
||||||
|
git__prefixncmp_icase(component, len, shortname_repo) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reject paths like AUX or COM1, or those versions that end in a dot or
|
||||||
|
* colon. ("AUX." or "AUX:")
|
||||||
|
*/
|
||||||
|
GIT_INLINE(bool) verify_dospath(
|
||||||
|
const char *component,
|
||||||
|
size_t len,
|
||||||
|
const char dospath[3],
|
||||||
|
bool trailing_num)
|
||||||
|
{
|
||||||
|
size_t last = trailing_num ? 4 : 3;
|
||||||
|
|
||||||
|
if (len < last || git__strncasecmp(component, dospath, 3) != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (trailing_num && !git__isdigit(component[3]))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return (len > last &&
|
||||||
|
component[last] != '.' &&
|
||||||
|
component[last] != ':');
|
||||||
|
}
|
||||||
|
|
||||||
|
GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags)
|
||||||
|
{
|
||||||
|
if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (flags & GIT_PATH_REJECT_NT_CHARS) {
|
||||||
|
if (c < 32)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
case ':':
|
||||||
|
case '"':
|
||||||
|
case '|':
|
||||||
|
case '?':
|
||||||
|
case '*':
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* be handled by tools that use the non-\\?\ APIs, we don't want slashes
|
||||||
|
* or double slashes at the end of paths that can make them ambiguous.
|
||||||
|
*
|
||||||
|
* For checkout, we don't want to recurse into ".git" either.
|
||||||
|
*/
|
||||||
|
static bool verify_component(
|
||||||
|
git_repository *repo,
|
||||||
|
const char *component,
|
||||||
|
size_t len,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_TRAVERSAL) &&
|
||||||
|
len == 1 && component[0] == '.')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_TRAVERSAL) &&
|
||||||
|
len == 2 && component[0] == '.' && component[1] == '.')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_DOT_GIT) && len == 4 &&
|
||||||
|
component[0] == '.' &&
|
||||||
|
(component[1] == 'g' || component[1] == 'G') &&
|
||||||
|
(component[2] == 'i' || component[2] == 'I') &&
|
||||||
|
(component[3] == 't' || component[3] == 'T'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_TRAILING_DOT) && component[len-1] == '.')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_TRAILING_SPACE) && component[len-1] == ' ')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_TRAILING_COLON) && component[len-1] == ':')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_DOS_GIT_SHORTNAME) &&
|
||||||
|
!verify_shortname(repo, component, len))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (flags & GIT_PATH_REJECT_DOS_PATHS) {
|
||||||
|
if (!verify_dospath(component, len, "CON", false) ||
|
||||||
|
!verify_dospath(component, len, "PRN", false) ||
|
||||||
|
!verify_dospath(component, len, "AUX", false) ||
|
||||||
|
!verify_dospath(component, len, "NUL", false) ||
|
||||||
|
!verify_dospath(component, len, "COM", true) ||
|
||||||
|
!verify_dospath(component, len, "LPT", true))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool git_path_isvalid(
|
||||||
|
git_repository *repo,
|
||||||
|
const char *path,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
const char *start, *c;
|
||||||
|
|
||||||
|
for (start = c = path; *c; c++) {
|
||||||
|
if (!verify_char(*c, flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (*c == '/') {
|
||||||
|
if (!verify_component(repo, start, (c - start), flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
start = c+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return verify_component(repo, start, (c - start), flags);
|
||||||
|
}
|
||||||
|
38
src/path.h
38
src/path.h
@ -462,4 +462,42 @@ extern bool git_path_does_fs_decompose_unicode(const char *root);
|
|||||||
extern bool git_path_is_local_file_url(const char *file_url);
|
extern bool git_path_is_local_file_url(const char *file_url);
|
||||||
extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path);
|
extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path);
|
||||||
|
|
||||||
|
/* Flags to determine path validity in `git_path_isvalid` */
|
||||||
|
#define GIT_PATH_REJECT_TRAVERSAL (1 << 0)
|
||||||
|
#define GIT_PATH_REJECT_DOT_GIT (1 << 1)
|
||||||
|
#define GIT_PATH_REJECT_BACKSLASH (1 << 2)
|
||||||
|
#define GIT_PATH_REJECT_TRAILING_DOT (1 << 3)
|
||||||
|
#define GIT_PATH_REJECT_TRAILING_SPACE (1 << 4)
|
||||||
|
#define GIT_PATH_REJECT_TRAILING_COLON (1 << 5)
|
||||||
|
#define GIT_PATH_REJECT_DOS_GIT_SHORTNAME (1 << 6)
|
||||||
|
#define GIT_PATH_REJECT_DOS_PATHS (1 << 7)
|
||||||
|
#define GIT_PATH_REJECT_NT_CHARS (1 << 8)
|
||||||
|
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
# define GIT_PATH_REJECT_DEFAULTS \
|
||||||
|
GIT_PATH_REJECT_TRAVERSAL | \
|
||||||
|
GIT_PATH_REJECT_BACKSLASH | \
|
||||||
|
GIT_PATH_REJECT_TRAILING_DOT | \
|
||||||
|
GIT_PATH_REJECT_TRAILING_SPACE | \
|
||||||
|
GIT_PATH_REJECT_TRAILING_COLON | \
|
||||||
|
GIT_PATH_REJECT_DOS_GIT_SHORTNAME | \
|
||||||
|
GIT_PATH_REJECT_DOS_PATHS | \
|
||||||
|
GIT_PATH_REJECT_NT_CHARS
|
||||||
|
#else
|
||||||
|
# define GIT_PATH_REJECT_DEFAULTS GIT_PATH_REJECT_TRAVERSAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine whether a path is a valid git path or not - this must not contain
|
||||||
|
* a '.' or '..' component, or a component that is ".git" (in any case).
|
||||||
|
*
|
||||||
|
* `repo` is optional. If specified, it will be used to determine the short
|
||||||
|
* path name to reject (if `GIT_PATH_REJECT_DOS_SHORTNAME` is specified),
|
||||||
|
* in addition to the default of "git~1".
|
||||||
|
*/
|
||||||
|
extern bool git_path_isvalid(
|
||||||
|
git_repository *repo,
|
||||||
|
const char *path,
|
||||||
|
unsigned int flags);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -712,6 +712,11 @@ 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_DEFAULTS)) {
|
||||||
|
giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", name);
|
||||||
|
return GIT_EINVALIDSPEC;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove a possibly existing empty directory hierarchy
|
/* Remove a possibly existing empty directory hierarchy
|
||||||
* which name would collide with the reference name
|
* which name would collide with the reference name
|
||||||
*/
|
*/
|
||||||
@ -1653,6 +1658,11 @@ 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_DEFAULTS)) {
|
||||||
|
giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", refname);
|
||||||
|
return GIT_EINVALIDSPEC;
|
||||||
|
}
|
||||||
|
|
||||||
if (retrieve_reflog_path(&log_path, repo, refname) < 0)
|
if (retrieve_reflog_path(&log_path, repo, refname) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
|
|
||||||
#define GIT_REPO_VERSION 0
|
#define GIT_REPO_VERSION 0
|
||||||
|
|
||||||
|
const char *git_repository__8dot3_default = "GIT~1";
|
||||||
|
size_t git_repository__8dot3_default_len = 5;
|
||||||
|
|
||||||
static void set_odb(git_repository *repo, git_odb *odb)
|
static void set_odb(git_repository *repo, git_odb *odb)
|
||||||
{
|
{
|
||||||
if (odb) {
|
if (odb) {
|
||||||
@ -120,6 +123,7 @@ void git_repository_free(git_repository *repo)
|
|||||||
git__free(repo->path_repository);
|
git__free(repo->path_repository);
|
||||||
git__free(repo->workdir);
|
git__free(repo->workdir);
|
||||||
git__free(repo->namespace);
|
git__free(repo->namespace);
|
||||||
|
git__free(repo->name_8dot3);
|
||||||
|
|
||||||
git__memzero(repo, sizeof(*repo));
|
git__memzero(repo, sizeof(*repo));
|
||||||
git__free(repo);
|
git__free(repo);
|
||||||
@ -791,6 +795,27 @@ const char *git_repository_get_namespace(git_repository *repo)
|
|||||||
return repo->namespace;
|
return repo->namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *git_repository__8dot3_name(git_repository *repo)
|
||||||
|
{
|
||||||
|
if (!repo->has_8dot3) {
|
||||||
|
repo->has_8dot3 = 1;
|
||||||
|
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
if (!repo->is_bare) {
|
||||||
|
repo->name_8dot3 = git_win32_path_8dot3_name(repo->path_repository);
|
||||||
|
|
||||||
|
/* We anticipate the 8.3 name is "GIT~1", so use a static for
|
||||||
|
* easy testing in the common case */
|
||||||
|
if (strcasecmp(repo->name_8dot3, git_repository__8dot3_default) == 0)
|
||||||
|
repo->has_8dot3_default = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo->has_8dot3_default ?
|
||||||
|
git_repository__8dot3_default : repo->name_8dot3;
|
||||||
|
}
|
||||||
|
|
||||||
static int check_repositoryformatversion(git_config *config)
|
static int check_repositoryformatversion(git_config *config)
|
||||||
{
|
{
|
||||||
int version;
|
int version;
|
||||||
|
@ -120,8 +120,11 @@ struct git_repository {
|
|||||||
char *path_repository;
|
char *path_repository;
|
||||||
char *workdir;
|
char *workdir;
|
||||||
char *namespace;
|
char *namespace;
|
||||||
|
char *name_8dot3;
|
||||||
|
|
||||||
unsigned is_bare:1;
|
unsigned is_bare:1,
|
||||||
|
has_8dot3:1,
|
||||||
|
has_8dot3_default:1;
|
||||||
unsigned int lru_counter;
|
unsigned int lru_counter;
|
||||||
|
|
||||||
git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX];
|
git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX];
|
||||||
@ -174,4 +177,19 @@ int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head
|
|||||||
|
|
||||||
int git_repository__cleanup_files(git_repository *repo, const char *files[], size_t files_len);
|
int git_repository__cleanup_files(git_repository *repo, const char *files[], size_t files_len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the DOS-compatible 8.3 "short name". This will return only the
|
||||||
|
* short name for the repository directory (ie, "git~1" for ".git"). This
|
||||||
|
* will always return a pointer to `git_repository__8dot3_default` when
|
||||||
|
* "GIT~1" is the short name. This will return NULL for bare repositories,
|
||||||
|
* and systems that do not have a short name.
|
||||||
|
*/
|
||||||
|
const char *git_repository__8dot3_name(git_repository *repo);
|
||||||
|
|
||||||
|
/* The default DOS-compatible 8.3 "short name" for a git repository,
|
||||||
|
* "GIT~1".
|
||||||
|
*/
|
||||||
|
extern const char *git_repository__8dot3_default;
|
||||||
|
extern size_t git_repository__8dot3_default_len;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
15
src/util.c
15
src/util.c
@ -250,6 +250,21 @@ int git__prefixcmp_icase(const char *str, const char *prefix)
|
|||||||
return strncasecmp(str, prefix, strlen(prefix));
|
return strncasecmp(str, prefix, strlen(prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
|
||||||
|
{
|
||||||
|
int s, p;
|
||||||
|
|
||||||
|
while(str_n--) {
|
||||||
|
s = (unsigned char)tolower(*str++);
|
||||||
|
p = (unsigned char)tolower(*prefix++);
|
||||||
|
|
||||||
|
if (s != p)
|
||||||
|
return s - p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0 - *prefix);
|
||||||
|
}
|
||||||
|
|
||||||
int git__suffixcmp(const char *str, const char *suffix)
|
int git__suffixcmp(const char *str, const char *suffix)
|
||||||
{
|
{
|
||||||
size_t a = strlen(str);
|
size_t a = strlen(str);
|
||||||
|
@ -106,6 +106,7 @@ GIT_INLINE(void) git__free(void *ptr)
|
|||||||
|
|
||||||
extern int git__prefixcmp(const char *str, const char *prefix);
|
extern int git__prefixcmp(const char *str, const char *prefix);
|
||||||
extern int git__prefixcmp_icase(const char *str, const char *prefix);
|
extern int git__prefixcmp_icase(const char *str, const char *prefix);
|
||||||
|
extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix);
|
||||||
extern int git__suffixcmp(const char *str, const char *suffix);
|
extern int git__suffixcmp(const char *str, const char *suffix);
|
||||||
|
|
||||||
GIT_INLINE(int) git__signum(int val)
|
GIT_INLINE(int) git__signum(int val)
|
||||||
|
@ -267,3 +267,39 @@ int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src)
|
|||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *git_win32_path_8dot3_name(const char *path)
|
||||||
|
{
|
||||||
|
git_win32_path longpath, shortpath;
|
||||||
|
wchar_t *start;
|
||||||
|
char *shortname;
|
||||||
|
int len, namelen = 1;
|
||||||
|
|
||||||
|
if (git_win32_path_from_utf8(longpath, path) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
len = GetShortPathNameW(longpath, shortpath, GIT_WIN_PATH_UTF16);
|
||||||
|
|
||||||
|
while (len && shortpath[len-1] == L'\\')
|
||||||
|
shortpath[--len] = L'\0';
|
||||||
|
|
||||||
|
if (len == 0 || len >= GIT_WIN_PATH_UTF16)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (start = shortpath + (len - 1);
|
||||||
|
start > shortpath && *(start-1) != '/' && *(start-1) != '\\';
|
||||||
|
start--)
|
||||||
|
namelen++;
|
||||||
|
|
||||||
|
/* We may not have actually been given a short name. But if we have,
|
||||||
|
* it will be in the ASCII byte range, so we don't need to worry about
|
||||||
|
* multi-byte sequences and can allocate naively.
|
||||||
|
*/
|
||||||
|
if (namelen > 12 || (shortname = git__malloc(namelen + 1)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((len = git__utf16_to_8(shortname, namelen + 1, start)) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return shortname;
|
||||||
|
}
|
||||||
|
@ -26,6 +26,11 @@
|
|||||||
*/
|
*/
|
||||||
#define GIT_WIN_PATH_UTF8 (259 * 3 + 1)
|
#define GIT_WIN_PATH_UTF8 (259 * 3 + 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The length of a Windows "shortname", for 8.3 compatibility.
|
||||||
|
*/
|
||||||
|
#define GIT_WIN_PATH_SHORTNAME 13
|
||||||
|
|
||||||
/* Win32 path types */
|
/* Win32 path types */
|
||||||
typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16];
|
typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16];
|
||||||
typedef char git_win32_utf8_path[GIT_WIN_PATH_UTF8];
|
typedef char git_win32_utf8_path[GIT_WIN_PATH_UTF8];
|
||||||
@ -62,4 +67,14 @@ extern int git_win32_path_canonicalize(git_win32_path path);
|
|||||||
*/
|
*/
|
||||||
extern int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src);
|
extern int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the short name for the terminal path component in the given path.
|
||||||
|
* For example, given "C:\Foo\Bar\Asdf.txt", this will return the short name
|
||||||
|
* for the file "Asdf.txt".
|
||||||
|
*
|
||||||
|
* @param path The given path in UTF-8
|
||||||
|
* @return The name of the shortname for the given path
|
||||||
|
*/
|
||||||
|
extern char *git_win32_path_8dot3_name(const char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
251
tests/checkout/nasty.c
Normal file
251
tests/checkout/nasty.c
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
#include "clar_libgit2.h"
|
||||||
|
#include "checkout_helpers.h"
|
||||||
|
|
||||||
|
#include "git2/checkout.h"
|
||||||
|
#include "repository.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
static const char *repo_name = "nasty";
|
||||||
|
static git_repository *repo;
|
||||||
|
static git_checkout_options checkout_opts;
|
||||||
|
|
||||||
|
void test_checkout_nasty__initialize(void)
|
||||||
|
{
|
||||||
|
repo = cl_git_sandbox_init(repo_name);
|
||||||
|
|
||||||
|
GIT_INIT_STRUCTURE(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION);
|
||||||
|
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_checkout_nasty__cleanup(void)
|
||||||
|
{
|
||||||
|
cl_git_sandbox_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_checkout_fails(const char *refname, const char *filename)
|
||||||
|
{
|
||||||
|
git_oid commit_id;
|
||||||
|
git_commit *commit;
|
||||||
|
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||||
|
git_buf path = GIT_BUF_INIT;
|
||||||
|
|
||||||
|
cl_git_pass(git_buf_joinpath(&path, repo_name, filename));
|
||||||
|
|
||||||
|
cl_git_pass(git_reference_name_to_id(&commit_id, repo, refname));
|
||||||
|
cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
|
||||||
|
|
||||||
|
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||||
|
|
||||||
|
cl_git_fail(git_checkout_tree(repo, (const git_object *)commit, &opts));
|
||||||
|
cl_assert(!git_path_exists(path.ptr));
|
||||||
|
|
||||||
|
git_commit_free(commit);
|
||||||
|
git_buf_free(&path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains ".git" as a tree, with a blob inside
|
||||||
|
* (".git/foobar").
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dotgit_tree(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotgit_tree", ".git/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains ".GIT" as a tree, with a blob inside
|
||||||
|
* (".GIT/foobar").
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dotcapitalgit_tree(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotcapitalgit_tree", ".GIT/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a tree ".", with a blob inside ("./foobar").
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dot_tree(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dot_tree", "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a tree ".", with a tree ".git", with a blob
|
||||||
|
* inside ("./.git/foobar").
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dot_dotgit_tree(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dot_dotgit_tree", ".git/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a tree, with a tree "..", with a tree ".git", with a
|
||||||
|
* blob inside ("foo/../.git/foobar").
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dotdot_dotgit_tree(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotdot_dotgit_tree", ".git/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a tree, with a tree "..", with a blob inside
|
||||||
|
* ("foo/../foobar").
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dotdot_tree(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotdot_tree", "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name ".git/foobar" */
|
||||||
|
void test_checkout_nasty__dotgit_path(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotgit_path", ".git/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name ".GIT/foobar" */
|
||||||
|
void test_checkout_nasty__dotcapitalgit_path(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotcapitalgit_path", ".GIT/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name "./.git/foobar" */
|
||||||
|
void test_checkout_nasty__dot_dotgit_path(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dot_dotgit_path", ".git/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name "./.GIT/foobar" */
|
||||||
|
void test_checkout_nasty__dot_dotcapitalgit_path(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dot_dotcapitalgit_path", ".GIT/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name "foo/../.git/foobar" */
|
||||||
|
void test_checkout_nasty__dotdot_dotgit_path(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotdot_dotgit_path", ".git/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name "foo/../.GIT/foobar" */
|
||||||
|
void test_checkout_nasty__dotdot_dotcapitalgit_path(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotdot_dotcapitalgit_path", ".GIT/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name "foo/." */
|
||||||
|
void test_checkout_nasty__dot_path(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dot_path", "./foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name "foo/." */
|
||||||
|
void test_checkout_nasty__dot_path_two(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dot_path_two", "foo/.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains a blob with the rogue name "foo/../foobar" */
|
||||||
|
void test_checkout_nasty__dotdot_path(void)
|
||||||
|
{
|
||||||
|
test_checkout_fails("refs/heads/dotdot_path", "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry with a backslash ".git\foobar" */
|
||||||
|
void test_checkout_nasty__dotgit_backslash_path(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
test_checkout_fails("refs/heads/dotgit_backslash_path", ".git/foobar");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry with a backslash ".GIT\foobar" */
|
||||||
|
void test_checkout_nasty__dotcapitalgit_backslash_path(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
test_checkout_fails("refs/heads/dotcapitalgit_backslash_path", ".GIT/foobar");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry with a backslash ".\.GIT\foobar" */
|
||||||
|
void test_checkout_nasty__dot_backslash_dotcapitalgit_path(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
test_checkout_fails("refs/heads/dot_backslash_dotcapitalgit_path", ".GIT/foobar");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry ".git.", because Win32 APIs will drop the
|
||||||
|
* trailing slash.
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dot_git_dot(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
test_checkout_fails("refs/heads/dot_git_dot", ".git/foobar");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry "git~1", because that is typically the
|
||||||
|
* short name for ".git".
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__git_tilde1(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
test_checkout_fails("refs/heads/git_tilde1", ".git/foobar");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry "git~2", when we have forced the short
|
||||||
|
* name for ".git" into "GIT~2".
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__git_custom_shortname(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
cl_must_pass(p_rename("nasty/.git", "nasty/_temp"));
|
||||||
|
cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666);
|
||||||
|
cl_must_pass(p_rename("nasty/_temp", "nasty/.git"));
|
||||||
|
test_checkout_fails("refs/heads/git_tilde2", ".git/foobar");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry "git~3", which should be allowed, since
|
||||||
|
* it is not the typical short name ("GIT~1") or the actual short name
|
||||||
|
* ("GIT~2") for ".git".
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__only_looks_like_a_git_shortname(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
git_oid commit_id;
|
||||||
|
git_commit *commit;
|
||||||
|
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||||
|
|
||||||
|
cl_must_pass(p_rename("nasty/.git", "nasty/_temp"));
|
||||||
|
cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666);
|
||||||
|
cl_must_pass(p_rename("nasty/_temp", "nasty/.git"));
|
||||||
|
|
||||||
|
cl_git_pass(git_reference_name_to_id(&commit_id, repo, "refs/heads/git_tilde3"));
|
||||||
|
cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
|
||||||
|
|
||||||
|
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||||
|
|
||||||
|
cl_git_pass(git_checkout_tree(repo, (const git_object *)commit, &opts));
|
||||||
|
cl_assert(git_path_exists("nasty/git~3/foobar"));
|
||||||
|
|
||||||
|
git_commit_free(commit);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry "git:", because Win32 APIs will reject
|
||||||
|
* that as looking too similar to a drive letter.
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dot_git_colon(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
test_checkout_fails("refs/heads/dot_git_colon", ".git/foobar");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A tree that contains an entry "git:foo", because Win32 APIs will turn
|
||||||
|
* that into ".git".
|
||||||
|
*/
|
||||||
|
void test_checkout_nasty__dot_git_colon_stuff(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
test_checkout_fails("refs/heads/dot_git_colon_stuff", ".git/foobar");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -51,3 +51,197 @@ void test_path_core__make_relative(void)
|
|||||||
test_make_relative("/path", "/path", "pathtofoo", GIT_ENOTFOUND);
|
test_make_relative("/path", "/path", "pathtofoo", GIT_ENOTFOUND);
|
||||||
test_make_relative("path", "path", "pathtofoo", GIT_ENOTFOUND);
|
test_make_relative("path", "path", "pathtofoo", GIT_ENOTFOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_path_core__isvalid_empty_dir_component(void)
|
||||||
|
{
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo//bar", 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));
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", GIT_PATH_REJECT_DOT_GIT));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", GIT_PATH_REJECT_DOT_GIT));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", GIT_PATH_REJECT_DOT_GIT));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", GIT_PATH_REJECT_DOT_GIT));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", GIT_PATH_REJECT_DOT_GIT));
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_path_core__isvalid_dos_git_shortname(void)
|
||||||
|
{
|
||||||
|
cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0));
|
||||||
|
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", GIT_PATH_REJECT_DOS_GIT_SHORTNAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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(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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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(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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_core_path__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));
|
||||||
|
}
|
||||||
|
@ -188,3 +188,27 @@ void test_path_win32__canonicalize(void)
|
|||||||
test_canonicalize(L"\\\\server\\..\\..\\share\\.\\foo", L"\\\\server\\share\\foo");
|
test_canonicalize(L"\\\\server\\..\\..\\share\\.\\foo", L"\\\\server\\share\\foo");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_path_win32__8dot3_name(void)
|
||||||
|
{
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
char *shortname;
|
||||||
|
|
||||||
|
/* Some guaranteed short names */
|
||||||
|
cl_assert_equal_s("PROGRA~1", (shortname = git_win32_path_8dot3_name("C:\\Program Files")));
|
||||||
|
git__free(shortname);
|
||||||
|
|
||||||
|
cl_assert_equal_s("WINDOWS", (shortname = git_win32_path_8dot3_name("C:\\WINDOWS")));
|
||||||
|
git__free(shortname);
|
||||||
|
|
||||||
|
/* Create some predictible short names */
|
||||||
|
cl_must_pass(p_mkdir(".foo", 0777));
|
||||||
|
cl_assert_equal_s("FOO~1", (shortname = git_win32_path_8dot3_name(".foo")));
|
||||||
|
git__free(shortname);
|
||||||
|
|
||||||
|
cl_git_write2file("bar~1", "foobar\n", 7, O_RDWR|O_CREAT, 0666);
|
||||||
|
cl_must_pass(p_mkdir(".bar", 0777));
|
||||||
|
cl_assert_equal_s("BAR~2", (shortname = git_win32_path_8dot3_name(".bar")));
|
||||||
|
git__free(shortname);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
BIN
tests/resources/nasty/.gitted/HEAD
Normal file
BIN
tests/resources/nasty/.gitted/HEAD
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/index
Normal file
BIN
tests/resources/nasty/.gitted/index
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_dotcapitalgit_path
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_dotcapitalgit_path
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_dotgit_path
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_dotgit_path
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_dotgit_tree
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_dotgit_tree
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_git_colon
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_git_colon
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_git_colon_stuff
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_git_colon_stuff
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_git_dot
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_git_dot
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_path
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_path
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_path_two
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_path_two
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dot_tree
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dot_tree
Normal file
Binary file not shown.
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotcapitalgit_path
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotcapitalgit_path
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotcapitalgit_tree
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotcapitalgit_tree
Normal file
Binary file not shown.
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotdot_dotgit_path
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotdot_dotgit_path
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotdot_dotgit_tree
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotdot_dotgit_tree
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotdot_path
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotdot_path
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotdot_tree
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotdot_tree
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotgit_backslash_path
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotgit_backslash_path
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotgit_path
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotgit_path
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/dotgit_tree
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/dotgit_tree
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/git_tilde1
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/git_tilde1
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/git_tilde2
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/git_tilde2
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/git_tilde3
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/git_tilde3
Normal file
Binary file not shown.
BIN
tests/resources/nasty/.gitted/refs/heads/master
Normal file
BIN
tests/resources/nasty/.gitted/refs/heads/master
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user