Commit 41dc9f06 by Edward Thomson

Merge pull request #3501 from libgit2/cmn/for-v23

Backports for v0.23
parents fe965028 5b6b7745
...@@ -19,6 +19,7 @@ CMAKE_POLICY(SET CMP0015 NEW) ...@@ -19,6 +19,7 @@ CMAKE_POLICY(SET CMP0015 NEW)
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
INCLUDE(CheckLibraryExists) INCLUDE(CheckLibraryExists)
INCLUDE(CheckFunctionExists)
INCLUDE(AddCFlagIfSupported) INCLUDE(AddCFlagIfSupported)
INCLUDE(FindPkgConfig) INCLUDE(FindPkgConfig)
...@@ -95,6 +96,23 @@ SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.") ...@@ -95,6 +96,23 @@ SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.")
SET(LIB_INSTALL_DIR lib CACHE PATH "Where to install libraries to.") SET(LIB_INSTALL_DIR lib CACHE PATH "Where to install libraries to.")
SET(INCLUDE_INSTALL_DIR include CACHE PATH "Where to install headers to.") SET(INCLUDE_INSTALL_DIR include CACHE PATH "Where to install headers to.")
# Set a couple variables to be substituted inside the .pc file.
# We can't just use LIB_INSTALL_DIR in the .pc file, as passing them as absolue
# or relative paths is both valid and supported by cmake.
SET (PKGCONFIG_PREFIX ${CMAKE_INSTALL_PREFIX})
IF(IS_ABSOLUTE ${LIB_INSTALL_DIR})
SET (PKGCONFIG_LIBDIR ${LIB_INSTALL_DIR})
ELSE(IS_ABSOLUTE ${LIB_INSTALL_DIR})
SET (PKGCONFIG_LIBDIR "\${prefix}/${LIB_INSTALL_DIR}")
ENDIF (IS_ABSOLUTE ${LIB_INSTALL_DIR})
IF(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
SET (PKGCONFIG_INCLUDEDIR ${INCLUDE_INSTALL_DIR})
ELSE(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
SET (PKGCONFIG_INCLUDEDIR "\${prefix}/${INCLUDE_INSTALL_DIR}")
ENDIF(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
FUNCTION(TARGET_OS_LIBRARIES target) FUNCTION(TARGET_OS_LIBRARIES target)
IF(WIN32) IF(WIN32)
TARGET_LINK_LIBRARIES(${target} ws2_32) TARGET_LINK_LIBRARIES(${target} ws2_32)
...@@ -440,6 +458,21 @@ ELSE () ...@@ -440,6 +458,21 @@ ELSE ()
ENDIF () ENDIF ()
ENDIF() ENDIF()
CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
IF (HAVE_FUTIMENS)
ADD_DEFINITIONS(-DHAVE_FUTIMENS)
ENDIF ()
CHECK_FUNCTION_EXISTS(qsort_r HAVE_QSORT_R)
IF (HAVE_QSORT_R)
ADD_DEFINITIONS(-DHAVE_QSORT_R)
ENDIF ()
CHECK_FUNCTION_EXISTS(qsort_s HAVE_QSORT_S)
IF (HAVE_QSORT_S)
ADD_DEFINITIONS(-DHAVE_QSORT_S)
ENDIF ()
IF( NOT CMAKE_CONFIGURATION_TYPES ) IF( NOT CMAKE_CONFIGURATION_TYPES )
# Build Debug by default # Build Debug by default
IF (NOT CMAKE_BUILD_TYPE) IF (NOT CMAKE_BUILD_TYPE)
...@@ -546,7 +579,12 @@ INSTALL(FILES include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} ) ...@@ -546,7 +579,12 @@ INSTALL(FILES include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} )
# Tests # Tests
IF (BUILD_CLAR) IF (BUILD_CLAR)
FIND_PACKAGE(PythonInterp REQUIRED) FIND_PACKAGE(PythonInterp)
IF(NOT PYTHONINTERP_FOUND)
MESSAGE(FATAL_ERROR "Could not find a python interpeter, which is needed to build the tests. "
"Make sure python is available, or pass -DBUILD_CLAR=OFF to skip building the tests")
ENDIF()
SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources/") SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources/")
SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests") SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests")
......
...@@ -128,7 +128,7 @@ The public error API ...@@ -128,7 +128,7 @@ The public error API
bugs, but in the meantime, please code defensively and check for NULL bugs, but in the meantime, please code defensively and check for NULL
when calling this function. when calling this function.
- `void geterr_clear(void)`: This function clears the last error. The - `void giterr_clear(void)`: This function clears the last error. The
library will call this when an error is generated by low level function library will call this when an error is generated by low level function
and the higher level function handles the error. and the higher level function handles the error.
......
...@@ -10,12 +10,6 @@ ...@@ -10,12 +10,6 @@
#include <time.h> #include <time.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef _MSC_VER
# include "inttypes.h"
#else
# include <inttypes.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
# define GIT_BEGIN_DECL extern "C" { # define GIT_BEGIN_DECL extern "C" {
# define GIT_END_DECL } # define GIT_END_DECL }
...@@ -26,6 +20,14 @@ ...@@ -26,6 +20,14 @@
# define GIT_END_DECL /* empty */ # define GIT_END_DECL /* empty */
#endif #endif
#if defined(_MSC_VER) && _MSC_VER < 1800
GIT_BEGIN_DECL
# include "inttypes.h"
GIT_END_DECL
#else
# include <inttypes.h>
#endif
/** Declare a public function exported for application use. */ /** Declare a public function exported for application use. */
#if __GNUC__ >= 4 #if __GNUC__ >= 4
# define GIT_EXTERN(type) extern \ # define GIT_EXTERN(type) extern \
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "git2/net.h" #include "git2/net.h"
#include "git2/types.h" #include "git2/types.h"
#include "git2/strarray.h"
/** /**
* @file git2/sys/transport.h * @file git2/sys/transport.h
......
libdir=@CMAKE_INSTALL_PREFIX@/@LIB_INSTALL_DIR@ prefix=@PKGCONFIG_PREFIX@
includedir=@CMAKE_INSTALL_PREFIX@/@INCLUDE_INSTALL_DIR@ libdir=@PKGCONFIG_LIBDIR@
includedir=@PKGCONFIG_INCLUDEDIR@
Name: libgit2 Name: libgit2
Description: The git library, take 2 Description: The git library, take 2
......
...@@ -244,6 +244,12 @@ static int checkout_action_common( ...@@ -244,6 +244,12 @@ static int checkout_action_common(
if (delta->new_file.mode == GIT_FILEMODE_LINK && wd != NULL) if (delta->new_file.mode == GIT_FILEMODE_LINK && wd != NULL)
*action |= CHECKOUT_ACTION__REMOVE; *action |= CHECKOUT_ACTION__REMOVE;
/* if the file is on disk and doesn't match our mode, force update */
if (wd &&
GIT_PERMS_IS_EXEC(wd->mode) !=
GIT_PERMS_IS_EXEC(delta->new_file.mode))
*action |= CHECKOUT_ACTION__REMOVE;
notify = GIT_CHECKOUT_NOTIFY_UPDATED; notify = GIT_CHECKOUT_NOTIFY_UPDATED;
} }
...@@ -1501,15 +1507,6 @@ static int blob_content_to_file( ...@@ -1501,15 +1507,6 @@ static int blob_content_to_file(
if (error < 0) if (error < 0)
return error; return error;
if (GIT_PERMS_IS_EXEC(mode)) {
data->perfdata.chmod_calls++;
if ((error = p_chmod(path, mode)) < 0) {
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
return error;
}
}
if (st) { if (st) {
data->perfdata.stat_calls++; data->perfdata.stat_calls++;
......
...@@ -110,7 +110,7 @@ static int commit_quick_parse( ...@@ -110,7 +110,7 @@ static int commit_quick_parse(
const uint8_t *buffer_end = buffer + buffer_len; const uint8_t *buffer_end = buffer + buffer_len;
const uint8_t *parents_start, *committer_start; const uint8_t *parents_start, *committer_start;
int i, parents = 0; int i, parents = 0;
int commit_time; int64_t commit_time;
buffer += strlen("tree ") + GIT_OID_HEXSZ + 1; buffer += strlen("tree ") + GIT_OID_HEXSZ + 1;
...@@ -166,10 +166,10 @@ static int commit_quick_parse( ...@@ -166,10 +166,10 @@ static int commit_quick_parse(
buffer--; buffer--;
} }
if ((buffer == committer_start) || (git__strtol32(&commit_time, (char *)(buffer + 1), NULL, 10) < 0)) if ((buffer == committer_start) || (git__strtol64(&commit_time, (char *)(buffer + 1), NULL, 10) < 0))
return commit_error(commit, "cannot parse commit time"); return commit_error(commit, "cannot parse commit time");
commit->time = (time_t)commit_time; commit->time = commit_time;
commit->parsed = 1; commit->parsed = 1;
return 0; return 0;
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define PARENT2 (1 << 1) #define PARENT2 (1 << 1)
#define RESULT (1 << 2) #define RESULT (1 << 2)
#define STALE (1 << 3) #define STALE (1 << 3)
#define ALL_FLAGS (PARENT1 | PARENT2 | STALE | RESULT)
#define PARENTS_PER_COMMIT 2 #define PARENTS_PER_COMMIT 2
#define COMMIT_ALLOC \ #define COMMIT_ALLOC \
...@@ -22,7 +23,7 @@ ...@@ -22,7 +23,7 @@
typedef struct git_commit_list_node { typedef struct git_commit_list_node {
git_oid oid; git_oid oid;
uint32_t time; int64_t time;
unsigned int seen:1, unsigned int seen:1,
uninteresting:1, uninteresting:1,
topo_delay:1, topo_delay:1,
......
...@@ -471,8 +471,10 @@ static int diff_list_apply_options( ...@@ -471,8 +471,10 @@ static int diff_list_apply_options(
/* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */ /* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */
/* Set GIT_DIFFCAPS_TRUST_NANOSECS on a platform basis */ /* Don't trust nanoseconds; we do not load nanos from disk */
#ifdef GIT_USE_NSEC
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_NANOSECS; diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_NANOSECS;
#endif
/* If not given explicit `opts`, check `diff.xyz` configs */ /* If not given explicit `opts`, check `diff.xyz` configs */
if (!opts) { if (!opts) {
......
...@@ -358,6 +358,7 @@ static int format_binary( ...@@ -358,6 +358,7 @@ static int format_binary(
scan += chunk_len; scan += chunk_len;
pi->line.num_lines++; pi->line.num_lines++;
} }
git_buf_putc(pi->buf, '\n');
return 0; return 0;
} }
...@@ -416,7 +417,6 @@ static int diff_print_patch_file_binary( ...@@ -416,7 +417,6 @@ static int diff_print_patch_file_binary(
if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data, if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data,
binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 || binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 ||
(error = git_buf_putc(pi->buf, '\n')) < 0 ||
(error = format_binary(pi, binary->old_file.type, binary->old_file.data, (error = format_binary(pi, binary->old_file.type, binary->old_file.data,
binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) { binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) {
......
...@@ -191,6 +191,81 @@ static int write_deflate(git_filebuf *file, void *source, size_t len) ...@@ -191,6 +191,81 @@ static int write_deflate(git_filebuf *file, void *source, size_t len)
return 0; return 0;
} }
#define MAX_SYMLINK_DEPTH 5
static int resolve_symlink(git_buf *out, const char *path)
{
int i, error, root;
ssize_t ret;
struct stat st;
git_buf curpath = GIT_BUF_INIT, target = GIT_BUF_INIT;
if ((error = git_buf_grow(&target, GIT_PATH_MAX + 1)) < 0 ||
(error = git_buf_puts(&curpath, path)) < 0)
return error;
for (i = 0; i < MAX_SYMLINK_DEPTH; i++) {
error = p_lstat(curpath.ptr, &st);
if (error < 0 && errno == ENOENT) {
error = git_buf_puts(out, curpath.ptr);
goto cleanup;
}
if (error < 0) {
giterr_set(GITERR_OS, "failed to stat '%s'", curpath.ptr);
error = -1;
goto cleanup;
}
if (!S_ISLNK(st.st_mode)) {
error = git_buf_puts(out, curpath.ptr);
goto cleanup;
}
ret = p_readlink(curpath.ptr, target.ptr, GIT_PATH_MAX);
if (ret < 0) {
giterr_set(GITERR_OS, "failed to read symlink '%s'", curpath.ptr);
error = -1;
goto cleanup;
}
if (ret == GIT_PATH_MAX) {
giterr_set(GITERR_INVALID, "symlink target too long");
error = -1;
goto cleanup;
}
/* readlink(2) won't NUL-terminate for us */
target.ptr[ret] = '\0';
target.size = ret;
root = git_path_root(target.ptr);
if (root >= 0) {
if ((error = git_buf_puts(&curpath, target.ptr)) < 0)
goto cleanup;
} else {
git_buf dir = GIT_BUF_INIT;
if ((error = git_path_dirname_r(&dir, curpath.ptr)) < 0)
goto cleanup;
git_buf_swap(&curpath, &dir);
git_buf_free(&dir);
if ((error = git_path_apply_relative(&curpath, target.ptr)) < 0)
goto cleanup;
}
}
giterr_set(GITERR_INVALID, "maximum symlink depth reached");
error = -1;
cleanup:
git_buf_free(&curpath);
git_buf_free(&target);
return error;
}
int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode) int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode)
{ {
int compression, error = -1; int compression, error = -1;
...@@ -265,11 +340,14 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode ...@@ -265,11 +340,14 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
file->path_lock = git_buf_detach(&tmp_path); file->path_lock = git_buf_detach(&tmp_path);
GITERR_CHECK_ALLOC(file->path_lock); GITERR_CHECK_ALLOC(file->path_lock);
} else { } else {
path_len = strlen(path); git_buf resolved_path = GIT_BUF_INIT;
if ((error = resolve_symlink(&resolved_path, path)) < 0)
goto cleanup;
/* Save the original path of the file */ /* Save the original path of the file */
file->path_original = git__strdup(path); path_len = resolved_path.size;
GITERR_CHECK_ALLOC(file->path_original); file->path_original = git_buf_detach(&resolved_path);
/* create the locking path by appending ".lock" to the original */ /* create the locking path by appending ".lock" to the original */
GITERR_CHECK_ALLOC_ADD(&alloc_len, path_len, GIT_FILELOCK_EXTLENGTH); GITERR_CHECK_ALLOC_ADD(&alloc_len, path_len, GIT_FILELOCK_EXTLENGTH);
......
...@@ -1790,27 +1790,24 @@ size_t git_index_reuc_entrycount(git_index *index) ...@@ -1790,27 +1790,24 @@ size_t git_index_reuc_entrycount(git_index *index)
return index->reuc.length; return index->reuc.length;
} }
static int index_reuc_on_dup(void **old, void *new)
{
index_entry_reuc_free(*old);
*old = new;
return GIT_EEXISTS;
}
static int index_reuc_insert( static int index_reuc_insert(
git_index *index, git_index *index,
git_index_reuc_entry *reuc, git_index_reuc_entry *reuc)
int replace)
{ {
git_index_reuc_entry **existing = NULL; int res;
size_t position;
assert(index && reuc && reuc->path != NULL); assert(index && reuc && reuc->path != NULL);
assert(git_vector_is_sorted(&index->reuc));
if (!git_index_reuc_find(&position, index, reuc->path)) res = git_vector_insert_sorted(&index->reuc, reuc, &index_reuc_on_dup);
existing = (git_index_reuc_entry **)&index->reuc.contents[position]; return res == GIT_EEXISTS ? 0 : res;
if (!replace || !existing)
return git_vector_insert(&index->reuc, reuc);
/* exists, replace it */
git__free(*existing);
*existing = reuc;
return 0;
} }
int git_index_reuc_add(git_index *index, const char *path, int git_index_reuc_add(git_index *index, const char *path,
...@@ -1825,7 +1822,7 @@ int git_index_reuc_add(git_index *index, const char *path, ...@@ -1825,7 +1822,7 @@ int git_index_reuc_add(git_index *index, const char *path,
if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode, if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode,
ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 || ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
(error = index_reuc_insert(index, reuc, 1)) < 0) (error = index_reuc_insert(index, reuc)) < 0)
index_entry_reuc_free(reuc); index_entry_reuc_free(reuc);
return error; return error;
...@@ -1845,7 +1842,7 @@ const git_index_reuc_entry *git_index_reuc_get_bypath( ...@@ -1845,7 +1842,7 @@ const git_index_reuc_entry *git_index_reuc_get_bypath(
if (!index->reuc.length) if (!index->reuc.length)
return NULL; return NULL;
git_vector_sort(&index->reuc); assert(git_vector_is_sorted(&index->reuc));
if (git_index_reuc_find(&pos, index, path) < 0) if (git_index_reuc_find(&pos, index, path) < 0)
return NULL; return NULL;
...@@ -1857,8 +1854,8 @@ const git_index_reuc_entry *git_index_reuc_get_byindex( ...@@ -1857,8 +1854,8 @@ const git_index_reuc_entry *git_index_reuc_get_byindex(
git_index *index, size_t n) git_index *index, size_t n)
{ {
assert(index); assert(index);
assert(git_vector_is_sorted(&index->reuc));
git_vector_sort(&index->reuc);
return git_vector_get(&index->reuc, n); return git_vector_get(&index->reuc, n);
} }
...@@ -1867,7 +1864,7 @@ int git_index_reuc_remove(git_index *index, size_t position) ...@@ -1867,7 +1864,7 @@ int git_index_reuc_remove(git_index *index, size_t position)
int error; int error;
git_index_reuc_entry *reuc; git_index_reuc_entry *reuc;
git_vector_sort(&index->reuc); assert(git_vector_is_sorted(&index->reuc));
reuc = git_vector_get(&index->reuc, position); reuc = git_vector_get(&index->reuc, position);
error = git_vector_remove(&index->reuc, position); error = git_vector_remove(&index->reuc, position);
......
...@@ -302,30 +302,59 @@ static int interesting(git_pqueue *list) ...@@ -302,30 +302,59 @@ static int interesting(git_pqueue *list)
return 0; return 0;
} }
int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos) static void clear_commit_marks_1(git_commit_list **plist,
git_commit_list_node *commit, unsigned int mark)
{ {
int error; while (commit) {
unsigned int i; unsigned int i;
git_commit_list_node *two;
git_commit_list *result = NULL, *tmp = NULL;
git_pqueue list;
/* If there's only the one commit, there can be no merge bases */ if (!(mark & commit->flags))
if (twos->length == 0) { return;
*out = NULL;
return 0; commit->flags &= ~mark;
for (i = 1; i < commit->out_degree; i++) {
git_commit_list_node *p = commit->parents[i];
git_commit_list_insert(p, plist);
} }
/* if the commit is repeated, we have a our merge base already */ commit = commit->out_degree ? commit->parents[0] : NULL;
git_vector_foreach(twos, i, two) {
if (one == two)
return git_commit_list_insert(one, out) ? 0 : -1;
} }
}
if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0) static void clear_commit_marks_many(git_vector *commits, unsigned int mark)
return -1; {
git_commit_list *list = NULL;
git_commit_list_node *c;
unsigned int i;
if (git_commit_list_parse(walk, one) < 0) git_vector_foreach(commits, i, c) {
git_commit_list_insert(c, &list);
}
while (list)
clear_commit_marks_1(&list, git_commit_list_pop(&list), mark);
}
static void clear_commit_marks(git_commit_list_node *commit, unsigned int mark)
{
git_commit_list *list = NULL;
git_commit_list_insert(commit, &list);
while (list)
clear_commit_marks_1(&list, git_commit_list_pop(&list), mark);
}
static int paint_down_to_common(
git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos)
{
git_pqueue list;
git_commit_list *result = NULL;
git_commit_list_node *two;
int error;
unsigned int i;
if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0)
return -1; return -1;
one->flags |= PARENT1; one->flags |= PARENT1;
...@@ -376,19 +405,138 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l ...@@ -376,19 +405,138 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
} }
git_pqueue_free(&list); git_pqueue_free(&list);
*out = result;
return 0;
}
static int remove_redundant(git_revwalk *walk, git_vector *commits)
{
git_vector work = GIT_VECTOR_INIT;
unsigned char *redundant;
unsigned int *filled_index;
unsigned int i, j;
int error = 0;
redundant = git__calloc(commits->length, 1);
GITERR_CHECK_ALLOC(redundant);
filled_index = git__calloc((commits->length - 1), sizeof(unsigned int));
GITERR_CHECK_ALLOC(filled_index);
for (i = 0; i < commits->length; ++i) {
if ((error = git_commit_list_parse(walk, commits->contents[i])) < 0)
goto done;
}
for (i = 0; i < commits->length; ++i) {
git_commit_list *common = NULL;
git_commit_list_node *commit = commits->contents[i];
if (redundant[i])
continue;
git_vector_clear(&work);
for (j = 0; j < commits->length; j++) {
if (i == j || redundant[j])
continue;
filled_index[work.length] = j;
if ((error = git_vector_insert(&work, commits->contents[j])) < 0)
goto done;
}
error = paint_down_to_common(&common, walk, commit, &work);
if (error < 0)
goto done;
if (commit->flags & PARENT2)
redundant[i] = 1;
for (j = 0; j < work.length; j++) {
git_commit_list_node *w = work.contents[j];
if (w->flags & PARENT1)
redundant[filled_index[j]] = 1;
}
clear_commit_marks(commit, ALL_FLAGS);
clear_commit_marks_many(&work, ALL_FLAGS);
git_commit_list_free(&common);
}
for (i = 0; i < commits->length; ++i) {
if (redundant[i])
commits->contents[i] = NULL;
}
done:
git__free(redundant);
git__free(filled_index);
git_vector_free(&work);
return error;
}
int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos)
{
int error;
unsigned int i;
git_commit_list_node *two;
git_commit_list *result = NULL, *tmp = NULL;
/* If there's only the one commit, there can be no merge bases */
if (twos->length == 0) {
*out = NULL;
return 0;
}
/* if the commit is repeated, we have a our merge base already */
git_vector_foreach(twos, i, two) {
if (one == two)
return git_commit_list_insert(one, out) ? 0 : -1;
}
if (git_commit_list_parse(walk, one) < 0)
return -1;
error = paint_down_to_common(&result, walk, one, twos);
if (error < 0)
return error;
/* filter out any stale commits in the results */ /* filter out any stale commits in the results */
tmp = result; tmp = result;
result = NULL; result = NULL;
while (tmp) { while (tmp) {
struct git_commit_list *next = tmp->next; git_commit_list_node *c = git_commit_list_pop(&tmp);
if (!(tmp->item->flags & STALE)) if (!(c->flags & STALE))
if (git_commit_list_insert_by_date(tmp->item, &result) == NULL) if (git_commit_list_insert_by_date(c, &result) == NULL)
return -1; return -1;
}
/*
* more than one merge base -- see if there are redundant merge
* bases and remove them
*/
if (result && result->next) {
git_vector redundant = GIT_VECTOR_INIT;
while (result)
git_vector_insert(&redundant, git_commit_list_pop(&result));
clear_commit_marks(one, ALL_FLAGS);
clear_commit_marks_many(twos, ALL_FLAGS);
if ((error = remove_redundant(walk, &redundant)) < 0) {
git_vector_free(&redundant);
return error;
}
git_vector_foreach(&redundant, i, two) {
if (two != NULL)
git_commit_list_insert_by_date(two, &result);
}
git__free(tmp); git_vector_free(&redundant);
tmp = next;
} }
*out = result; *out = result;
......
...@@ -374,10 +374,14 @@ static int backend_sort_cmp(const void *a, const void *b) ...@@ -374,10 +374,14 @@ static int backend_sort_cmp(const void *a, const void *b)
const backend_internal *backend_a = (const backend_internal *)(a); const backend_internal *backend_a = (const backend_internal *)(a);
const backend_internal *backend_b = (const backend_internal *)(b); const backend_internal *backend_b = (const backend_internal *)(b);
if (backend_a->is_alternate == backend_b->is_alternate) if (backend_b->priority == backend_a->priority) {
if (backend_a->is_alternate)
return -1;
if (backend_b->is_alternate)
return 1;
return 0;
}
return (backend_b->priority - backend_a->priority); return (backend_b->priority - backend_a->priority);
return backend_a->is_alternate ? 1 : -1;
} }
int git_odb_new(git_odb **out) int git_odb_new(git_odb **out)
...@@ -621,23 +625,18 @@ void git_odb_free(git_odb *db) ...@@ -621,23 +625,18 @@ void git_odb_free(git_odb *db)
GIT_REFCOUNT_DEC(db, odb_free); GIT_REFCOUNT_DEC(db, odb_free);
} }
int git_odb_exists(git_odb *db, const git_oid *id) static int odb_exists_1(git_odb *db, const git_oid *id, bool only_refreshed)
{ {
git_odb_object *object;
size_t i; size_t i;
bool found = false; bool found = false;
assert(db && id);
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
git_odb_object_free(object);
return (int)true;
}
for (i = 0; i < db->backends.length && !found; ++i) { for (i = 0; i < db->backends.length && !found; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend; git_odb_backend *b = internal->backend;
if (only_refreshed && !b->refresh)
continue;
if (b->exists != NULL) if (b->exists != NULL)
found = (bool)b->exists(b, id); found = (bool)b->exists(b, id);
} }
...@@ -645,43 +644,45 @@ int git_odb_exists(git_odb *db, const git_oid *id) ...@@ -645,43 +644,45 @@ int git_odb_exists(git_odb *db, const git_oid *id)
return (int)found; return (int)found;
} }
int git_odb_exists_prefix( int git_odb_exists(git_odb *db, const git_oid *id)
git_oid *out, git_odb *db, const git_oid *short_id, size_t len)
{ {
int error = GIT_ENOTFOUND, num_found = 0; git_odb_object *object;
size_t i;
git_oid key = {{0}}, last_found = {{0}}, found;
assert(db && short_id); assert(db && id);
if (len < GIT_OID_MINPREFIXLEN) if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
return git_odb__error_ambiguous("prefix length too short"); git_odb_object_free(object);
if (len > GIT_OID_HEXSZ) return (int)true;
len = GIT_OID_HEXSZ; }
if (len == GIT_OID_HEXSZ) { if (odb_exists_1(db, id, false))
if (git_odb_exists(db, short_id)) { return 1;
if (out)
git_oid_cpy(out, short_id); if (!git_odb_refresh(db))
return odb_exists_1(db, id, true);
/* Failed to refresh, hence not found */
return 0; return 0;
} else { }
return git_odb__error_notfound("no match for id prefix", short_id);
}
}
/* just copy valid part of short_id */ static int odb_exists_prefix_1(git_oid *out, git_odb *db,
memcpy(&key.id, short_id->id, (len + 1) / 2); const git_oid *key, size_t len, bool only_refreshed)
if (len & 1) {
key.id[len / 2] &= 0xF0; size_t i;
int error = GIT_ENOTFOUND, num_found = 0;
git_oid last_found = {{0}}, found;
for (i = 0; i < db->backends.length; ++i) { for (i = 0; i < db->backends.length; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend; git_odb_backend *b = internal->backend;
if (only_refreshed && !b->refresh)
continue;
if (!b->exists_prefix) if (!b->exists_prefix)
continue; continue;
error = b->exists_prefix(&found, b, &key, len); error = b->exists_prefix(&found, b, key, len);
if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
continue; continue;
if (error) if (error)
...@@ -698,13 +699,53 @@ int git_odb_exists_prefix( ...@@ -698,13 +699,53 @@ int git_odb_exists_prefix(
} }
if (!num_found) if (!num_found)
return git_odb__error_notfound("no match for id prefix", &key); return GIT_ENOTFOUND;
if (out) if (out)
git_oid_cpy(out, &last_found); git_oid_cpy(out, &last_found);
return 0; return 0;
} }
int git_odb_exists_prefix(
git_oid *out, git_odb *db, const git_oid *short_id, size_t len)
{
int error;
git_oid key = {{0}};
assert(db && short_id);
if (len < GIT_OID_MINPREFIXLEN)
return git_odb__error_ambiguous("prefix length too short");
if (len > GIT_OID_HEXSZ)
len = GIT_OID_HEXSZ;
if (len == GIT_OID_HEXSZ) {
if (git_odb_exists(db, short_id)) {
if (out)
git_oid_cpy(out, short_id);
return 0;
} else {
return git_odb__error_notfound("no match for id prefix", short_id);
}
}
/* just copy valid part of short_id */
memcpy(&key.id, short_id->id, (len + 1) / 2);
if (len & 1)
key.id[len / 2] &= 0xF0;
error = odb_exists_prefix_1(out, db, &key, len, false);
if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
error = odb_exists_prefix_1(out, db, &key, len, true);
if (error == GIT_ENOTFOUND)
return git_odb__error_notfound("no match for id prefix", &key);
return error;
}
int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id) int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)
{ {
int error; int error;
...@@ -784,36 +825,38 @@ static int hardcoded_objects(git_rawobj *raw, const git_oid *id) ...@@ -784,36 +825,38 @@ static int hardcoded_objects(git_rawobj *raw, const git_oid *id)
} }
} }
int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
bool only_refreshed)
{ {
size_t i, reads = 0; size_t i;
int error;
git_rawobj raw; git_rawobj raw;
git_odb_object *object; git_odb_object *object;
bool found = false;
assert(out && db && id); if (!hardcoded_objects(&raw, id))
found = true;
*out = git_cache_get_raw(odb_cache(db), id);
if (*out != NULL)
return 0;
error = hardcoded_objects(&raw, id);
for (i = 0; i < db->backends.length && error < 0; ++i) { for (i = 0; i < db->backends.length && !found; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend; git_odb_backend *b = internal->backend;
if (only_refreshed && !b->refresh)
continue;
if (b->read != NULL) { if (b->read != NULL) {
++reads; int error = b->read(&raw.data, &raw.len, &raw.type, b, id);
error = b->read(&raw.data, &raw.len, &raw.type, b, id); if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND)
} continue;
}
if (error && error != GIT_PASSTHROUGH) { if (error < 0)
if (!reads)
return git_odb__error_notfound("no match for id", id);
return error; return error;
found = true;
} }
}
if (!found)
return GIT_ENOTFOUND;
giterr_clear(); giterr_clear();
if ((object = odb_object__alloc(id, &raw)) == NULL) if ((object = odb_object__alloc(id, &raw)) == NULL)
...@@ -823,42 +866,48 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) ...@@ -823,42 +866,48 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
return 0; return 0;
} }
int git_odb_read_prefix( int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len) {
int error;
assert(out && db && id);
*out = git_cache_get_raw(odb_cache(db), id);
if (*out != NULL)
return 0;
error = odb_read_1(out, db, id, false);
if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
error = odb_read_1(out, db, id, true);
if (error == GIT_ENOTFOUND)
return git_odb__error_notfound("no match for id", id);
return error;
}
static int read_prefix_1(git_odb_object **out, git_odb *db,
const git_oid *key, size_t len, bool only_refreshed)
{ {
size_t i; size_t i;
int error = GIT_ENOTFOUND; int error = GIT_ENOTFOUND;
git_oid key = {{0}}, found_full_oid = {{0}}; git_oid found_full_oid = {{0}};
git_rawobj raw; git_rawobj raw;
void *data = NULL; void *data = NULL;
bool found = false; bool found = false;
git_odb_object *object; git_odb_object *object;
assert(out && db);
if (len < GIT_OID_MINPREFIXLEN)
return git_odb__error_ambiguous("prefix length too short");
if (len > GIT_OID_HEXSZ)
len = GIT_OID_HEXSZ;
if (len == GIT_OID_HEXSZ) {
*out = git_cache_get_raw(odb_cache(db), short_id);
if (*out != NULL)
return 0;
}
/* just copy valid part of short_id */
memcpy(&key.id, short_id->id, (len + 1) / 2);
if (len & 1)
key.id[len / 2] &= 0xF0;
for (i = 0; i < db->backends.length; ++i) { for (i = 0; i < db->backends.length; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend; git_odb_backend *b = internal->backend;
if (only_refreshed && !b->refresh)
continue;
if (b->read_prefix != NULL) { if (b->read_prefix != NULL) {
git_oid full_oid; git_oid full_oid;
error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, &key, len); error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len);
if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
continue; continue;
...@@ -879,7 +928,7 @@ int git_odb_read_prefix( ...@@ -879,7 +928,7 @@ int git_odb_read_prefix(
} }
if (!found) if (!found)
return git_odb__error_notfound("no match for prefix", &key); return GIT_ENOTFOUND;
if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL)
return -1; return -1;
...@@ -888,6 +937,42 @@ int git_odb_read_prefix( ...@@ -888,6 +937,42 @@ int git_odb_read_prefix(
return 0; return 0;
} }
int git_odb_read_prefix(
git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len)
{
git_oid key = {{0}};
int error;
assert(out && db);
if (len < GIT_OID_MINPREFIXLEN)
return git_odb__error_ambiguous("prefix length too short");
if (len > GIT_OID_HEXSZ)
len = GIT_OID_HEXSZ;
if (len == GIT_OID_HEXSZ) {
*out = git_cache_get_raw(odb_cache(db), short_id);
if (*out != NULL)
return 0;
}
/* just copy valid part of short_id */
memcpy(&key.id, short_id->id, (len + 1) / 2);
if (len & 1)
key.id[len / 2] &= 0xF0;
error = read_prefix_1(out, db, &key, len, false);
if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
error = read_prefix_1(out, db, &key, len, true);
if (error == GIT_ENOTFOUND)
return git_odb__error_notfound("no match for prefix", &key);
return error;
}
int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload) int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload)
{ {
unsigned int i; unsigned int i;
......
...@@ -154,12 +154,19 @@ void git_mempack_reset(git_odb_backend *_backend) ...@@ -154,12 +154,19 @@ void git_mempack_reset(git_odb_backend *_backend)
}); });
git_array_clear(db->commits); git_array_clear(db->commits);
git_oidmap_free(db->objects);
db->objects = git_oidmap_alloc();
} }
static void impl__free(git_odb_backend *_backend) static void impl__free(git_odb_backend *_backend)
{ {
git_mempack_reset(_backend); struct memory_packer_db *db = (struct memory_packer_db *)_backend;
git__free(_backend);
git_mempack_reset(db);
git_oidmap_free(db->objects);
git__free(db);
} }
int git_mempack_new(git_odb_backend **out) int git_mempack_new(git_odb_backend **out)
......
...@@ -346,7 +346,7 @@ static int pack_backend__refresh(git_odb_backend *backend_) ...@@ -346,7 +346,7 @@ static int pack_backend__refresh(git_odb_backend *backend_)
return error; return error;
} }
static int pack_backend__read_header_internal( static int pack_backend__read_header(
size_t *len_p, git_otype *type_p, size_t *len_p, git_otype *type_p,
struct git_odb_backend *backend, const git_oid *oid) struct git_odb_backend *backend, const git_oid *oid)
{ {
...@@ -361,24 +361,7 @@ static int pack_backend__read_header_internal( ...@@ -361,24 +361,7 @@ static int pack_backend__read_header_internal(
return git_packfile_resolve_header(len_p, type_p, e.p, e.offset); return git_packfile_resolve_header(len_p, type_p, e.p, e.offset);
} }
static int pack_backend__read_header( static int pack_backend__read(
size_t *len_p, git_otype *type_p,
struct git_odb_backend *backend, const git_oid *oid)
{
int error;
error = pack_backend__read_header_internal(len_p, type_p, backend, oid);
if (error != GIT_ENOTFOUND)
return error;
if ((error = pack_backend__refresh(backend)) < 0)
return error;
return pack_backend__read_header_internal(len_p, type_p, backend, oid);
}
static int pack_backend__read_internal(
void **buffer_p, size_t *len_p, git_otype *type_p, void **buffer_p, size_t *len_p, git_otype *type_p,
git_odb_backend *backend, const git_oid *oid) git_odb_backend *backend, const git_oid *oid)
{ {
...@@ -397,24 +380,7 @@ static int pack_backend__read_internal( ...@@ -397,24 +380,7 @@ static int pack_backend__read_internal(
return 0; return 0;
} }
static int pack_backend__read( static int pack_backend__read_prefix(
void **buffer_p, size_t *len_p, git_otype *type_p,
git_odb_backend *backend, const git_oid *oid)
{
int error;
error = pack_backend__read_internal(buffer_p, len_p, type_p, backend, oid);
if (error != GIT_ENOTFOUND)
return error;
if ((error = pack_backend__refresh(backend)) < 0)
return error;
return pack_backend__read_internal(buffer_p, len_p, type_p, backend, oid);
}
static int pack_backend__read_prefix_internal(
git_oid *out_oid, git_oid *out_oid,
void **buffer_p, void **buffer_p,
size_t *len_p, size_t *len_p,
...@@ -451,45 +417,9 @@ static int pack_backend__read_prefix_internal( ...@@ -451,45 +417,9 @@ static int pack_backend__read_prefix_internal(
return error; return error;
} }
static int pack_backend__read_prefix(
git_oid *out_oid,
void **buffer_p,
size_t *len_p,
git_otype *type_p,
git_odb_backend *backend,
const git_oid *short_oid,
size_t len)
{
int error;
error = pack_backend__read_prefix_internal(
out_oid, buffer_p, len_p, type_p, backend, short_oid, len);
if (error != GIT_ENOTFOUND)
return error;
if ((error = pack_backend__refresh(backend)) < 0)
return error;
return pack_backend__read_prefix_internal(
out_oid, buffer_p, len_p, type_p, backend, short_oid, len);
}
static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid) static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
{ {
struct git_pack_entry e; struct git_pack_entry e;
int error;
error = pack_entry_find(&e, (struct pack_backend *)backend, oid);
if (error != GIT_ENOTFOUND)
return error == 0;
if ((error = pack_backend__refresh(backend)) < 0) {
giterr_clear();
return (int)false;
}
return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0; return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0;
} }
...@@ -501,12 +431,7 @@ static int pack_backend__exists_prefix( ...@@ -501,12 +431,7 @@ static int pack_backend__exists_prefix(
struct git_pack_entry e = {0}; struct git_pack_entry e = {0};
error = pack_entry_find_prefix(&e, pb, short_id, len); error = pack_entry_find_prefix(&e, pb, short_id, len);
if (error == GIT_ENOTFOUND && !(error = pack_backend__refresh(backend)))
error = pack_entry_find_prefix(&e, pb, short_id, len);
git_oid_cpy(out, &e.sha1); git_oid_cpy(out, &e.sha1);
return error; return error;
} }
...@@ -674,7 +599,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) ...@@ -674,7 +599,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
git_path_isdir(git_buf_cstr(&path))) git_path_isdir(git_buf_cstr(&path)))
{ {
backend->pack_folder = git_buf_detach(&path); backend->pack_folder = git_buf_detach(&path);
error = pack_backend__refresh((git_odb_backend *)backend); error = pack_backend__refresh((git_odb_backend *)backend);
} }
......
...@@ -302,6 +302,7 @@ cert_fail_name: ...@@ -302,6 +302,7 @@ cert_fail_name:
typedef struct { typedef struct {
git_stream parent; git_stream parent;
git_stream *io; git_stream *io;
bool connected;
char *host; char *host;
SSL *ssl; SSL *ssl;
git_cert_x509 cert_info; git_cert_x509 cert_info;
...@@ -318,6 +319,8 @@ int openssl_connect(git_stream *stream) ...@@ -318,6 +319,8 @@ int openssl_connect(git_stream *stream)
if ((ret = git_stream_connect(st->io)) < 0) if ((ret = git_stream_connect(st->io)) < 0)
return ret; return ret;
st->connected = true;
bio = BIO_new(&git_stream_bio_method); bio = BIO_new(&git_stream_bio_method);
GITERR_CHECK_ALLOC(bio); GITERR_CHECK_ALLOC(bio);
bio->ptr = st->io; bio->ptr = st->io;
...@@ -405,9 +408,11 @@ int openssl_close(git_stream *stream) ...@@ -405,9 +408,11 @@ int openssl_close(git_stream *stream)
openssl_stream *st = (openssl_stream *) stream; openssl_stream *st = (openssl_stream *) stream;
int ret; int ret;
if ((ret = ssl_teardown(st->ssl)) < 0) if (st->connected && (ret = ssl_teardown(st->ssl)) < 0)
return -1; return -1;
st->connected = false;
return git_stream_close(st->io); return git_stream_close(st->io);
} }
......
...@@ -1453,7 +1453,7 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) ...@@ -1453,7 +1453,7 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size)
entry = git__calloc(1, sizeof(git_reflog_entry)); entry = git__calloc(1, sizeof(git_reflog_entry));
GITERR_CHECK_ALLOC(entry); GITERR_CHECK_ALLOC(entry);
entry->committer = git__malloc(sizeof(git_signature)); entry->committer = git__calloc(1, sizeof(git_signature));
GITERR_CHECK_ALLOC(entry->committer); GITERR_CHECK_ALLOC(entry->committer);
if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < 0) if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < 0)
......
...@@ -908,12 +908,28 @@ bool git_repository__reserved_names( ...@@ -908,12 +908,28 @@ bool git_repository__reserved_names(
buf->size = git_repository__reserved_names_win32[i].size; buf->size = git_repository__reserved_names_win32[i].size;
} }
/* Try to add any repo-specific reserved names */ /* Try to add any repo-specific reserved names - the gitlink file
* within a submodule or the repository (if the repository directory
* is beneath the workdir). These are typically `.git`, but should
* be protected in case they are not. Note, repo and workdir paths
* are always prettified to end in `/`, so a prefixcmp is safe.
*/
if (!repo->is_bare) { if (!repo->is_bare) {
const char *reserved_path = repo->path_gitlink ? int (*prefixcmp)(const char *, const char *);
repo->path_gitlink : repo->path_repository; int error, ignorecase;
error = git_repository__cvar(
&ignorecase, repo, GIT_CVAR_IGNORECASE);
prefixcmp = (error || ignorecase) ? git__prefixcmp_icase :
git__prefixcmp;
if (repo->path_gitlink &&
reserved_names_add8dot3(repo, repo->path_gitlink) < 0)
goto on_error;
if (reserved_names_add8dot3(repo, reserved_path) < 0) if (repo->path_repository &&
prefixcmp(repo->path_repository, repo->workdir) == 0 &&
reserved_names_add8dot3(repo, repo->path_repository) < 0)
goto on_error; goto on_error;
} }
} }
......
...@@ -34,13 +34,27 @@ static bool contains_angle_brackets(const char *input) ...@@ -34,13 +34,27 @@ static bool contains_angle_brackets(const char *input)
return strchr(input, '<') != NULL || strchr(input, '>') != NULL; return strchr(input, '<') != NULL || strchr(input, '>') != NULL;
} }
static bool is_crud(unsigned char c)
{
return c <= 32 ||
c == '.' ||
c == ',' ||
c == ':' ||
c == ';' ||
c == '<' ||
c == '>' ||
c == '"' ||
c == '\\' ||
c == '\'';
}
static char *extract_trimmed(const char *ptr, size_t len) static char *extract_trimmed(const char *ptr, size_t len)
{ {
while (len && git__isspace(ptr[0])) { while (len && is_crud((unsigned char)ptr[0])) {
ptr++; len--; ptr++; len--;
} }
while (len && git__isspace(ptr[len - 1])) { while (len && is_crud((unsigned char)ptr[len - 1])) {
len--; len--;
} }
......
...@@ -130,11 +130,14 @@ static int git_proto_stream_write( ...@@ -130,11 +130,14 @@ static int git_proto_stream_write(
static void git_proto_stream_free(git_smart_subtransport_stream *stream) static void git_proto_stream_free(git_smart_subtransport_stream *stream)
{ {
git_proto_stream *s = (git_proto_stream *)stream; git_proto_stream *s;
git_subtransport *t = OWNING_SUBTRANSPORT(s); git_subtransport *t;
int ret;
if (!stream)
return;
GIT_UNUSED(ret); s = (git_proto_stream *)stream;
t = OWNING_SUBTRANSPORT(s);
t->current_stream = NULL; t->current_stream = NULL;
......
...@@ -756,8 +756,10 @@ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *use ...@@ -756,8 +756,10 @@ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *use
list = libssh2_userauth_list(session, username, strlen(username)); list = libssh2_userauth_list(session, username, strlen(username));
/* either error, or the remote accepts NONE auth, which is bizarre, let's punt */ /* either error, or the remote accepts NONE auth, which is bizarre, let's punt */
if (list == NULL && !libssh2_userauth_authenticated(session)) if (list == NULL && !libssh2_userauth_authenticated(session)) {
ssh_error(session, "Failed to retrieve list of SSH authentication methods");
return -1; return -1;
}
ptr = list; ptr = list;
while (ptr) { while (ptr) {
......
...@@ -22,7 +22,6 @@ typedef int GIT_SOCKET; ...@@ -22,7 +22,6 @@ typedef int GIT_SOCKET;
#define p_stat(p,b) stat(p, b) #define p_stat(p,b) stat(p, b)
#define p_utimes(f, t) utimes(f, t) #define p_utimes(f, t) utimes(f, t)
#define p_futimes(f, t) futimes(f, t)
#define p_readlink(a, b, c) readlink(a, b, c) #define p_readlink(a, b, c) readlink(a, b, c)
#define p_symlink(o,n) symlink(o, n) #define p_symlink(o,n) symlink(o, n)
...@@ -53,4 +52,18 @@ extern char *p_realpath(const char *, char *); ...@@ -53,4 +52,18 @@ extern char *p_realpath(const char *, char *);
#define p_localtime_r(c, r) localtime_r(c, r) #define p_localtime_r(c, r) localtime_r(c, r)
#define p_gmtime_r(c, r) gmtime_r(c, r) #define p_gmtime_r(c, r) gmtime_r(c, r)
#ifdef HAVE_FUTIMENS
GIT_INLINE(int) p_futimes(int f, const struct timeval t[2])
{
struct timespec s[2];
s[0].tv_sec = t[0].tv_sec;
s[0].tv_nsec = t[0].tv_usec * 1000;
s[1].tv_sec = t[1].tv_sec;
s[1].tv_nsec = t[1].tv_usec * 1000;
return futimens(f, s);
}
#else
# define p_futimes futimes
#endif
#endif #endif
...@@ -607,7 +607,7 @@ size_t git__unescape(char *str) ...@@ -607,7 +607,7 @@ size_t git__unescape(char *str)
return (pos - str); return (pos - str);
} }
#if defined(GIT_WIN32) || defined(BSD) #if defined(HAVE_QSORT_S) || (defined(HAVE_QSORT_R) && defined(BSD))
typedef struct { typedef struct {
git__sort_r_cmp cmp; git__sort_r_cmp cmp;
void *payload; void *payload;
...@@ -624,21 +624,16 @@ static int GIT_STDLIB_CALL git__qsort_r_glue_cmp( ...@@ -624,21 +624,16 @@ static int GIT_STDLIB_CALL git__qsort_r_glue_cmp(
void git__qsort_r( void git__qsort_r(
void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload)
{ {
#if defined(__MINGW32__) || defined(AMIGA) || \ #if defined(HAVE_QSORT_R) && defined(BSD)
defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(__gnu_hurd__) || defined(__ANDROID_API__) || \
defined(__sun) || defined(__CYGWIN__) || \
(__GLIBC__ == 2 && __GLIBC_MINOR__ < 8) || \
(defined(_MSC_VER) && _MSC_VER < 1500)
git__insertsort_r(els, nel, elsize, NULL, cmp, payload);
#elif defined(GIT_WIN32)
git__qsort_r_glue glue = { cmp, payload };
qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue);
#elif defined(BSD)
git__qsort_r_glue glue = { cmp, payload }; git__qsort_r_glue glue = { cmp, payload };
qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp); qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp);
#else #elif defined(HAVE_QSORT_R) && defined(__GLIBC__)
qsort_r(els, nel, elsize, cmp, payload); qsort_r(els, nel, elsize, cmp, payload);
#elif defined(HAVE_QSORT_S)
git__qsort_r_glue glue = { cmp, payload };
qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue);
#else
git__insertsort_r(els, nel, elsize, NULL, cmp, payload);
#endif #endif
} }
......
...@@ -198,13 +198,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) ...@@ -198,13 +198,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
/* See if this is an absolute path (beginning with a drive letter) */ /* See if this is an absolute path (beginning with a drive letter) */
if (path__is_absolute(src)) { if (path__is_absolute(src)) {
if (git__utf8_to_16(dest, MAX_PATH, src) < 0) if (git__utf8_to_16(dest, MAX_PATH, src) < 0)
return -1; goto on_error;
} }
/* File-prefixed NT-style paths beginning with \\?\ */ /* File-prefixed NT-style paths beginning with \\?\ */
else if (path__is_nt_namespace(src)) { else if (path__is_nt_namespace(src)) {
/* Skip the NT prefix, the destination already contains it */ /* Skip the NT prefix, the destination already contains it */
if (git__utf8_to_16(dest, MAX_PATH, src + PATH__NT_NAMESPACE_LEN) < 0) if (git__utf8_to_16(dest, MAX_PATH, src + PATH__NT_NAMESPACE_LEN) < 0)
return -1; goto on_error;
} }
/* UNC paths */ /* UNC paths */
else if (path__is_unc(src)) { else if (path__is_unc(src)) {
...@@ -213,36 +213,43 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) ...@@ -213,36 +213,43 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
/* Skip the leading "\\" */ /* Skip the leading "\\" */
if (git__utf8_to_16(dest, MAX_PATH - 2, src + 2) < 0) if (git__utf8_to_16(dest, MAX_PATH - 2, src + 2) < 0)
return -1; goto on_error;
} }
/* Absolute paths omitting the drive letter */ /* Absolute paths omitting the drive letter */
else if (src[0] == '\\' || src[0] == '/') { else if (src[0] == '\\' || src[0] == '/') {
if (path__cwd(dest, MAX_PATH) < 0) if (path__cwd(dest, MAX_PATH) < 0)
return -1; goto on_error;
if (!path__is_absolute(dest)) { if (!path__is_absolute(dest)) {
errno = ENOENT; errno = ENOENT;
return -1; goto on_error;
} }
/* Skip the drive letter specification ("C:") */ /* Skip the drive letter specification ("C:") */
if (git__utf8_to_16(dest + 2, MAX_PATH - 2, src) < 0) if (git__utf8_to_16(dest + 2, MAX_PATH - 2, src) < 0)
return -1; goto on_error;
} }
/* Relative paths */ /* Relative paths */
else { else {
int cwd_len; int cwd_len;
if ((cwd_len = git_win32_path__cwd(dest, MAX_PATH)) < 0) if ((cwd_len = git_win32_path__cwd(dest, MAX_PATH)) < 0)
return -1; goto on_error;
dest[cwd_len++] = L'\\'; dest[cwd_len++] = L'\\';
if (git__utf8_to_16(dest + cwd_len, MAX_PATH - cwd_len, src) < 0) if (git__utf8_to_16(dest + cwd_len, MAX_PATH - cwd_len, src) < 0)
return -1; goto on_error;
} }
return git_win32_path_canonicalize(out); return git_win32_path_canonicalize(out);
on_error:
/* set windows error code so we can use its error message */
if (errno == ENAMETOOLONG)
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return -1;
} }
int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src) int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src)
......
...@@ -146,12 +146,19 @@ static int lstat_w( ...@@ -146,12 +146,19 @@ static int lstat_w(
return git_win32__file_attribute_to_stat(buf, &fdata, path); return git_win32__file_attribute_to_stat(buf, &fdata, path);
} }
switch (GetLastError()) {
case ERROR_ACCESS_DENIED:
errno = EACCES;
break;
default:
errno = ENOENT; errno = ENOENT;
break;
}
/* To match POSIX behavior, set ENOTDIR when any of the folders in the /* To match POSIX behavior, set ENOTDIR when any of the folders in the
* file path is a regular file, otherwise set ENOENT. * file path is a regular file, otherwise set ENOENT.
*/ */
if (posix_enotdir) { if (errno == ENOENT && posix_enotdir) {
size_t path_len = wcslen(path); size_t path_len = wcslen(path);
/* scan up path until we find an existing item */ /* scan up path until we find an existing item */
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* *
*/ */
#include "util.h" #include "../util.h"
#if !defined(XDIFF_H) #if !defined(XDIFF_H)
#define XDIFF_H #define XDIFF_H
......
...@@ -946,7 +946,7 @@ void test_checkout_tree__filemode_preserved_in_index(void) ...@@ -946,7 +946,7 @@ void test_checkout_tree__filemode_preserved_in_index(void)
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(entry = git_index_get_bypath(index, "executable.txt", 0)); cl_assert(entry = git_index_get_bypath(index, "executable.txt", 0));
cl_assert_equal_i(0100755, entry->mode); cl_assert(GIT_PERMS_IS_EXEC(entry->mode));
git_commit_free(commit); git_commit_free(commit);
...@@ -957,7 +957,7 @@ void test_checkout_tree__filemode_preserved_in_index(void) ...@@ -957,7 +957,7 @@ void test_checkout_tree__filemode_preserved_in_index(void)
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(entry = git_index_get_bypath(index, "a/b.txt", 0)); cl_assert(entry = git_index_get_bypath(index, "a/b.txt", 0));
cl_assert_equal_i(0100644, entry->mode); cl_assert(!GIT_PERMS_IS_EXEC(entry->mode));
git_commit_free(commit); git_commit_free(commit);
...@@ -968,7 +968,18 @@ void test_checkout_tree__filemode_preserved_in_index(void) ...@@ -968,7 +968,18 @@ void test_checkout_tree__filemode_preserved_in_index(void)
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts)); cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(entry = git_index_get_bypath(index, "a/b.txt", 0)); cl_assert(entry = git_index_get_bypath(index, "a/b.txt", 0));
cl_assert_equal_i(0100755, entry->mode); cl_assert(GIT_PERMS_IS_EXEC(entry->mode));
git_commit_free(commit);
/* Finally, check out the text file again and check that the exec bit is cleared */
cl_git_pass(git_oid_fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9"));
cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(entry = git_index_get_bypath(index, "a/b.txt", 0));
cl_assert(!GIT_PERMS_IS_EXEC(entry->mode));
git_commit_free(commit); git_commit_free(commit);
...@@ -976,6 +987,73 @@ void test_checkout_tree__filemode_preserved_in_index(void) ...@@ -976,6 +987,73 @@ void test_checkout_tree__filemode_preserved_in_index(void)
git_index_free(index); git_index_free(index);
} }
mode_t read_filemode(const char *path)
{
git_buf fullpath = GIT_BUF_INIT;
struct stat st;
mode_t result;
git_buf_joinpath(&fullpath, "testrepo", path);
cl_must_pass(p_stat(fullpath.ptr, &st));
result = GIT_PERMS_IS_EXEC(st.st_mode) ?
GIT_FILEMODE_BLOB_EXECUTABLE : GIT_FILEMODE_BLOB;
git_buf_free(&fullpath);
return result;
}
void test_checkout_tree__filemode_preserved_in_workdir(void)
{
#ifndef GIT_WIN32
git_oid executable_oid;
git_commit *commit;
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
/* test a freshly added executable */
cl_git_pass(git_oid_fromstr(&executable_oid, "afe4393b2b2a965f06acf2ca9658eaa01e0cd6b6"));
cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(GIT_PERMS_IS_EXEC(read_filemode("executable.txt")));
git_commit_free(commit);
/* Now start with a commit which has a text file */
cl_git_pass(git_oid_fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9"));
cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(!GIT_PERMS_IS_EXEC(read_filemode("a/b.txt")));
git_commit_free(commit);
/* And then check out to a commit which converts the text file to an executable */
cl_git_pass(git_oid_fromstr(&executable_oid, "144344043ba4d4a405da03de3844aa829ae8be0e"));
cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(GIT_PERMS_IS_EXEC(read_filemode("a/b.txt")));
git_commit_free(commit);
/* Finally, check out the text file again and check that the exec bit is cleared */
cl_git_pass(git_oid_fromstr(&executable_oid, "cf80f8de9f1185bf3a05f993f6121880dd0cfbc9"));
cl_git_pass(git_commit_lookup(&commit, g_repo, &executable_oid));
cl_git_pass(git_checkout_tree(g_repo, (const git_object *)commit, &opts));
cl_assert(!GIT_PERMS_IS_EXEC(read_filemode("a/b.txt")));
git_commit_free(commit);
#endif
}
void test_checkout_tree__removes_conflicts(void) void test_checkout_tree__removes_conflicts(void)
{ {
git_oid commit_id; git_oid commit_id;
......
...@@ -35,6 +35,13 @@ void test_commit_signature__leading_and_trailing_spaces_are_trimmed(void) ...@@ -35,6 +35,13 @@ void test_commit_signature__leading_and_trailing_spaces_are_trimmed(void)
assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", " \t nulltoken \n", " \n emeric.fermas@gmail.com \n"); assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", " \t nulltoken \n", " \n emeric.fermas@gmail.com \n");
} }
void test_commit_signature__leading_and_trailing_crud_is_trimmed(void)
{
assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", "\"nulltoken\"", "\"emeric.fermas@gmail.com\"");
assert_name_and_email("nulltoken w", "emeric.fermas@gmail.com", "nulltoken w.", "emeric.fermas@gmail.com");
assert_name_and_email("nulltoken \xe2\x98\xba", "emeric.fermas@gmail.com", "nulltoken \xe2\x98\xba", "emeric.fermas@gmail.com");
}
void test_commit_signature__angle_brackets_in_names_are_not_supported(void) void test_commit_signature__angle_brackets_in_names_are_not_supported(void)
{ {
cl_git_fail(try_build_signature("<Phil Haack", "phil@haack", 1234567890, 60)); cl_git_fail(try_build_signature("<Phil Haack", "phil@haack", 1234567890, 60));
......
...@@ -151,3 +151,56 @@ void test_core_filebuf__rename_error(void) ...@@ -151,3 +151,56 @@ void test_core_filebuf__rename_error(void)
cl_assert_equal_i(false, git_path_exists(test_lock)); cl_assert_equal_i(false, git_path_exists(test_lock));
} }
void test_core_filebuf__symlink_follow(void)
{
git_filebuf file = GIT_FILEBUF_INIT;
const char *dir = "linkdir", *source = "linkdir/link";
#ifdef GIT_WIN32
cl_skip();
#endif
cl_git_pass(p_mkdir(dir, 0777));
cl_git_pass(p_symlink("target", source));
cl_git_pass(git_filebuf_open(&file, source, 0, 0666));
cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
cl_assert_equal_i(true, git_path_exists("linkdir/target.lock"));
cl_git_pass(git_filebuf_commit(&file));
cl_assert_equal_i(true, git_path_exists("linkdir/target"));
git_filebuf_cleanup(&file);
/* The second time around, the target file does exist */
cl_git_pass(git_filebuf_open(&file, source, 0, 0666));
cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
cl_assert_equal_i(true, git_path_exists("linkdir/target.lock"));
cl_git_pass(git_filebuf_commit(&file));
cl_assert_equal_i(true, git_path_exists("linkdir/target"));
git_filebuf_cleanup(&file);
cl_git_pass(git_futils_rmdir_r(dir, NULL, GIT_RMDIR_REMOVE_FILES));
}
void test_core_filebuf__symlink_depth(void)
{
git_filebuf file = GIT_FILEBUF_INIT;
const char *dir = "linkdir", *source = "linkdir/link";
#ifdef GIT_WIN32
cl_skip();
#endif
cl_git_pass(p_mkdir(dir, 0777));
/* Endless loop */
cl_git_pass(p_symlink("link", source));
cl_git_fail(git_filebuf_open(&file, source, 0, 0666));
cl_git_pass(git_futils_rmdir_r(dir, NULL, GIT_RMDIR_REMOVE_FILES));
}
...@@ -96,7 +96,8 @@ void test_diff_binary__add(void) ...@@ -96,7 +96,8 @@ void test_diff_binary__add(void)
"Kc${Nk-~s>u4FC%O\n" "Kc${Nk-~s>u4FC%O\n"
"\n" \ "\n" \
"literal 0\n" \ "literal 0\n" \
"Hc$@<O00001\n"; "Hc$@<O00001\n" \
"\n";
opts.flags = GIT_DIFF_SHOW_BINARY; opts.flags = GIT_DIFF_SHOW_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ; opts.id_abbrev = GIT_OID_HEXSZ;
...@@ -136,7 +137,8 @@ void test_diff_binary__modify(void) ...@@ -136,7 +137,8 @@ void test_diff_binary__modify(void)
"Mc${NkU}WL~000&M4gdfE\n" \ "Mc${NkU}WL~000&M4gdfE\n" \
"\n" \ "\n" \
"literal 3\n" \ "literal 3\n" \
"Kc${Nk-~s>u4FC%O\n"; "Kc${Nk-~s>u4FC%O\n" \
"\n";
opts.flags = GIT_DIFF_SHOW_BINARY; opts.flags = GIT_DIFF_SHOW_BINARY;
...@@ -177,7 +179,8 @@ void test_diff_binary__delete(void) ...@@ -177,7 +179,8 @@ void test_diff_binary__delete(void)
"Hc$@<O00001\n" \ "Hc$@<O00001\n" \
"\n" \ "\n" \
"literal 3\n" \ "literal 3\n" \
"Kc${Nk-~s>u4FC%O\n"; "Kc${Nk-~s>u4FC%O\n" \
"\n";
opts.flags = GIT_DIFF_SHOW_BINARY; opts.flags = GIT_DIFF_SHOW_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ; opts.id_abbrev = GIT_OID_HEXSZ;
...@@ -208,7 +211,8 @@ void test_diff_binary__delta(void) ...@@ -208,7 +211,8 @@ void test_diff_binary__delta(void)
"delta 198\n" \ "delta 198\n" \
"zc$}LmI8{(0BqLQJI6p64AwNwaIJGP_Pr*5}Br~;mqJ$<Jl;sX*mF<MGCYv&*L7AHu\n" \ "zc$}LmI8{(0BqLQJI6p64AwNwaIJGP_Pr*5}Br~;mqJ$<Jl;sX*mF<MGCYv&*L7AHu\n" \
"zGA1*^gt?gYVN82wTbPO_W)+x<&1+cP;HrPHR>PQ;Y(X&QMK*C5^Br3bjG4d=XI^5@\n" \ "zGA1*^gt?gYVN82wTbPO_W)+x<&1+cP;HrPHR>PQ;Y(X&QMK*C5^Br3bjG4d=XI^5@\n" \
"JfH567LIF3FM2!Fd\n"; "JfH567LIF3FM2!Fd\n" \
"\n";
opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ; opts.id_abbrev = GIT_OID_HEXSZ;
...@@ -249,7 +253,8 @@ void test_diff_binary__delta_append(void) ...@@ -249,7 +253,8 @@ void test_diff_binary__delta_append(void)
"nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \ "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
"\n" \ "\n" \
"delta 7\n" \ "delta 7\n" \
"Oc%18D`@*{63ljhg(E~C7\n"; "Oc%18D`@*{63ljhg(E~C7\n" \
"\n";
opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ; opts.id_abbrev = GIT_OID_HEXSZ;
...@@ -314,7 +319,8 @@ void test_diff_binary__index_to_workdir(void) ...@@ -314,7 +319,8 @@ void test_diff_binary__index_to_workdir(void)
"nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \ "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
"\n" \ "\n" \
"delta 7\n" \ "delta 7\n" \
"Oc%18D`@*{63ljhg(E~C7\n"; "Oc%18D`@*{63ljhg(E~C7\n" \
"\n";
opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ; opts.id_abbrev = GIT_OID_HEXSZ;
...@@ -379,7 +385,8 @@ void test_diff_binary__print_patch_from_diff(void) ...@@ -379,7 +385,8 @@ void test_diff_binary__print_patch_from_diff(void)
"nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \ "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
"\n" \ "\n" \
"delta 7\n" \ "delta 7\n" \
"Oc%18D`@*{63ljhg(E~C7\n"; "Oc%18D`@*{63ljhg(E~C7\n" \
"\n";
opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ; opts.id_abbrev = GIT_OID_HEXSZ;
......
#include "clar_libgit2.h"
#include "index.h"
#include "git2/sys/index.h"
#include "git2/repository.h"
#include "../reset/reset_helpers.h"
static git_repository *repo;
static git_index *repo_index;
#define TEST_REPO_PATH "nsecs"
// Fixture setup and teardown
void test_index_nsec__initialize(void)
{
repo = cl_git_sandbox_init("nsecs");
git_repository_index(&repo_index, repo);
}
void test_index_nsec__cleanup(void)
{
git_index_free(repo_index);
repo_index = NULL;
cl_git_sandbox_cleanup();
}
static bool has_nsecs(void)
{
const git_index_entry *entry;
size_t i;
bool has_nsecs = false;
for (i = 0; i < git_index_entrycount(repo_index); i++) {
entry = git_index_get_byindex(repo_index, i);
if (entry->ctime.nanoseconds || entry->mtime.nanoseconds) {
has_nsecs = true;
break;
}
}
return has_nsecs;
}
void test_index_nsec__has_nanos(void)
{
cl_assert_equal_b(true, has_nsecs());
}
void test_index_nsec__staging_maintains_other_nanos(void)
{
const git_index_entry *entry;
cl_git_rewritefile("nsecs/a.txt", "This is file A");
cl_git_pass(git_index_add_bypath(repo_index, "a.txt"));
cl_git_pass(git_index_write(repo_index));
cl_git_pass(git_index_write(repo_index));
git_index_read(repo_index, 1);
cl_assert_equal_b(true, has_nsecs());
cl_assert((entry = git_index_get_bypath(repo_index, "a.txt", 0)));
cl_assert_equal_i(0, entry->ctime.nanoseconds);
cl_assert_equal_i(0, entry->mtime.nanoseconds);
}
void test_index_nsec__status_doesnt_clear_nsecs(void)
{
git_status_list *statuslist;
cl_git_pass(git_status_list_new(&statuslist, repo, NULL));
git_index_read(repo_index, 1);
cl_assert_equal_b(true, has_nsecs());
git_status_list_free(statuslist);
}
...@@ -56,14 +56,14 @@ void test_odb_sorting__basic_backends_sorting(void) ...@@ -56,14 +56,14 @@ void test_odb_sorting__basic_backends_sorting(void)
void test_odb_sorting__alternate_backends_sorting(void) void test_odb_sorting__alternate_backends_sorting(void)
{ {
cl_git_pass(git_odb_add_backend(_odb, new_backend(0), 5)); cl_git_pass(git_odb_add_backend(_odb, new_backend(1), 5));
cl_git_pass(git_odb_add_backend(_odb, new_backend(2), 3)); cl_git_pass(git_odb_add_backend(_odb, new_backend(5), 3));
cl_git_pass(git_odb_add_backend(_odb, new_backend(1), 4)); cl_git_pass(git_odb_add_backend(_odb, new_backend(3), 4));
cl_git_pass(git_odb_add_backend(_odb, new_backend(3), 1)); cl_git_pass(git_odb_add_backend(_odb, new_backend(7), 1));
cl_git_pass(git_odb_add_alternate(_odb, new_backend(4), 5)); cl_git_pass(git_odb_add_alternate(_odb, new_backend(0), 5));
cl_git_pass(git_odb_add_alternate(_odb, new_backend(6), 3)); cl_git_pass(git_odb_add_alternate(_odb, new_backend(4), 3));
cl_git_pass(git_odb_add_alternate(_odb, new_backend(5), 4)); cl_git_pass(git_odb_add_alternate(_odb, new_backend(2), 4));
cl_git_pass(git_odb_add_alternate(_odb, new_backend(7), 1)); cl_git_pass(git_odb_add_alternate(_odb, new_backend(6), 1));
check_backend_sorting(_odb); check_backend_sorting(_odb);
} }
...@@ -154,6 +154,49 @@ void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_re ...@@ -154,6 +154,49 @@ void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_re
git_buf_free(&subtrees_log_path); git_buf_free(&subtrees_log_path);
} }
void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error(void)
{
git_reflog *reflog;
const git_error *error;
const char *refname = "refs/heads/newline";
const char *refmessage =
"Reflog*message with a newline and enough content after it to pass the GIT_REFLOG_SIZE_MIN check inside reflog_parse.";
git_reference *ref;
git_oid id;
git_buf logpath = GIT_BUF_INIT, logcontents = GIT_BUF_INIT;
char *star;
git_oid_fromstr(&id, current_master_tip);
/* create a new branch */
cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, refmessage));
/* corrupt the branch reflog by introducing a newline inside the reflog message (we replace '*' with '\n') */
git_buf_join_n(&logpath, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname);
cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath)));
cl_assert((star = strchr(git_buf_cstr(&logcontents), '*')) != NULL);
*star = '\n';
cl_git_rewritefile(git_buf_cstr(&logpath), git_buf_cstr(&logcontents));
/* confirm that the file was rewritten successfully and now contains a '\n' in the expected location */
cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath)));
cl_assert(strstr(git_buf_cstr(&logcontents), "Reflog\nmessage") != NULL);
/* clear the error state so we can capture the error generated by git_reflog_read */
giterr_clear();
cl_git_fail(git_reflog_read(&reflog, g_repo, refname));
error = giterr_last();
cl_assert(error != NULL);
cl_assert_equal_s("Unable to parse OID - contains invalid characters", error->message);
git_reference_free(ref);
git_buf_free(&logpath);
git_buf_free(&logcontents);
}
void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void) void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void)
{ {
git_reference *master, *new_master; git_reference *master, *new_master;
......
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
hideDotFiles = dotGitOnly
031986a8372d1442cfe9e3b54906a9aadc524a7e
[core]
repositoryformatversion = 0
filemode = true
bare = true
logallrefupdates = true
P pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack
# pack-refs with: peeled fully-peeled
e18fa2788e9c4e12d83150808a31dfbfb1ae364f refs/heads/master
91f4b95df4a59504a9813ba66912562931d990e3 refs/heads/ref2/ref28
...@@ -437,3 +437,38 @@ void test_revwalk_basic__mimic_git_rev_list(void) ...@@ -437,3 +437,38 @@ void test_revwalk_basic__mimic_git_rev_list(void)
cl_git_fail_with(git_revwalk_next(&oid, _walk), GIT_ITEROVER); cl_git_fail_with(git_revwalk_next(&oid, _walk), GIT_ITEROVER);
} }
void test_revwalk_basic__big_timestamp(void)
{
git_reference *head;
git_commit *tip;
git_signature *sig;
git_tree *tree;
git_oid id;
int error;
revwalk_basic_setup_walk("testrepo.git");
cl_git_pass(git_repository_head(&head, _repo));
cl_git_pass(git_reference_peel((git_object **) &tip, head, GIT_OBJ_COMMIT));
/* Commit with a far-ahead timestamp, we should be able to parse it in the revwalk */
cl_git_pass(git_signature_new(&sig, "Joe", "joe@example.com", 2399662595, 0));
cl_git_pass(git_commit_tree(&tree, tip));
cl_git_pass(git_commit_create(&id, _repo, "HEAD", sig, sig, NULL, "some message", tree, 1, &tip));
cl_git_pass(git_revwalk_push_head(_walk));
while ((error = git_revwalk_next(&id, _walk)) == 0) {
/* nothing */
}
cl_assert_equal_i(GIT_ITEROVER, error);
git_tree_free(tree);
git_commit_free(tip);
git_reference_free(head);
git_signature_free(sig);
}
...@@ -492,3 +492,22 @@ void test_revwalk_mergebase__octopus_merge_branch(void) ...@@ -492,3 +492,22 @@ void test_revwalk_mergebase__octopus_merge_branch(void)
* *
* a * a
*/ */
void test_revwalk_mergebase__remove_redundant(void)
{
git_repository *repo;
git_oid one, two, base;
git_oidarray result = {NULL, 0};
cl_git_pass(git_repository_open(&repo, cl_fixture("redundant.git")));
cl_git_pass(git_oid_fromstr(&one, "d89137c93ba1ee749214ff4ce52ae9137bc833f9"));
cl_git_pass(git_oid_fromstr(&two, "91f4b95df4a59504a9813ba66912562931d990e3"));
cl_git_pass(git_oid_fromstr(&base, "6cb1f2352d974e1c5a776093017e8772416ac97a"));
cl_git_pass(git_merge_bases(&result, repo, &one, &two));
cl_assert_equal_i(1, result.count);
cl_assert_equal_oid(&base, &result.ids[0]);
git_repository_free(repo);
}
...@@ -38,7 +38,7 @@ void test_revwalk_signatureparsing__do_not_choke_when_name_contains_angle_bracke ...@@ -38,7 +38,7 @@ void test_revwalk_signatureparsing__do_not_choke_when_name_contains_angle_bracke
signature = git_commit_committer(commit); signature = git_commit_committer(commit);
cl_assert_equal_s("foo@example.com", signature->email); cl_assert_equal_s("foo@example.com", signature->email);
cl_assert_equal_s("<Yu V. Bin Haacked>", signature->name); cl_assert_equal_s("Yu V. Bin Haacked", signature->name);
cl_assert_equal_i(1323847743, (int)signature->when.time); cl_assert_equal_i(1323847743, (int)signature->when.time);
cl_assert_equal_i(60, signature->when.offset); cl_assert_equal_i(60, signature->when.offset);
......
#include "clar_libgit2.h"
#include "git2/clone.h"
#include "clone.h"
#include "buffer.h"
#include "fileops.h"
static git_buf path = GIT_BUF_INIT;
void test_win32_longpath__initialize(void)
{
#ifdef GIT_WIN32
const char *base = clar_sandbox_path();
size_t base_len = strlen(base);
size_t remain = MAX_PATH - base_len;
size_t i;
git_buf_clear(&path);
git_buf_puts(&path, base);
git_buf_putc(&path, '/');
cl_assert(remain < (MAX_PATH - 5));
for (i = 0; i < (remain - 5); i++)
git_buf_putc(&path, 'a');
#endif
}
void test_win32_longpath__cleanup(void)
{
git_buf_free(&path);
}
#ifdef GIT_WIN32
void assert_name_too_long(void)
{
const git_error *err;
size_t expected_len, actual_len;
const char *expected_msg;
err = giterr_last();
actual_len = strlen(err->message);
expected_msg = git_win32_get_error_message(ERROR_FILENAME_EXCED_RANGE);
expected_len = strlen(expected_msg);
/* check the suffix */
cl_assert_equal_s(expected_msg, err->message + (actual_len - expected_len));
}
#endif
void test_win32_longpath__errmsg_on_checkout(void)
{
#ifdef GIT_WIN32
git_repository *repo;
cl_git_fail(git_clone(&repo, cl_fixture("testrepo.git"), path.ptr, NULL));
assert_name_too_long();
#endif
}
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