Commit 928b4cad by Carlos Martín Nieto

Merge pull request #3005 from libgit2/cmn/maint-update

Backports for the maint branch
parents 79010d09 1f726d05
......@@ -42,7 +42,6 @@ OPTION( VALGRIND "Configure build for valgrind" OFF )
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET( USE_ICONV ON )
ADD_DEFINITIONS(-DGIT_COMMON_CRYPTO)
ENDIF()
IF(MSVC)
......@@ -172,6 +171,8 @@ ENDIF()
IF (WIN32 AND NOT MINGW AND NOT SHA1_TYPE STREQUAL "builtin")
ADD_DEFINITIONS(-DWIN32_SHA1)
FILE(GLOB SRC_SHA1 src/hash/hash_win32.c)
ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
ADD_DEFINITIONS(-DGIT_COMMON_CRYPTO)
ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin")
ADD_DEFINITIONS(-DOPENSSL_SHA1)
IF (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
......@@ -217,7 +218,8 @@ IF (USE_SSH)
ENDIF()
IF (LIBSSH2_FOUND)
ADD_DEFINITIONS(-DGIT_SSH)
INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIRS})
LINK_DIRECTORIES(${LIBSSH2_LIBRARY_DIRS})
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} libssh2")
SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES})
ENDIF()
......
......@@ -342,8 +342,8 @@ GIT_EXTERN(int) git_repository_head_unborn(git_repository *repo);
/**
* Check if a repository is empty
*
* An empty repository has just been initialized and contains
* no references.
* An empty repository has just been initialized and contains no references
* apart from HEAD, which must be pointing to the unborn master branch.
*
* @param repo Repo to test
* @return 1 if the repository is empty, 0 if it isn't, error code
......
......@@ -7,6 +7,9 @@
#ifndef INCLUDE_sys_git_repository_h__
#define INCLUDE_sys_git_repository_h__
#include "git2/common.h"
#include "git2/types.h"
/**
* @file git2/sys/repository.h
* @brief Git repository custom implementation routines
......@@ -53,7 +56,7 @@ GIT_EXTERN(void) git_repository__cleanup(git_repository *repo);
*
* @param repo A repository object
* @param recurse_submodules Should submodules be updated recursively
* @returrn 0 on success, < 0 on error
* @return 0 on success, < 0 on error
*/
GIT_EXTERN(int) git_repository_reinit_filesystem(
git_repository *repo,
......
......@@ -138,8 +138,13 @@ int git_branch_delete(git_reference *branch)
if (git_reference_delete(branch) < 0)
goto on_error;
if (git_reflog_delete(git_reference_owner(branch), git_reference_name(branch)) < 0)
if ((error = git_reflog_delete(git_reference_owner(branch), git_reference_name(branch))) < 0) {
if (error == GIT_ENOTFOUND) {
giterr_clear();
error = 0;
}
goto on_error;
}
error = 0;
......
......@@ -191,7 +191,10 @@ bool git_buf_text_is_binary(const git_buf *buf)
while (scan < end) {
unsigned char c = *scan++;
if (c > 0x1F && c < 0x7F)
/* Printable characters are those above SPACE (0x1F) excluding DEL,
* and including BS, ESC and FF.
*/
if ((c > 0x1F && c != 127) || c == '\b' || c == '\033' || c == '\014')
printable++;
else if (c == '\0')
return true;
......
......@@ -2212,6 +2212,7 @@ static void checkout_data_clear(checkout_data *data)
git__free(data->pfx);
data->pfx = NULL;
git_buf_free(&data->last_mkdir);
git_buf_free(&data->path);
git_buf_free(&data->tmp);
......
......@@ -1284,6 +1284,7 @@ static int config_parse(git_strmap *values, diskfile_backend *cfg_file, struct r
if (result == 0) {
result = config_parse(values, cfg_file, r, level, depth+1);
r = git_array_get(cfg_file->readers, index);
reader = git_array_get(cfg_file->readers, reader_idx);
}
else if (result == GIT_ENOTFOUND) {
giterr_clear();
......
......@@ -822,7 +822,8 @@ int git_patch__invoke_callbacks(
for (i = 0; !error && i < git_array_size(patch->hunks); ++i) {
diff_patch_hunk *h = git_array_get(patch->hunks, i);
error = hunk_cb(patch->delta, &h->hunk, payload);
if (hunk_cb)
error = hunk_cb(patch->delta, &h->hunk, payload);
if (!line_cb)
continue;
......
......@@ -330,7 +330,7 @@ int git_futils_mkdir_withperf(
{
int error = -1;
git_buf make_path = GIT_BUF_INIT;
ssize_t root = 0, min_root_len;
ssize_t root = 0, min_root_len, root_len;
char lastch = '/', *tail;
struct stat st;
......@@ -343,22 +343,29 @@ int git_futils_mkdir_withperf(
goto done;
}
/* remove trailing slashes on path */
while (make_path.ptr[make_path.size - 1] == '/') {
make_path.size--;
make_path.ptr[make_path.size] = '\0';
}
/* Trim trailing slashes (except the root) */
if ((root_len = git_path_root(make_path.ptr)) < 0)
root_len = 0;
else
root_len++;
while (make_path.size > (size_t)root_len &&
make_path.ptr[make_path.size - 1] == '/')
make_path.ptr[--make_path.size] = '\0';
/* if we are not supposed to made the last element, truncate it */
if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) {
git_buf_rtruncate_at_char(&make_path, '/');
git_path_dirname_r(&make_path, make_path.ptr);
flags |= GIT_MKDIR_SKIP_LAST;
}
if ((flags & GIT_MKDIR_SKIP_LAST) != 0)
git_buf_rtruncate_at_char(&make_path, '/');
if ((flags & GIT_MKDIR_SKIP_LAST) != 0) {
git_path_dirname_r(&make_path, make_path.ptr);
}
/* if nothing left after truncation, then we're done! */
if (!make_path.size) {
/* We were either given the root path (or trimmed it to
* the root), we don't have anything to do.
*/
if (make_path.size <= (size_t)root_len) {
error = 0;
goto done;
}
......
......@@ -292,6 +292,9 @@ static void index_entry_reuc_free(git_index_reuc_entry *reuc)
static void index_entry_free(git_index_entry *entry)
{
if (!entry)
return;
memset(&entry->id, 0, sizeof(entry->id));
git__free(entry);
}
......
......@@ -289,6 +289,7 @@ static int store_object(git_indexer *idx)
k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error);
if (!error) {
git__free(pentry);
giterr_set(GITERR_INDEXER, "cannot handle duplicate objects in pack");
goto on_error;
}
......
......@@ -8,6 +8,9 @@
#ifdef GIT_SSL
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "global.h"
#include "posix.h"
......
......@@ -56,6 +56,7 @@ static git_pack_cache_entry *new_cache_object(git_rawobj *source)
if (!e)
return NULL;
git_atomic_inc(&e->refcount);
memcpy(&e->raw, source, sizeof(git_rawobj));
return e;
......@@ -145,7 +146,11 @@ static void free_lowest_entry(git_pack_cache *cache)
}
}
static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)
static int cache_add(
git_pack_cache_entry **cached_out,
git_pack_cache *cache,
git_rawobj *base,
git_off_t offset)
{
git_pack_cache_entry *entry;
int error, exists = 0;
......@@ -171,6 +176,8 @@ static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)
assert(error != 0);
kh_value(cache->entries, k) = entry;
cache->memory_used += entry->raw.len;
*cached_out = entry;
}
git_mutex_unlock(&cache->lock);
/* Somebody beat us to adding it into the cache */
......@@ -699,7 +706,7 @@ int git_packfile_unpack(
* long as it's not already the cached one.
*/
if (!cached)
free_base = !!cache_add(&p->bases, obj, elem->base_key);
free_base = !!cache_add(&cached, &p->bases, obj, elem->base_key);
elem = &stack[elem_pos - 1];
curpos = elem->offset;
......
......@@ -634,7 +634,7 @@ int git_rebase_init(
*out = NULL;
GITERR_CHECK_VERSION(given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options");
GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options");
if (!onto)
onto = upstream;
......@@ -1058,6 +1058,8 @@ int git_rebase_finish(
assert(rebase);
GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options");
if ((error = rebase_normalize_opts(rebase->repo, &opts, given_opts)) < 0)
goto done;
......
......@@ -1771,6 +1771,15 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
goto cleanup;
}
/* If the new branch matches part of the namespace of a previously deleted branch,
* there maybe an obsolete/unused directory (or directory hierarchy) in the way.
*/
if (git_path_isdir(git_buf_cstr(&path)) &&
(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) {
error = -1;
goto cleanup;
}
error = git_futils_writebuffer(&buf, git_buf_cstr(&path), O_WRONLY|O_CREAT|O_APPEND, GIT_REFLOG_FILE_MODE);
cleanup:
......
......@@ -1459,7 +1459,7 @@ int git_remote_update_tips(
const char *reflog_message)
{
git_refspec *spec, tagspec;
git_vector refs;
git_vector refs = GIT_VECTOR_INIT;
int error;
size_t i;
......@@ -2330,6 +2330,10 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
(error = git_remote_connect(remote, GIT_DIRECTION_PUSH)) < 0)
goto cleanup;
free_refspecs(&remote->active_refspecs);
if (dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs) < 0)
goto cleanup;
if (remote->push) {
git_push_free(remote->push);
remote->push = NULL;
......
......@@ -1724,7 +1724,7 @@ int git_repository_set_bare(git_repository *repo)
if ((error = git_repository_config__weakptr(&config, repo)) < 0)
return error;
if ((error = git_config_set_bool(config, "core.bare", false)) < 0)
if ((error = git_config_set_bool(config, "core.bare", true)) < 0)
return error;
if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0)
......
......@@ -15,6 +15,11 @@ GIT_INLINE(int) git_stream_connect(git_stream *st)
return st->connect(st);
}
GIT_INLINE(int) git_stream_is_encrypted(git_stream *st)
{
return st->encrypted;
}
GIT_INLINE(int) git_stream_certificate(git_cert **out, git_stream *st)
{
if (!st->encrypted) {
......
......@@ -136,6 +136,7 @@ static void git_proto_stream_free(git_smart_subtransport_stream *stream)
t->current_stream = NULL;
git_stream_close(s->io);
git_stream_free(s->io);
git__free(s->url);
git__free(s);
......
......@@ -350,6 +350,11 @@ static int on_headers_complete(http_parser *parser)
} else {
assert(t->cred);
if (!(t->cred->credtype & allowed_auth_types)) {
giterr_set(GITERR_NET, "credentials callback returned an invalid cred type");
return t->parse_error = PARSE_ERROR_GENERIC;
}
/* Successfully acquired a credential. */
t->parse_error = PARSE_ERROR_REPLAY;
return 0;
......@@ -553,7 +558,8 @@ static int http_connect(http_subtransport *t)
error = git_stream_connect(t->io);
#ifdef GIT_SSL
if ((!error || error == GIT_ECERTIFICATE) && t->owner->certificate_check_cb != NULL) {
if ((!error || error == GIT_ECERTIFICATE) && t->owner->certificate_check_cb != NULL &&
git_stream_is_encrypted(t->io)) {
git_cert *cert;
int is_valid;
......
......@@ -448,12 +448,8 @@ int p_stat(const char* path, struct stat* buf)
git_win32_path path_w;
int len;
if ((len = git_win32_path_from_utf8(path_w, path)) < 0)
return -1;
git_win32__path_trim_end(path_w, len);
if (lstat_w(path_w, buf, false) < 0)
if ((len = git_win32_path_from_utf8(path_w, path)) < 0 ||
lstat_w(path_w, buf, false) < 0)
return -1;
/* The item is a symbolic link or mount point. No need to iterate
......
......@@ -4,7 +4,7 @@
#include "path.h"
#ifdef GIT_WIN32
# include <Windows.h>
# include <windows.h>
#endif
static git_repository *repo;
......
......@@ -830,7 +830,7 @@ void test_core_buffer__classify_with_utf8(void)
cl_assert(!git_buf_text_contains_nul(&b));
b.ptr = data1; b.size = b.asize = data1len;
cl_assert(git_buf_text_is_binary(&b));
cl_assert(!git_buf_text_is_binary(&b));
cl_assert(!git_buf_text_contains_nul(&b));
b.ptr = data2; b.size = b.asize = data2len;
......
......@@ -95,3 +95,20 @@ void test_core_stat__0(void)
cl_assert_error(ENOTDIR);
}
void test_core_stat__root(void)
{
const char *sandbox = clar_sandbox_path();
git_buf root = GIT_BUF_INIT;
int root_len;
struct stat st;
root_len = git_path_root(sandbox);
cl_assert(root_len >= 0);
git_buf_set(&root, sandbox, root_len+1);
cl_must_pass(p_stat(root.ptr, &st));
cl_assert(S_ISDIR(st.st_mode));
git_buf_free(&root);
}
......@@ -58,17 +58,17 @@ static void do_fetch(const char *url, git_remote_autotag_option_t flag, int n)
void test_online_fetch__default_git(void)
{
do_fetch("git://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 5);
do_fetch("git://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 6);
}
void test_online_fetch__default_http(void)
{
do_fetch("http://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 5);
do_fetch("http://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 6);
}
void test_online_fetch__default_https(void)
{
do_fetch("https://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 5);
do_fetch("https://github.com/libgit2/TestGitRepository.git", GIT_REMOTE_DOWNLOAD_TAGS_AUTO, 6);
}
void test_online_fetch__no_tags_git(void)
......
......@@ -196,3 +196,107 @@ void test_refs_branches_create__can_create_branch_with_unicode(void)
branch = NULL;
}
}
/**
* Verify that we can create a branch with a name that matches the
* namespace of a previously delete branch.
*
* git branch level_one/level_two
* git branch -D level_one/level_two
* git branch level_one
*
* We expect the delete to have deleted the files:
* ".git/refs/heads/level_one/level_two"
* ".git/logs/refs/heads/level_one/level_two"
* It may or may not have deleted the (now empty)
* containing directories. To match git.git behavior,
* the second create needs to implicilty delete the
* directories and create the new files.
* "refs/heads/level_one"
* "logs/refs/heads/level_one"
*
* We should not fail to create the branch or its
* reflog because of an obsolete namespace container
* directory.
*/
void test_refs_branches_create__name_vs_namespace(void)
{
const char * name;
struct item {
const char *first;
const char *second;
};
static const struct item item[] = {
{ "level_one/level_two", "level_one" },
{ "a/b/c/d/e", "a/b/c/d" },
{ "ss/tt/uu/vv/ww", "ss" },
/* And one test case that is deeper. */
{ "xx1/xx2/xx3/xx4", "xx1/xx2/xx3/xx4/xx5/xx6" },
{ NULL, NULL },
};
const struct item *p;
retrieve_known_commit(&target, repo);
for (p=item; p->first; p++) {
cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0, NULL, NULL));
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
cl_git_pass(git_branch_name(&name, branch));
cl_assert_equal_s(name, p->first);
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
branch = NULL;
cl_git_pass(git_branch_create(&branch, repo, p->second, target, 0, NULL, NULL));
git_reference_free(branch);
branch = NULL;
}
}
/**
* We still need to fail if part of the namespace is
* still in use.
*/
void test_refs_branches_create__name_vs_namespace_fail(void)
{
const char * name;
struct item {
const char *first;
const char *first_alternate;
const char *second;
};
static const struct item item[] = {
{ "level_one/level_two", "level_one/alternate", "level_one" },
{ "a/b/c/d/e", "a/b/c/d/alternate", "a/b/c/d" },
{ "ss/tt/uu/vv/ww", "ss/alternate", "ss" },
{ NULL, NULL, NULL },
};
const struct item *p;
retrieve_known_commit(&target, repo);
for (p=item; p->first; p++) {
cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0, NULL, NULL));
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
cl_git_pass(git_branch_name(&name, branch));
cl_assert_equal_s(name, p->first);
cl_git_pass(git_branch_delete(branch));
git_reference_free(branch);
branch = NULL;
cl_git_pass(git_branch_create(&branch, repo, p->first_alternate, target, 0, NULL, NULL));
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
cl_git_pass(git_branch_name(&name, branch));
cl_assert_equal_s(name, p->first_alternate);
/* we do not delete the alternate. */
git_reference_free(branch);
branch = NULL;
cl_git_fail(git_branch_create(&branch, repo, p->second, target, 0, NULL, NULL));
git_reference_free(branch);
branch = NULL;
}
}
......@@ -714,3 +714,29 @@ void test_repo_init__init_with_initial_commit(void)
git_index_free(index);
}
void test_repo_init__at_filesystem_root(void)
{
git_repository *repo;
const char *sandbox = clar_sandbox_path();
git_buf root = GIT_BUF_INIT;
int root_len;
if (!cl_getenv("GITTEST_INVASIVE_FILESYSTEM"))
cl_skip();
root_len = git_path_root(sandbox);
cl_assert(root_len >= 0);
git_buf_put(&root, sandbox, root_len+1);
git_buf_joinpath(&root, root.ptr, "libgit2_test_dir");
cl_assert(!git_path_exists(root.ptr));
cl_git_pass(git_repository_init(&repo, root.ptr, 0));
cl_assert(git_path_isdir(root.ptr));
cl_git_pass(git_futils_rmdir_r(root.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
git_buf_free(&root);
git_repository_free(repo);
}
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