Commit e9f10cda by Edward Thomson Committed by GitHub

Merge pull request #3948 from libgit2/cmn/v24-updates

Backport fixes to v0.24
parents 211e117a adfece0d
......@@ -40,7 +40,7 @@ OPTION( USE_ICONV "Link with and use iconv library" OFF )
OPTION( USE_SSH "Link with libssh to enable SSH support" ON )
OPTION( USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF )
OPTION( VALGRIND "Configure build for valgrind" OFF )
OPTION( CURL "User curl for HTTP if available" ON)
OPTION( CURL "Use curl for HTTP if available" ON)
OPTION( DEBUG_POOL "Enable debug pool allocator" OFF )
IF(DEBUG_POOL)
......@@ -151,6 +151,10 @@ FUNCTION(TARGET_OS_LIBRARIES target)
TARGET_LINK_LIBRARIES(${target} socket nsl)
LIST(APPEND LIBGIT2_PC_LIBS "-lsocket" "-lnsl")
SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Haiku")
TARGET_LINK_LIBRARIES(${target} network)
LIST(APPEND LIBGIT2_PC_LIBS "-lnetwork")
SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE)
ENDIF()
CHECK_LIBRARY_EXISTS(rt clock_gettime "time.h" NEED_LIBRT)
IF(NEED_LIBRT)
......@@ -161,6 +165,8 @@ FUNCTION(TARGET_OS_LIBRARIES target)
IF(THREADSAFE)
TARGET_LINK_LIBRARIES(${target} ${CMAKE_THREAD_LIBS_INIT})
LIST(APPEND LIBGIT2_PC_LIBS ${CMAKE_THREAD_LIBS_INIT})
SET(LIBGIT2_PC_LIBS ${LIBGIT2_PC_LIBS} PARENT_SCOPE)
ENDIF()
ENDFUNCTION()
......@@ -280,6 +286,7 @@ ELSE ()
IF (CURL_FOUND)
ADD_DEFINITIONS(-DGIT_CURL)
INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS})
LINK_DIRECTORIES(${CURL_LIBRARY_DIRS})
LINK_LIBRARIES(${CURL_LIBRARIES})
LIST(APPEND LIBGIT2_PC_LIBS ${CURL_LDFLAGS})
ENDIF()
......@@ -467,19 +474,21 @@ ELSE ()
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
ENDIF ()
IF (MINGW) # MinGW always does PIC and complains if we tell it to
IF (MINGW OR MSYS) # MinGW and MSYS always do PIC and complain if we tell them to
STRING(REGEX REPLACE "-fPIC" "" CMAKE_SHARED_LIBRARY_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}")
# MinGW >= 3.14 uses the C99-style stdio functions
# automatically, but forks like mingw-w64 still want
# us to define this in order to use them
ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO=1)
ELSEIF (BUILD_SHARED_LIBS)
ADD_C_FLAG_IF_SUPPORTED(-fvisibility=hidden)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
ENDIF ()
IF (MINGW)
# MinGW >= 3.14 uses the C99-style stdio functions
# automatically, but forks like mingw-w64 still want
# us to define this in order to use them
ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO=1)
ENDIF ()
ADD_C_FLAG_IF_SUPPORTED(-Wdocumentation)
ADD_C_FLAG_IF_SUPPORTED(-Wno-missing-field-initializers)
ADD_C_FLAG_IF_SUPPORTED(-Wstrict-aliasing=2)
......
......@@ -15,18 +15,30 @@ with any kind of software without having to release its source code.
Additionally, the example code has been released to the public domain (see the
[separate license](examples/COPYING) for more information).
* Website: [libgit2.github.com](http://libgit2.github.com)
* StackOverflow Tag: [libgit2](http://stackoverflow.com/questions/tagged/libgit2)
* Issues: [GitHub Issues](https://github.com/libgit2/libgit2/issues) (Right here!)
* API documentation: <http://libgit2.github.com/libgit2/>
* IRC: [#libgit2](irc://irc.freenode.net/libgit2) on irc.freenode.net.
* Mailing list: The libgit2 mailing list was
traditionally hosted in Librelist but has been deprecated. We encourage you to
[use StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) instead for any questions regarding
the library, or [open an issue](https://github.com/libgit2/libgit2/issues)
on GitHub for bug reports. The mailing list archives are still available at
<http://librelist.com/browser/libgit2/>.
Getting Help
============
**Join us on Slack**
Visit [slack.libgit2.org](http://slack.libgit2.org/) to sign up, then join
us in `#libgit2`. If you prefer IRC, you can also point your client to our
slack channel once you've registered.
**Getting Help**
If you have questions about the library, please be sure to check out the
[API documentation](http://libgit2.github.com/libgit2/). If you still have
questions, reach out to us on Slack or post a question on
[StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) (with the `libgit2` tag).
**Reporting Bugs**
Please open a [GitHub Issue](https://github.com/libgit2/libgit2/issues) and
include as much information as possible. If possible, provide sample code
that illustrates the problem you're seeing. If you're seeing a bug only
on a specific repository, please provide a link to it if possible.
We ask that you not open a GitHub Issue for help, only for bug reports.
What It Can Do
==============
......@@ -235,16 +247,22 @@ we can add it to the list.
How Can I Contribute?
==================================
Check the [contribution guidelines](CONTRIBUTING.md) to understand our
workflow, the libgit2 [coding conventions](CONVENTIONS.md), and our list of
[good starting projects](PROJECTS.md).
We welcome new contributors! We have a number of issues marked as
["up for grabs"](https://github.com/libgit2/libgit2/issues?q=is%3Aissue+is%3Aopen+label%3A%22up+for+grabs%22)
and
["easy fix"](https://github.com/libgit2/libgit2/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3A%22easy+fix%22)
that are good places to jump in and get started. There's much more detailed
information in our list of [outstanding projects](PROJECTS.md).
Please be sure to check the [contribution guidelines](CONTRIBUTING.md) to
understand our workflow, and the libgit2 [coding conventions](CONVENTIONS.md).
License
==================================
`libgit2` is under GPL2 **with linking exception**. This means you can link to
and use the library from any program, proprietary or open source; paid or
gratis. However, you cannot modify libgit2 and distribute it without
supplying the source.
gratis. However, if you modify libgit2 itself, you must distribute the
source to your modified version of libgit2.
See the [COPYING file](COPYING) for the full license text.
......@@ -66,6 +66,8 @@ Key
- Bi - ignored blob (WD only)
- T1,T2,T3 - trees with different SHAs,
- Ti - ignored tree (WD only)
- S1,S2 - submodules with different SHAs
- Sd - dirty submodule (WD only)
- x - nothing
Diff with 2 non-workdir iterators
......@@ -162,6 +164,27 @@ Checkout From 3 Iterators (2 not workdir, 1 workdir)
| 35+ | T1 | T2 | x | update locally deleted tree (SAFE+MISSING) |
| 36* | T1 | T2 | B1/Bi | update to tree with typechanged tree->blob conflict (F-1) |
| 37 | T1 | T2 | T1/T2/T3 | update to existing tree (MAYBE SAFE) |
| 38+ | x | S1 | x | add submodule (SAFE) |
| 39 | x | S1 | S1/Sd | independently added submodule (SUBMODULE) |
| 40* | x | S1 | B1 | add submodule with blob confilct (FORCEABLE) |
| 41* | x | S1 | T1 | add submodule with tree conflict (FORCEABLE) |
| 42 | S1 | x | S1/Sd | deleted submodule (SUBMODULE) |
| 43 | S1 | x | x | independently deleted submodule (SUBMODULE) |
| 44 | S1 | x | B1 | independently deleted submodule with added blob (SAFE+MISSING) |
| 45 | S1 | x | T1 | independently deleted submodule with added tree (SAFE+MISSING) |
| 46 | S1 | S1 | x | locally deleted submodule (SUBMODULE) |
| 47+ | S1 | S2 | x | update locally deleted submodule (SAFE) |
| 48 | S1 | S1 | S2 | locally updated submodule commit (SUBMODULE) |
| 49 | S1 | S2 | S1 | updated submodule commit (SUBMODULE) |
| 50+ | S1 | B1 | x | add blob with locally deleted submodule (SAFE+MISSING) |
| 51* | S1 | B1 | S1 | typechange submodule->blob (SAFE) |
| 52* | S1 | B1 | Sd | typechange dirty submodule->blob (SAFE!?!?) |
| 53+ | S1 | T1 | x | add tree with locally deleted submodule (SAFE+MISSING) |
| 54* | S1 | T1 | S1/Sd | typechange submodule->tree (MAYBE SAFE) |
| 55+ | B1 | S1 | x | add submodule with locally deleted blob (SAFE+MISSING) |
| 56* | B1 | S1 | B1 | typechange blob->submodule (SAFE) |
| 57+ | T1 | S1 | x | add submodule with locally deleted tree (SAFE+MISSING) |
| 58* | T1 | S1 | T1 | typechange tree->submodule (SAFE) |
The number is followed by ' ' if no change is needed or '+' if the case
......@@ -176,6 +199,8 @@ There are four tiers of safe cases:
content, which is unknown at this point
* FORCEABLE == conflict unless FORCE is given
* DIRTY == no conflict but change is not applied unless FORCE
* SUBMODULE == no conflict and no change is applied unless a deleted
submodule dir is empty
Some slightly unusual circumstances:
......@@ -198,7 +223,9 @@ Some slightly unusual circumstances:
cases, if baseline == target, we don't touch the workdir (it is
either already right or is "dirty"). However, since this case also
implies that a ?/B1/x case will exist as well, it can be skipped.
* 41 - It's not clear how core git distinguishes this case from 39 (mode?).
* 52 - Core git makes destructive changes without any warning when the
submodule is dirty and the type changes to a blob.
Cases 3, 17, 24, 26, and 29 are all considered conflicts even though
none of them will require making any updates to the working directory.
......@@ -313,6 +313,13 @@ GIT_EXTERN(int) git_checkout_init_options(
* Updates files in the index and the working tree to match the content of
* the commit pointed at by HEAD.
*
* Note that this is _not_ the correct mechanism used to switch branches;
* do not change your `HEAD` and then call this method, that would leave
* you with checkout conflicts since your working directory would then
* appear to be dirty. Instead, checkout the target of the branch and
* then update `HEAD` using `git_repository_set_head` to point to the
* branch you checked out.
*
* @param repo repository to check out (must be non-bare)
* @param opts specifies checkout options (may be NULL)
* @return 0 on success, GIT_EUNBORNBRANCH if HEAD points to a non
......
......@@ -96,7 +96,7 @@ GIT_INLINE(int) git_array__search(
{
size_t lim;
unsigned char *part, *array = array_ptr, *base = array_ptr;
int cmp;
int cmp = -1;
for (lim = array_len; lim != 0; lim >>= 1) {
part = base + (lim >> 1) * item_size;
......
......@@ -37,25 +37,27 @@ static void origin_decref(git_blame__origin *o)
static int make_origin(git_blame__origin **out, git_commit *commit, const char *path)
{
git_blame__origin *o;
git_object *blob;
size_t path_len = strlen(path), alloc_len;
int error = 0;
if ((error = git_object_lookup_bypath(&blob, (git_object*)commit,
path, GIT_OBJ_BLOB)) < 0)
return error;
GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*o), path_len);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
o = git__calloc(1, alloc_len);
GITERR_CHECK_ALLOC(o);
o->commit = commit;
o->blob = (git_blob *) blob;
o->refcnt = 1;
strcpy(o->path, path);
if (!(error = git_object_lookup_bypath((git_object**)&o->blob, (git_object*)commit,
path, GIT_OBJ_BLOB))) {
*out = o;
} else {
origin_decref(o);
}
return error;
*out = o;
return 0;
}
/* Locate an existing origin or create a new one. */
......@@ -529,8 +531,16 @@ static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt)
goto finish;
porigin = find_origin(blame, p, origin);
if (!porigin)
if (!porigin) {
/*
* We only have to decrement the parent's
* reference count when no porigin has
* been created, as otherwise the commit
* is assigned to the created object.
*/
git_commit_free(p);
continue;
}
if (porigin->blob && origin->blob &&
!git_oid_cmp(git_blob_id(porigin->blob), git_blob_id(origin->blob))) {
pass_whole_blame(blame, origin, porigin);
......
......@@ -464,7 +464,8 @@ static int checkout_action_with_wd(
*action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
break;
case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */
if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
if (wd->mode != GIT_FILEMODE_COMMIT &&
checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
*action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
else
*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
......@@ -1342,9 +1343,11 @@ fail:
static bool should_remove_existing(checkout_data *data)
{
int ignorecase = 0;
int ignorecase;
git_repository__cvar(&ignorecase, data->repo, GIT_CVAR_IGNORECASE);
if (git_repository__cvar(&ignorecase, data->repo, GIT_CVAR_IGNORECASE) < 0) {
ignorecase = 0;
}
return (ignorecase &&
(data->strategy & GIT_CHECKOUT_DONT_REMOVE_EXISTING) == 0);
......@@ -2405,8 +2408,13 @@ static int checkout_data_init(
if (!data->opts.baseline && !data->opts.baseline_index) {
data->opts_free_baseline = true;
error = 0;
error = checkout_lookup_head_tree(&data->opts.baseline, repo);
/* if we don't have an index, this is an initial checkout and
* should be against an empty baseline
*/
if (data->index->on_disk)
error = checkout_lookup_head_tree(&data->opts.baseline, repo);
if (error == GIT_EUNBORNBRANCH) {
error = 0;
......@@ -2691,7 +2699,7 @@ int git_checkout_tree(
if ((error = git_repository_index(&index, repo)) < 0)
return error;
if ((opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
iter_opts.pathlist.count = opts->paths.count;
iter_opts.pathlist.strings = opts->paths.strings;
}
......
......@@ -45,7 +45,7 @@
# include "win32/error.h"
# include "win32/version.h"
# ifdef GIT_THREADS
# include "win32/pthread.h"
# include "win32/thread.h"
# endif
# if defined(GIT_MSVC_CRTDBG)
# include "win32/w32_stack.h"
......
......@@ -49,6 +49,37 @@ int git__delta_read_header(
return 0;
}
#define DELTA_HEADER_BUFFER_LEN 16
int git__delta_read_header_fromstream(size_t *base_sz, size_t *res_sz, git_packfile_stream *stream)
{
static const size_t buffer_len = DELTA_HEADER_BUFFER_LEN;
unsigned char buffer[DELTA_HEADER_BUFFER_LEN];
const unsigned char *delta, *delta_end;
size_t len;
ssize_t read;
len = read = 0;
while (len < buffer_len) {
read = git_packfile_stream_read(stream, &buffer[len], buffer_len - len);
if (read == 0)
break;
if (read == GIT_EBUFS)
continue;
len += read;
}
delta = buffer;
delta_end = delta + len;
if ((hdr_sz(base_sz, &delta, delta_end) < 0) ||
(hdr_sz(res_sz, &delta, delta_end) < 0))
return -1;
return 0;
}
int git__delta_apply(
git_rawobj *out,
const unsigned char *base,
......@@ -90,13 +121,13 @@ int git__delta_apply(
size_t off = 0, len = 0;
if (cmd & 0x01) off = *delta++;
if (cmd & 0x02) off |= *delta++ << 8;
if (cmd & 0x04) off |= *delta++ << 16;
if (cmd & 0x08) off |= *delta++ << 24;
if (cmd & 0x02) off |= *delta++ << 8UL;
if (cmd & 0x04) off |= *delta++ << 16UL;
if (cmd & 0x08) off |= *delta++ << 24UL;
if (cmd & 0x10) len = *delta++;
if (cmd & 0x20) len |= *delta++ << 8;
if (cmd & 0x40) len |= *delta++ << 16;
if (cmd & 0x20) len |= *delta++ << 8UL;
if (cmd & 0x40) len |= *delta++ << 16UL;
if (!len) len = 0x10000;
if (base_len < off + len || res_sz < len)
......
......@@ -8,6 +8,7 @@
#define INCLUDE_delta_apply_h__
#include "odb.h"
#include "pack.h"
/**
* Apply a git binary delta to recover the original content.
......@@ -47,4 +48,15 @@ extern int git__delta_read_header(
size_t *base_sz,
size_t *res_sz);
/**
* Read the header of a git binary delta
*
* This variant reads just enough from the packfile stream to read the
* delta header.
*/
extern int git__delta_read_header_fromstream(
size_t *base_sz,
size_t *res_sz,
git_packfile_stream *stream);
#endif
......@@ -70,7 +70,7 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode)
git_file source;
char buffer[FILEIO_BUFSIZE];
ssize_t read_bytes;
int error;
int error = 0;
source = p_open(file->path_original, O_RDONLY);
if (source < 0) {
......
......@@ -59,8 +59,9 @@ static int init_common(void)
if ((ret = git_hash_global_init()) == 0 &&
(ret = git_sysdir_global_init()) == 0 &&
(ret = git_filter_global_init()) == 0 &&
(ret = git_transport_ssh_global_init()) == 0)
ret = git_openssl_stream_global_init();
(ret = git_transport_ssh_global_init()) == 0 &&
(ret = git_openssl_stream_global_init()) == 0)
ret = git_mwindow_global_init();
GIT_MEMORY_BARRIER;
......@@ -85,11 +86,6 @@ static void shutdown_common(void)
git__free(git__user_agent);
git__free(git__ssl_ciphers);
#if defined(GIT_MSVC_CRTDBG)
git_win32__crtdbg_stacktrace_cleanup();
git_win32__stack_cleanup();
#endif
}
/**
......@@ -137,7 +133,7 @@ static int synchronized_threads_init(void)
_tls_index = TlsAlloc();
win32_pthread_initialize();
git_threads_init();
if (git_mutex_init(&git__mwindow_mutex))
return -1;
......@@ -181,6 +177,11 @@ int git_libgit2_shutdown(void)
TlsFree(_tls_index);
git_mutex_free(&git__mwindow_mutex);
#if defined(GIT_MSVC_CRTDBG)
git_win32__crtdbg_stacktrace_cleanup();
git_win32__stack_cleanup();
#endif
}
/* Exit the lock */
......@@ -226,6 +227,9 @@ void git__free_tls_data(void)
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
GIT_UNUSED(hInstDll);
GIT_UNUSED(lpvReserved);
/* This is how Windows lets us know our thread is being shut down */
if (fdwReason == DLL_THREAD_DETACH) {
git__free_tls_data();
......
......@@ -11,35 +11,64 @@
#define GIT_IGNORE_DEFAULT_RULES ".\n..\n.git\n"
/**
* A negative ignore pattern can match a positive one without
* wildcards if its pattern equals the tail of the positive
* pattern. Thus
* A negative ignore pattern can negate a positive one without
* wildcards if it is a basename only and equals the basename of
* the positive pattern. Thus
*
* foo/bar
* !bar
*
* would result in foo/bar being unignored again.
* would result in foo/bar being unignored again while
*
* moo/foo/bar
* !foo/bar
*
* would do nothing. The reverse also holds true: a positive
* basename pattern can be negated by unignoring the basename in
* subdirectories. Thus
*
* bar
* !foo/bar
*
* would result in foo/bar being unignored again. As with the
* first case,
*
* foo/bar
* !moo/foo/bar
*
* would do nothing, again.
*/
static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
{
git_attr_fnmatch *longer, *shorter;
char *p;
if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0
&& (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0) {
/*
* no chance of matching if rule is shorter than
* the negated one
*/
if (rule->length < neg->length)
/* If lengths match we need to have an exact match */
if (rule->length == neg->length) {
return strcmp(rule->pattern, neg->pattern) == 0;
} else if (rule->length < neg->length) {
shorter = rule;
longer = neg;
} else {
shorter = neg;
longer = rule;
}
/* Otherwise, we need to check if the shorter
* rule is a basename only (that is, it contains
* no path separator) and, if so, if it
* matches the tail of the longer rule */
p = longer->pattern + longer->length - shorter->length;
if (p[-1] != '/')
return false;
if (memchr(shorter->pattern, '/', shorter->length) != NULL)
return false;
/*
* shift pattern so its tail aligns with the
* negated pattern
*/
p = rule->pattern + rule->length - neg->length;
if (strcmp(p, neg->pattern) == 0)
return true;
return memcmp(p, shorter->pattern, shorter->length) == 0;
}
return false;
......
......@@ -505,10 +505,11 @@ static int index_remove_entry(git_index *index, size_t pos)
int error = 0;
git_index_entry *entry = git_vector_get(&index->entries, pos);
if (entry != NULL)
if (entry != NULL) {
git_tree_cache_invalidate_path(index->tree, entry->path);
DELETE_IN_MAP(index, entry);
}
DELETE_IN_MAP(index, entry);
error = git_vector_remove(&index->entries, pos);
if (!error) {
......@@ -2968,6 +2969,8 @@ int git_index_read_index(
*remove_entry = NULL;
int diff;
error = 0;
if (old_entry && new_entry)
diff = git_index_entry_cmp(old_entry, new_entry);
else if (!old_entry && new_entry)
......@@ -2985,7 +2988,8 @@ int git_index_read_index(
/* Path and stage are equal, if the OID is equal, keep it to
* keep the stat cache data.
*/
if (git_oid_equal(&old_entry->id, &new_entry->id)) {
if (git_oid_equal(&old_entry->id, &new_entry->id) &&
old_entry->mode == new_entry->mode) {
add_entry = (git_index_entry *)old_entry;
} else {
dup_entry = (git_index_entry *)new_entry;
......@@ -2996,8 +3000,17 @@ int git_index_read_index(
if (dup_entry) {
if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0)
goto done;
index_entry_adjust_namemask(add_entry,
((struct entry_internal *)add_entry)->pathlen);
}
/* invalidate this path in the tree cache if this is new (to
* invalidate the parent trees)
*/
if (dup_entry && !remove_entry && index->tree)
git_tree_cache_invalidate_path(index->tree, dup_entry->path);
if (add_entry) {
if ((error = git_vector_insert(&new_entries, add_entry)) == 0)
INSERT_IN_MAP_EX(index, new_entries_map, add_entry, error);
......@@ -3008,7 +3021,7 @@ int git_index_read_index(
if (error < 0) {
giterr_set(GITERR_INDEX, "failed to insert entry");
return error;
goto done;
}
if (diff <= 0) {
......
......@@ -2730,6 +2730,7 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde
opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
opts.pathspec.count = merged_paths->length;
opts.pathspec.strings = (char **)merged_paths->contents;
opts.ignore_submodules = GIT_SUBMODULE_IGNORE_ALL;
if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, NULL, &opts)) < 0)
goto done;
......
......@@ -33,25 +33,20 @@ static git_mwindow_ctl mem_ctl;
/* Global list of mwindow files, to open packs once across repos */
git_strmap *git__pack_cache = NULL;
/**
* Run under mwindow lock
*/
int git_mwindow_files_init(void)
static void git_mwindow_files_free(void)
{
if (git__pack_cache)
return 0;
git__on_shutdown(git_mwindow_files_free);
git_strmap *tmp = git__pack_cache;
return git_strmap_alloc(&git__pack_cache);
git__pack_cache = NULL;
git_strmap_free(tmp);
}
void git_mwindow_files_free(void)
int git_mwindow_global_init(void)
{
git_strmap *tmp = git__pack_cache;
assert(!git__pack_cache);
git__pack_cache = NULL;
git_strmap_free(tmp);
git__on_shutdown(git_mwindow_files_free);
return git_strmap_alloc(&git__pack_cache);
}
int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
......@@ -69,12 +64,6 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
return -1;
}
if (git_mwindow_files_init() < 0) {
git_mutex_unlock(&git__mwindow_mutex);
git__free(packname);
return -1;
}
pos = git_strmap_lookup_index(git__pack_cache, packname);
git__free(packname);
......
......@@ -43,8 +43,7 @@ int git_mwindow_file_register(git_mwindow_file *mwf);
void git_mwindow_file_deregister(git_mwindow_file *mwf);
void git_mwindow_close(git_mwindow **w_cursor);
int git_mwindow_files_init(void);
void git_mwindow_files_free(void);
extern int git_mwindow_global_init(void);
struct git_pack_file; /* just declaration to avoid cyclical includes */
int git_mwindow_get_pack(struct git_pack_file **out, const char *path);
......
......@@ -803,19 +803,12 @@ int git_odb__read_header_or_object(
return 0;
}
static git_oid empty_blob = {{ 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b,
0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91 }};
static git_oid empty_tree = {{ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }};
static int hardcoded_objects(git_rawobj *raw, const git_oid *id)
{
if (!git_oid_cmp(id, &empty_blob)) {
raw->type = GIT_OBJ_BLOB;
raw->len = 0;
raw->data = git__calloc(1, sizeof(uint8_t));
return 0;
} else if (!git_oid_cmp(id, &empty_tree)) {
if (!git_oid_cmp(id, &empty_tree)) {
raw->type = GIT_OBJ_TREE;
raw->len = 0;
raw->data = git__calloc(1, sizeof(uint8_t));
......@@ -1229,7 +1222,7 @@ int git_odb__error_notfound(
{
if (oid != NULL) {
char oid_str[GIT_OID_HEXSZ + 1];
git_oid_tostr(oid_str, oid_len, oid);
git_oid_tostr(oid_str, oid_len+1, oid);
giterr_set(GITERR_ODB, "Object not found - %s (%.*s)",
message, oid_len, oid_str);
} else
......
......@@ -91,7 +91,7 @@ static int object_mkdir(const git_buf *name, const loose_backend *be)
static size_t get_binary_object_header(obj_hdr *hdr, git_buf *obj)
{
unsigned char c;
unsigned long c;
unsigned char *data = (unsigned char *)obj->ptr;
size_t shift, size, used = 0;
......
......@@ -591,9 +591,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
struct pack_backend *backend = NULL;
git_buf path = GIT_BUF_INIT;
if (git_mwindow_files_init() < 0)
return -1;
if (pack_backend__alloc(&backend, 8) < 0)
return -1;
......
......@@ -522,8 +522,9 @@ ssize_t openssl_read(git_stream *stream, void *data, size_t len)
openssl_stream *st = (openssl_stream *) stream;
int ret;
if ((ret = SSL_read(st->ssl, data, len)) <= 0)
ssl_set_error(st->ssl, ret);
if ((ret = SSL_read(st->ssl, data, len)) <= 0) {
return ssl_set_error(st->ssl, ret);
}
return ret;
}
......
......@@ -1186,7 +1186,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
git_mutex_init(&p[i].mutex);
git_cond_init(&p[i].cond);
ret = git_thread_create(&p[i].thread, NULL,
ret = git_thread_create(&p[i].thread,
threaded_find_deltas, &p[i]);
if (ret) {
giterr_set(GITERR_THREAD, "unable to create thread");
......
......@@ -499,15 +499,14 @@ int git_packfile_resolve_header(
if (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) {
size_t base_size;
git_rawobj delta;
git_packfile_stream stream;
base_offset = get_delta_base(p, &w_curs, &curpos, type, offset);
git_mwindow_close(&w_curs);
error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, size, type);
git_mwindow_close(&w_curs);
if (error < 0)
if ((error = git_packfile_stream_open(&stream, p, curpos)) < 0)
return error;
error = git__delta_read_header(delta.data, delta.len, &base_size, size_p);
git__free(delta.data);
error = git__delta_read_header_fromstream(&base_size, size_p, &stream);
git_packfile_stream_free(&stream);
if (error < 0)
return error;
} else
......
......@@ -53,8 +53,10 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
if (rhs) {
size_t rlen = strlen(++rhs);
is_glob = (1 <= rlen && strchr(rhs, '*'));
refspec->dst = git__strndup(rhs, rlen);
if (rlen || !is_fetch) {
is_glob = (1 <= rlen && strchr(rhs, '*'));
refspec->dst = git__strndup(rhs, rlen);
}
}
llen = (rhs ? (size_t)(rhs - lhs - 1) : strlen(lhs));
......
......@@ -1414,7 +1414,11 @@ static int update_tips_for_spec(
/* In autotag mode, don't overwrite any locally-existing tags */
error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
log_message);
if (error < 0 && error != GIT_EEXISTS)
if (error == GIT_EEXISTS)
continue;
if (error < 0)
goto on_error;
git_reference_free(ref);
......@@ -2224,15 +2228,21 @@ static int remove_branch_config_related_entries(
if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
break;
if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
break;
if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
if (error != GIT_ENOTFOUND)
break;
giterr_clear();
}
git_buf_clear(&buf);
if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
break;
if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
break;
if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
if (error != GIT_ENOTFOUND)
break;
giterr_clear();
}
}
if (error == GIT_ITEROVER)
......
......@@ -264,7 +264,7 @@ cleanup:
* the stack could remove directories name limits, but at the cost of doing
* repeated malloc/frees inside the loop below, so let's not do it now.
*/
static int find_ceiling_dir_offset(
static size_t find_ceiling_dir_offset(
const char *path,
const char *ceiling_directories)
{
......@@ -278,7 +278,7 @@ static int find_ceiling_dir_offset(
min_len = (size_t)(git_path_root(path) + 1);
if (ceiling_directories == NULL || min_len == 0)
return (int)min_len;
return min_len;
for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
......@@ -305,7 +305,7 @@ static int find_ceiling_dir_offset(
}
}
return (int)(max_len <= min_len ? min_len : max_len);
return (max_len <= min_len ? min_len : max_len);
}
/*
......@@ -359,21 +359,36 @@ static int find_repo(
git_buf path = GIT_BUF_INIT;
struct stat st;
dev_t initial_device = 0;
bool try_with_dot_git = ((flags & GIT_REPOSITORY_OPEN_BARE) != 0);
int ceiling_offset;
int min_iterations;
bool in_dot_git;
size_t ceiling_offset = 0;
git_buf_free(repo_path);
if ((error = git_path_prettify(&path, start_path, NULL)) < 0)
return error;
ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
/* in_dot_git toggles each loop:
* /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a
* With GIT_REPOSITORY_OPEN_BARE, we assume we started with /a/b/c.git
* and don't append .git the first time through.
* min_iterations indicates the number of iterations left before going
* further counts as a search. */
if (flags & GIT_REPOSITORY_OPEN_BARE) {
in_dot_git = true;
min_iterations = 1;
} else {
in_dot_git = false;
min_iterations = 2;
}
if (!try_with_dot_git &&
(error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
return error;
while (!error && (min_iterations || !(path.ptr[ceiling_offset] == 0 ||
(flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))) {
if (!in_dot_git)
if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
break;
in_dot_git = !in_dot_git;
while (!error && !git_buf_len(repo_path)) {
if (p_stat(path.ptr, &st) == 0) {
/* check that we have not crossed device boundaries */
if (initial_device == 0)
......@@ -414,17 +429,10 @@ static int find_repo(
break;
}
if (try_with_dot_git) {
/* if we tried original dir with and without .git AND either hit
* directory ceiling or NO_SEARCH was requested, then be done.
*/
if (path.ptr[ceiling_offset] == '\0' ||
(flags & GIT_REPOSITORY_OPEN_NO_SEARCH) != 0)
break;
/* otherwise look first for .git item */
error = git_buf_joinpath(&path, path.ptr, DOT_GIT);
}
try_with_dot_git = !try_with_dot_git;
/* Once we've checked the directory (and .git if applicable),
* find the ceiling for a search. */
if (min_iterations && (--min_iterations == 0))
ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
}
if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
......
......@@ -16,7 +16,7 @@
#include "socket_stream.h"
#include "curl_stream.h"
int stransport_error(OSStatus ret)
static int stransport_error(OSStatus ret)
{
CFStringRef message;
......@@ -33,6 +33,7 @@ int stransport_error(OSStatus ret)
CFRelease(message);
#else
giterr_set(GITERR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret);
GIT_UNUSED(message);
#endif
return -1;
......@@ -46,7 +47,7 @@ typedef struct {
git_cert_x509 cert_info;
} stransport_stream;
int stransport_connect(git_stream *stream)
static int stransport_connect(git_stream *stream)
{
stransport_stream *st = (stransport_stream *) stream;
int error;
......@@ -66,6 +67,9 @@ int stransport_connect(git_stream *stream)
if ((ret = SSLCopyPeerTrust(st->ctx, &trust)) != noErr)
goto on_error;
if (!trust)
return GIT_ECERTIFICATE;
if ((ret = SecTrustEvaluate(trust, &sec_res)) != noErr)
goto on_error;
......@@ -89,7 +93,7 @@ on_error:
return stransport_error(ret);
}
int stransport_certificate(git_cert **out, git_stream *stream)
static int stransport_certificate(git_cert **out, git_stream *stream)
{
stransport_stream *st = (stransport_stream *) stream;
SecTrustRef trust = NULL;
......@@ -116,7 +120,7 @@ int stransport_certificate(git_cert **out, git_stream *stream)
return 0;
}
int stransport_set_proxy(git_stream *stream, const char *proxy)
static int stransport_set_proxy(git_stream *stream, const char *proxy)
{
stransport_stream *st = (stransport_stream *) stream;
......@@ -146,7 +150,7 @@ static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len)
return noErr;
}
ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int flags)
static ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int flags)
{
stransport_stream *st = (stransport_stream *) stream;
size_t data_len, processed;
......@@ -195,7 +199,7 @@ static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len)
return error;
}
ssize_t stransport_read(git_stream *stream, void *data, size_t len)
static ssize_t stransport_read(git_stream *stream, void *data, size_t len)
{
stransport_stream *st = (stransport_stream *) stream;
size_t processed;
......@@ -207,7 +211,7 @@ ssize_t stransport_read(git_stream *stream, void *data, size_t len)
return processed;
}
int stransport_close(git_stream *stream)
static int stransport_close(git_stream *stream)
{
stransport_stream *st = (stransport_stream *) stream;
OSStatus ret;
......@@ -219,7 +223,7 @@ int stransport_close(git_stream *stream)
return git_stream_close(st->io);
}
void stransport_free(git_stream *stream)
static void stransport_free(git_stream *stream)
{
stransport_stream *st = (stransport_stream *) stream;
......@@ -255,6 +259,7 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po
st->ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
if (!st->ctx) {
giterr_set(GITERR_NET, "failed to create SSL context");
git__free(st);
return -1;
}
......@@ -264,7 +269,8 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po
(ret = SSLSetProtocolVersionMin(st->ctx, kTLSProtocol1)) != noErr ||
(ret = SSLSetProtocolVersionMax(st->ctx, kTLSProtocol12)) != noErr ||
(ret = SSLSetPeerDomainName(st->ctx, host, strlen(host))) != noErr) {
git_stream_free((git_stream *)st);
CFRelease(st->ctx);
git__free(st);
return stransport_error(ret);
}
......
......@@ -83,45 +83,43 @@ static int git_sysdir_guess_template_dirs(git_buf *out)
#endif
}
typedef int (*git_sysdir_guess_cb)(git_buf *out);
static git_buf git_sysdir__dirs[GIT_SYSDIR__MAX] =
{ GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT, GIT_BUF_INIT };
struct git_sysdir__dir {
git_buf buf;
int (*guess)(git_buf *out);
};
static git_sysdir_guess_cb git_sysdir__dir_guess[GIT_SYSDIR__MAX] = {
git_sysdir_guess_system_dirs,
git_sysdir_guess_global_dirs,
git_sysdir_guess_xdg_dirs,
git_sysdir_guess_programdata_dirs,
git_sysdir_guess_template_dirs,
static struct git_sysdir__dir git_sysdir__dirs[] = {
{ GIT_BUF_INIT, git_sysdir_guess_system_dirs },
{ GIT_BUF_INIT, git_sysdir_guess_global_dirs },
{ GIT_BUF_INIT, git_sysdir_guess_xdg_dirs },
{ GIT_BUF_INIT, git_sysdir_guess_programdata_dirs },
{ GIT_BUF_INIT, git_sysdir_guess_template_dirs },
};
static int git_sysdir__dirs_shutdown_set = 0;
static void git_sysdir_global_shutdown(void)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(git_sysdir__dirs); ++i)
git_buf_free(&git_sysdir__dirs[i].buf);
}
int git_sysdir_global_init(void)
{
git_sysdir_t i;
const git_buf *path;
size_t i;
int error = 0;
for (i = 0; !error && i < GIT_SYSDIR__MAX; i++)
error = git_sysdir_get(&path, i);
for (i = 0; !error && i < ARRAY_SIZE(git_sysdir__dirs); i++)
error = git_sysdir__dirs[i].guess(&git_sysdir__dirs[i].buf);
return error;
}
git__on_shutdown(git_sysdir_global_shutdown);
void git_sysdir_global_shutdown(void)
{
int i;
for (i = 0; i < GIT_SYSDIR__MAX; ++i)
git_buf_free(&git_sysdir__dirs[i]);
git_sysdir__dirs_shutdown_set = 0;
return error;
}
static int git_sysdir_check_selector(git_sysdir_t which)
{
if (which < GIT_SYSDIR__MAX)
if (which < ARRAY_SIZE(git_sysdir__dirs))
return 0;
giterr_set(GITERR_INVALID, "config directory selector out of range");
......@@ -137,18 +135,7 @@ int git_sysdir_get(const git_buf **out, git_sysdir_t which)
GITERR_CHECK_ERROR(git_sysdir_check_selector(which));
if (!git_buf_len(&git_sysdir__dirs[which])) {
/* prepare shutdown if we're going to need it */
if (!git_sysdir__dirs_shutdown_set) {
git__on_shutdown(git_sysdir_global_shutdown);
git_sysdir__dirs_shutdown_set = 1;
}
GITERR_CHECK_ERROR(
git_sysdir__dir_guess[which](&git_sysdir__dirs[which]));
}
*out = &git_sysdir__dirs[which];
*out = &git_sysdir__dirs[which].buf;
return 0;
}
......@@ -183,31 +170,38 @@ int git_sysdir_set(git_sysdir_t which, const char *search_path)
if (search_path != NULL)
expand_path = strstr(search_path, PATH_MAGIC);
/* init with default if not yet done and needed (ignoring error) */
if ((!search_path || expand_path) &&
!git_buf_len(&git_sysdir__dirs[which]))
git_sysdir__dir_guess[which](&git_sysdir__dirs[which]);
/* reset the default if this path has been cleared */
if (!search_path || expand_path)
git_sysdir__dirs[which].guess(&git_sysdir__dirs[which].buf);
/* if $PATH is not referenced, then just set the path */
if (!expand_path)
return git_buf_sets(&git_sysdir__dirs[which], search_path);
if (!expand_path) {
if (search_path)
git_buf_sets(&git_sysdir__dirs[which].buf, search_path);
goto done;
}
/* otherwise set to join(before $PATH, old value, after $PATH) */
if (expand_path > search_path)
git_buf_set(&merge, search_path, expand_path - search_path);
if (git_buf_len(&git_sysdir__dirs[which]))
if (git_buf_len(&git_sysdir__dirs[which].buf))
git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR,
merge.ptr, git_sysdir__dirs[which].ptr);
merge.ptr, git_sysdir__dirs[which].buf.ptr);
expand_path += strlen(PATH_MAGIC);
if (*expand_path)
git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path);
git_buf_swap(&git_sysdir__dirs[which], &merge);
git_buf_swap(&git_sysdir__dirs[which].buf, &merge);
git_buf_free(&merge);
return git_buf_oom(&git_sysdir__dirs[which]) ? -1 : 0;
done:
if (git_buf_oom(&git_sysdir__dirs[which].buf))
return -1;
return 0;
}
static int git_sysdir_find_in_dirlist(
......
......@@ -103,9 +103,4 @@ extern int git_sysdir_get_str(char *out, size_t outlen, git_sysdir_t which);
*/
extern int git_sysdir_set(git_sysdir_t which, const char *paths);
/**
* Free the configuration file search paths.
*/
extern void git_sysdir_global_shutdown(void);
#endif /* INCLUDE_sysdir_h__ */
......@@ -137,8 +137,14 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
tag->message = NULL;
if (buffer < buffer_end) {
if( *buffer != '\n' )
return tag_error("No new line before message");
/* If we're not at the end of the header, search for it */
if( *buffer != '\n' ) {
search = strstr(buffer, "\n\n");
if (search)
buffer = search + 1;
else
return tag_error("tag contains no message");
}
text_len = buffer_end - ++buffer;
......
......@@ -40,58 +40,12 @@ typedef git_atomic git_atomic_ssize;
#ifdef GIT_THREADS
#if !defined(GIT_WIN32)
typedef struct {
pthread_t thread;
} git_thread;
#define git_thread_create(git_thread_ptr, attr, start_routine, arg) \
pthread_create(&(git_thread_ptr)->thread, attr, start_routine, arg)
#define git_thread_join(git_thread_ptr, status) \
pthread_join((git_thread_ptr)->thread, status)
#endif
/* Pthreads Mutex */
#define git_mutex pthread_mutex_t
#define git_mutex_init(a) pthread_mutex_init(a, NULL)
#define git_mutex_lock(a) pthread_mutex_lock(a)
#define git_mutex_unlock(a) pthread_mutex_unlock(a)
#define git_mutex_free(a) pthread_mutex_destroy(a)
/* Pthreads condition vars */
#define git_cond pthread_cond_t
#define git_cond_init(c) pthread_cond_init(c, NULL)
#define git_cond_free(c) pthread_cond_destroy(c)
#define git_cond_wait(c, l) pthread_cond_wait(c, l)
#define git_cond_signal(c) pthread_cond_signal(c)
#define git_cond_broadcast(c) pthread_cond_broadcast(c)
/* Pthread (-ish) rwlock
*
* This differs from normal pthreads rwlocks in two ways:
* 1. Separate APIs for releasing read locks and write locks (as
* opposed to the pure POSIX API which only has one unlock fn)
* 2. You should not use recursive read locks (i.e. grabbing a read
* lock in a thread that already holds a read lock) because the
* Windows implementation doesn't support it
*/
#define git_rwlock pthread_rwlock_t
#define git_rwlock_init(a) pthread_rwlock_init(a, NULL)
#define git_rwlock_rdlock(a) pthread_rwlock_rdlock(a)
#define git_rwlock_rdunlock(a) pthread_rwlock_rdunlock(a)
#define git_rwlock_wrlock(a) pthread_rwlock_wrlock(a)
#define git_rwlock_wrunlock(a) pthread_rwlock_wrunlock(a)
#define git_rwlock_free(a) pthread_rwlock_destroy(a)
#define GIT_RWLOCK_STATIC_INIT PTHREAD_RWLOCK_INITIALIZER
#ifndef GIT_WIN32
#define pthread_rwlock_rdunlock pthread_rwlock_unlock
#define pthread_rwlock_wrunlock pthread_rwlock_unlock
#ifdef GIT_WIN32
# include "win32/thread.h"
#else
# include "unix/pthread.h"
#endif
GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
{
#if defined(GIT_WIN32)
......@@ -178,7 +132,7 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
#else
#define git_thread unsigned int
#define git_thread_create(thread, attr, start_routine, arg) 0
#define git_thread_create(thread, start_routine, arg) 0
#define git_thread_join(id, status) (void)0
/* Pthreads Mutex */
......
......@@ -114,7 +114,7 @@ static bool challenge_match(git_http_auth_scheme *scheme, void *data)
size_t scheme_len;
scheme_len = strlen(scheme_name);
return (strncmp(challenge, scheme_name, scheme_len) == 0 &&
return (strncasecmp(challenge, scheme_name, scheme_len) == 0 &&
(challenge[scheme_len] == '\0' || challenge[scheme_len] == ' '));
}
......@@ -569,6 +569,7 @@ static int http_connect(http_subtransport *t)
git_stream_close(t->io);
git_stream_free(t->io);
t->io = NULL;
t->connected = 0;
}
if (t->connection_data.use_ssl) {
......
......@@ -433,6 +433,7 @@ int git_pkt_parse_line(
* line?
*/
if (len == PKT_LEN_SIZE) {
*head = NULL;
*out = line;
return 0;
}
......
......@@ -759,6 +759,14 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt,
line_len -= (line_end - line);
line = line_end;
/* When a valid packet with no content has been
* read, git_pkt_parse_line does not report an
* error, but the pkt pointer has not been set.
* Handle this by skipping over empty packets.
*/
if (pkt == NULL)
continue;
error = add_push_report_pkt(push, pkt);
git_pkt_free(pkt);
......@@ -813,6 +821,9 @@ static int parse_report(transport_smart *transport, git_push *push)
error = 0;
if (pkt == NULL)
continue;
switch (pkt->type) {
case GIT_PKT_DATA:
/* This is a sideband packet which contains other packets */
......
......@@ -45,7 +45,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode)
if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_COMMIT)
return GIT_FILEMODE_COMMIT;
/* 12XXXX means commit */
/* 12XXXX means symlink */
if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_LINK)
return GIT_FILEMODE_LINK;
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_unix_pthread_h__
#define INCLUDE_unix_pthread_h__
typedef struct {
pthread_t thread;
} git_thread;
#define git_threads_init() (void)0
#define git_thread_create(git_thread_ptr, start_routine, arg) \
pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg)
#define git_thread_join(git_thread_ptr, status) \
pthread_join((git_thread_ptr)->thread, status)
/* Git Mutex */
#define git_mutex pthread_mutex_t
#define git_mutex_init(a) pthread_mutex_init(a, NULL)
#define git_mutex_lock(a) pthread_mutex_lock(a)
#define git_mutex_unlock(a) pthread_mutex_unlock(a)
#define git_mutex_free(a) pthread_mutex_destroy(a)
/* Git condition vars */
#define git_cond pthread_cond_t
#define git_cond_init(c) pthread_cond_init(c, NULL)
#define git_cond_free(c) pthread_cond_destroy(c)
#define git_cond_wait(c, l) pthread_cond_wait(c, l)
#define git_cond_signal(c) pthread_cond_signal(c)
#define git_cond_broadcast(c) pthread_cond_broadcast(c)
/* Pthread (-ish) rwlock
*
* This differs from normal pthreads rwlocks in two ways:
* 1. Separate APIs for releasing read locks and write locks (as
* opposed to the pure POSIX API which only has one unlock fn)
* 2. You should not use recursive read locks (i.e. grabbing a read
* lock in a thread that already holds a read lock) because the
* Windows implementation doesn't support it
*/
#define git_rwlock pthread_rwlock_t
#define git_rwlock_init(a) pthread_rwlock_init(a, NULL)
#define git_rwlock_rdlock(a) pthread_rwlock_rdlock(a)
#define git_rwlock_rdunlock(a) pthread_rwlock_unlock(a)
#define git_rwlock_wrlock(a) pthread_rwlock_wrlock(a)
#define git_rwlock_wrunlock(a) pthread_rwlock_unlock(a)
#define git_rwlock_free(a) pthread_rwlock_destroy(a)
#define GIT_RWLOCK_STATIC_INIT PTHREAD_RWLOCK_INITIALIZER
#endif /* INCLUDE_unix_pthread_h__ */
......@@ -122,8 +122,8 @@ int git__strtol64(int64_t *result, const char *nptr, const char **endptr, int ba
v = c - 'A' + 10;
if (v >= base)
break;
nn = n*base + v;
if (nn < n)
nn = n * base + (neg ? -v : v);
if ((!neg && nn < n) || (neg && nn > n))
ovfl = 1;
n = nn;
}
......@@ -142,7 +142,7 @@ Return:
return -1;
}
*result = neg ? -n : n;
*result = n;
return 0;
}
......
......@@ -16,7 +16,7 @@
#include <io.h>
#include <direct.h>
#ifdef GIT_THREADS
#include "win32/pthread.h"
#include "win32/thread.h"
#endif
#include "git2.h"
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef GIT_PTHREAD_H
#define GIT_PTHREAD_H
#include "../common.h"
#if defined (_MSC_VER)
# define GIT_RESTRICT __restrict
#else
# define GIT_RESTRICT __restrict__
#endif
typedef struct {
HANDLE thread;
void *(*proc)(void *);
void *param;
void *result;
} git_win32_thread;
typedef int pthread_mutexattr_t;
typedef int pthread_condattr_t;
typedef int pthread_attr_t;
typedef int pthread_rwlockattr_t;
typedef CRITICAL_SECTION pthread_mutex_t;
typedef HANDLE pthread_cond_t;
typedef struct { void *Ptr; } GIT_SRWLOCK;
typedef struct {
union {
GIT_SRWLOCK srwl;
CRITICAL_SECTION csec;
} native;
} pthread_rwlock_t;
#define PTHREAD_MUTEX_INITIALIZER {(void*)-1}
int git_win32__thread_create(
git_win32_thread *GIT_RESTRICT,
const pthread_attr_t *GIT_RESTRICT,
void *(*) (void *),
void *GIT_RESTRICT);
int git_win32__thread_join(
git_win32_thread *,
void **);
#ifdef GIT_THREADS
typedef git_win32_thread git_thread;
#define git_thread_create(git_thread_ptr, attr, start_routine, arg) \
git_win32__thread_create(git_thread_ptr, attr, start_routine, arg)
#define git_thread_join(git_thread_ptr, status) \
git_win32__thread_join(git_thread_ptr, status)
#endif
int pthread_mutex_init(
pthread_mutex_t *GIT_RESTRICT mutex,
const pthread_mutexattr_t *GIT_RESTRICT mutexattr);
int pthread_mutex_destroy(pthread_mutex_t *);
int pthread_mutex_lock(pthread_mutex_t *);
int pthread_mutex_unlock(pthread_mutex_t *);
int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
int pthread_cond_destroy(pthread_cond_t *);
int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
int pthread_cond_signal(pthread_cond_t *);
/* pthread_cond_broadcast is not supported on Win32 yet. */
int pthread_num_processors_np(void);
int pthread_rwlock_init(
pthread_rwlock_t *GIT_RESTRICT lock,
const pthread_rwlockattr_t *GIT_RESTRICT attr);
int pthread_rwlock_rdlock(pthread_rwlock_t *);
int pthread_rwlock_rdunlock(pthread_rwlock_t *);
int pthread_rwlock_wrlock(pthread_rwlock_t *);
int pthread_rwlock_wrunlock(pthread_rwlock_t *);
int pthread_rwlock_destroy(pthread_rwlock_t *);
extern int win32_pthread_initialize(void);
#endif
......@@ -5,18 +5,26 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "pthread.h"
#include "thread.h"
#include "../global.h"
#define CLEAN_THREAD_EXIT 0x6F012842
typedef void (WINAPI *win32_srwlock_fn)(GIT_SRWLOCK *);
static win32_srwlock_fn win32_srwlock_initialize;
static win32_srwlock_fn win32_srwlock_acquire_shared;
static win32_srwlock_fn win32_srwlock_release_shared;
static win32_srwlock_fn win32_srwlock_acquire_exclusive;
static win32_srwlock_fn win32_srwlock_release_exclusive;
/* The thread procedure stub used to invoke the caller's procedure
* and capture the return value for later collection. Windows will
* only hold a DWORD, but we need to be able to store an entire
* void pointer. This requires the indirection. */
static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
{
git_win32_thread *thread = lpParameter;
git_thread *thread = lpParameter;
thread->result = thread->proc(thread->param);
......@@ -25,14 +33,31 @@ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
return CLEAN_THREAD_EXIT;
}
int git_win32__thread_create(
git_win32_thread *GIT_RESTRICT thread,
const pthread_attr_t *GIT_RESTRICT attr,
int git_threads_init(void)
{
HMODULE hModule = GetModuleHandleW(L"kernel32");
if (hModule) {
win32_srwlock_initialize = (win32_srwlock_fn)
GetProcAddress(hModule, "InitializeSRWLock");
win32_srwlock_acquire_shared = (win32_srwlock_fn)
GetProcAddress(hModule, "AcquireSRWLockShared");
win32_srwlock_release_shared = (win32_srwlock_fn)
GetProcAddress(hModule, "ReleaseSRWLockShared");
win32_srwlock_acquire_exclusive = (win32_srwlock_fn)
GetProcAddress(hModule, "AcquireSRWLockExclusive");
win32_srwlock_release_exclusive = (win32_srwlock_fn)
GetProcAddress(hModule, "ReleaseSRWLockExclusive");
}
return 0;
}
int git_thread_create(
git_thread *GIT_RESTRICT thread,
void *(*start_routine)(void*),
void *GIT_RESTRICT arg)
{
GIT_UNUSED(attr);
thread->result = NULL;
thread->param = arg;
thread->proc = start_routine;
......@@ -42,8 +67,8 @@ int git_win32__thread_create(
return thread->thread ? 0 : -1;
}
int git_win32__thread_join(
git_win32_thread *thread,
int git_thread_join(
git_thread *thread,
void **value_ptr)
{
DWORD exit;
......@@ -70,39 +95,32 @@ int git_win32__thread_join(
return 0;
}
int pthread_mutex_init(
pthread_mutex_t *GIT_RESTRICT mutex,
const pthread_mutexattr_t *GIT_RESTRICT mutexattr)
int git_mutex_init(git_mutex *GIT_RESTRICT mutex)
{
GIT_UNUSED(mutexattr);
InitializeCriticalSection(mutex);
return 0;
}
int pthread_mutex_destroy(pthread_mutex_t *mutex)
int git_mutex_free(git_mutex *mutex)
{
DeleteCriticalSection(mutex);
return 0;
}
int pthread_mutex_lock(pthread_mutex_t *mutex)
int git_mutex_lock(git_mutex *mutex)
{
EnterCriticalSection(mutex);
return 0;
}
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int git_mutex_unlock(git_mutex *mutex)
{
LeaveCriticalSection(mutex);
return 0;
}
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
int git_cond_init(git_cond *cond)
{
/* We don't support non-default attributes. */
if (attr)
return EINVAL;
/* This is an auto-reset event. */
*cond = CreateEventW(NULL, FALSE, FALSE, NULL);
assert(*cond);
......@@ -112,7 +130,7 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
return *cond ? 0 : ENOMEM;
}
int pthread_cond_destroy(pthread_cond_t *cond)
int git_cond_free(git_cond *cond)
{
BOOL closed;
......@@ -127,7 +145,7 @@ int pthread_cond_destroy(pthread_cond_t *cond)
return 0;
}
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int git_cond_wait(git_cond *cond, git_mutex *mutex)
{
int error;
DWORD wait_result;
......@@ -136,7 +154,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
return EINVAL;
/* The caller must be holding the mutex. */
error = pthread_mutex_unlock(mutex);
error = git_mutex_unlock(mutex);
if (error)
return error;
......@@ -145,10 +163,10 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
assert(WAIT_OBJECT_0 == wait_result);
GIT_UNUSED(wait_result);
return pthread_mutex_lock(mutex);
return git_mutex_lock(mutex);
}
int pthread_cond_signal(pthread_cond_t *cond)
int git_cond_signal(git_cond *cond)
{
BOOL signaled;
......@@ -162,36 +180,8 @@ int pthread_cond_signal(pthread_cond_t *cond)
return 0;
}
/* pthread_cond_broadcast is not implemented because doing so with just
* Win32 events is quite complicated, and no caller in libgit2 uses it
* yet.
*/
int pthread_num_processors_np(void)
{
DWORD_PTR p, s;
int n = 0;
if (GetProcessAffinityMask(GetCurrentProcess(), &p, &s))
for (; p; p >>= 1)
n += p&1;
return n ? n : 1;
}
typedef void (WINAPI *win32_srwlock_fn)(GIT_SRWLOCK *);
static win32_srwlock_fn win32_srwlock_initialize;
static win32_srwlock_fn win32_srwlock_acquire_shared;
static win32_srwlock_fn win32_srwlock_release_shared;
static win32_srwlock_fn win32_srwlock_acquire_exclusive;
static win32_srwlock_fn win32_srwlock_release_exclusive;
int pthread_rwlock_init(
pthread_rwlock_t *GIT_RESTRICT lock,
const pthread_rwlockattr_t *GIT_RESTRICT attr)
int git_rwlock_init(git_rwlock *GIT_RESTRICT lock)
{
GIT_UNUSED(attr);
if (win32_srwlock_initialize)
win32_srwlock_initialize(&lock->native.srwl);
else
......@@ -200,7 +190,7 @@ int pthread_rwlock_init(
return 0;
}
int pthread_rwlock_rdlock(pthread_rwlock_t *lock)
int git_rwlock_rdlock(git_rwlock *lock)
{
if (win32_srwlock_acquire_shared)
win32_srwlock_acquire_shared(&lock->native.srwl);
......@@ -210,7 +200,7 @@ int pthread_rwlock_rdlock(pthread_rwlock_t *lock)
return 0;
}
int pthread_rwlock_rdunlock(pthread_rwlock_t *lock)
int git_rwlock_rdunlock(git_rwlock *lock)
{
if (win32_srwlock_release_shared)
win32_srwlock_release_shared(&lock->native.srwl);
......@@ -220,7 +210,7 @@ int pthread_rwlock_rdunlock(pthread_rwlock_t *lock)
return 0;
}
int pthread_rwlock_wrlock(pthread_rwlock_t *lock)
int git_rwlock_wrlock(git_rwlock *lock)
{
if (win32_srwlock_acquire_exclusive)
win32_srwlock_acquire_exclusive(&lock->native.srwl);
......@@ -230,7 +220,7 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *lock)
return 0;
}
int pthread_rwlock_wrunlock(pthread_rwlock_t *lock)
int git_rwlock_wrunlock(git_rwlock *lock)
{
if (win32_srwlock_release_exclusive)
win32_srwlock_release_exclusive(&lock->native.srwl);
......@@ -240,30 +230,10 @@ int pthread_rwlock_wrunlock(pthread_rwlock_t *lock)
return 0;
}
int pthread_rwlock_destroy(pthread_rwlock_t *lock)
int git_rwlock_free(git_rwlock *lock)
{
if (!win32_srwlock_initialize)
DeleteCriticalSection(&lock->native.csec);
git__memzero(lock, sizeof(*lock));
return 0;
}
int win32_pthread_initialize(void)
{
HMODULE hModule = GetModuleHandleW(L"kernel32");
if (hModule) {
win32_srwlock_initialize = (win32_srwlock_fn)
GetProcAddress(hModule, "InitializeSRWLock");
win32_srwlock_acquire_shared = (win32_srwlock_fn)
GetProcAddress(hModule, "AcquireSRWLockShared");
win32_srwlock_release_shared = (win32_srwlock_fn)
GetProcAddress(hModule, "ReleaseSRWLockShared");
win32_srwlock_acquire_exclusive = (win32_srwlock_fn)
GetProcAddress(hModule, "AcquireSRWLockExclusive");
win32_srwlock_release_exclusive = (win32_srwlock_fn)
GetProcAddress(hModule, "ReleaseSRWLockExclusive");
}
return 0;
}
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_win32_thread_h__
#define INCLUDE_win32_thread_h__
#include "../common.h"
#if defined (_MSC_VER)
# define GIT_RESTRICT __restrict
#else
# define GIT_RESTRICT __restrict__
#endif
typedef struct {
HANDLE thread;
void *(*proc)(void *);
void *param;
void *result;
} git_thread;
typedef CRITICAL_SECTION git_mutex;
typedef HANDLE git_cond;
typedef struct { void *Ptr; } GIT_SRWLOCK;
typedef struct {
union {
GIT_SRWLOCK srwl;
CRITICAL_SECTION csec;
} native;
} git_rwlock;
int git_threads_init(void);
int git_thread_create(git_thread *GIT_RESTRICT,
void *(*) (void *),
void *GIT_RESTRICT);
int git_thread_join(git_thread *, void **);
int git_mutex_init(git_mutex *GIT_RESTRICT mutex);
int git_mutex_free(git_mutex *);
int git_mutex_lock(git_mutex *);
int git_mutex_unlock(git_mutex *);
int git_cond_init(git_cond *);
int git_cond_free(git_cond *);
int git_cond_wait(git_cond *, git_mutex *);
int git_cond_signal(git_cond *);
int git_rwlock_init(git_rwlock *GIT_RESTRICT lock);
int git_rwlock_rdlock(git_rwlock *);
int git_rwlock_rdunlock(git_rwlock *);
int git_rwlock_wrlock(git_rwlock *);
int git_rwlock_wrunlock(git_rwlock *);
int git_rwlock_free(git_rwlock *);
#endif /* INCLUDE_win32_thread_h__ */
......@@ -294,11 +294,12 @@ void test_checkout_index__options_dir_modes(void)
(void)p_umask(um = p_umask(022));
cl_git_pass(p_stat("./testrepo/a", &st));
cl_assert_equal_i_fmt(st.st_mode, (GIT_FILEMODE_TREE | 0701) & ~um, "%07o");
/* Haiku & Hurd use other mode bits, so we must mask them out */
cl_assert_equal_i_fmt(st.st_mode & (S_IFMT | 07777), (GIT_FILEMODE_TREE | 0701) & ~um, "%07o");
/* File-mode test, since we're on the 'dir' branch */
cl_git_pass(p_stat("./testrepo/a/b.txt", &st));
cl_assert_equal_i_fmt(st.st_mode, GIT_FILEMODE_BLOB_EXECUTABLE & ~um, "%07o");
cl_assert_equal_i_fmt(st.st_mode & (S_IFMT | 07777), GIT_FILEMODE_BLOB_EXECUTABLE & ~um, "%07o");
git_commit_free(commit);
}
......
......@@ -1416,3 +1416,70 @@ void test_checkout_tree__safe_proceeds_if_no_index(void)
git_object_free(obj);
}
static int checkout_conflict_count_cb(
git_checkout_notify_t why,
const char *path,
const git_diff_file *b,
const git_diff_file *t,
const git_diff_file *w,
void *payload)
{
size_t *n = payload;
GIT_UNUSED(why);
GIT_UNUSED(path);
GIT_UNUSED(b);
GIT_UNUSED(t);
GIT_UNUSED(w);
(*n)++;
return 0;
}
/* A repo that has a HEAD (even a properly born HEAD that peels to
* a commit) but no index should be treated as if it's an empty baseline
*/
void test_checkout_tree__baseline_is_empty_when_no_index(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_reference *head;
git_object *obj;
git_status_list *status;
size_t conflicts = 0;
assert_on_branch(g_repo, "master");
cl_git_pass(git_repository_head(&head, g_repo));
cl_git_pass(git_reference_peel(&obj, head, GIT_OBJ_COMMIT));
cl_git_pass(git_reset(g_repo, obj, GIT_RESET_HARD, NULL));
cl_must_pass(p_unlink("testrepo/.git/index"));
/* for a safe checkout, we should have checkout conflicts with
* the existing untracked files.
*/
opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE;
opts.notify_flags = GIT_CHECKOUT_NOTIFY_CONFLICT;
opts.notify_cb = checkout_conflict_count_cb;
opts.notify_payload = &conflicts;
cl_git_fail_with(GIT_ECONFLICT, git_checkout_tree(g_repo, obj, &opts));
cl_assert_equal_i(4, conflicts);
/* but force should succeed and update the index */
opts.checkout_strategy |= GIT_CHECKOUT_FORCE;
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
cl_git_pass(git_status_list_new(&status, g_repo, NULL));
cl_assert_equal_i(0, git_status_list_entrycount(status));
git_status_list_free(status);
git_object_free(obj);
git_reference_free(head);
}
void test_checkout_tree__nullopts(void)
{
cl_git_pass(git_checkout_tree(g_repo, NULL, NULL));
}
......@@ -6,6 +6,36 @@
static git_repository *g_repo = NULL;
/*
From the test repo used for this test:
--------------------------------------
This is a test repo for libgit2 where tree entries have type changes
The key types that could be found in tree entries are:
1 - GIT_FILEMODE_NEW = 0000000
2 - GIT_FILEMODE_TREE = 0040000
3 - GIT_FILEMODE_BLOB = 0100644
4 - GIT_FILEMODE_BLOB_EXECUTABLE = 0100755
5 - GIT_FILEMODE_LINK = 0120000
6 - GIT_FILEMODE_COMMIT = 0160000
I will try to have every type of transition somewhere in the history
of this repo.
Commits
-------
Initial commit - a(1) b(1) c(1) d(1) e(1)
Create content - a(1->2) b(1->3) c(1->4) d(1->5) e(1->6)
Changes #1 - a(2->3) b(3->4) c(4->5) d(5->6) e(6->2)
Changes #2 - a(3->5) b(4->6) c(5->2) d(6->3) e(2->4)
Changes #3 - a(5->3) b(6->4) c(2->5) d(3->6) e(4->2)
Changes #4 - a(3->2) b(4->3) c(5->4) d(6->5) e(2->6)
Changes #5 - a(2->1) b(3->1) c(4->1) d(5->1) e(6->1)
*/
static const char *g_typechange_oids[] = {
"79b9f23e85f55ea36a472a902e875bc1121a94cb",
"9bdb75b73836a99e3dbeea640a81de81031fdc29",
......@@ -21,6 +51,14 @@ static bool g_typechange_empty[] = {
true, false, false, false, false, false, true, true
};
static const int g_typechange_expected_conflicts[] = {
1, 2, 3, 3, 2, 3, 2
};
static const int g_typechange_expected_untracked[] = {
6, 4, 3, 2, 3, 2, 5
};
void test_checkout_typechange__initialize(void)
{
g_repo = cl_git_sandbox_init("typechanges");
......@@ -112,12 +150,7 @@ void test_checkout_typechange__checkout_typechanges_safe(void)
for (i = 0; g_typechange_oids[i] != NULL; ++i) {
cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i]));
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
/* There are bugs in some submodule->tree changes that prevent
* SAFE from passing here, even though the following should work:
*/
/* !i ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE; */
opts.checkout_strategy = !i ? GIT_CHECKOUT_FORCE : GIT_CHECKOUT_SAFE;
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
......@@ -190,6 +223,38 @@ static void force_create_file(const char *file)
cl_git_rewritefile(file, "yowza!!");
}
static int make_submodule_dirty(git_submodule *sm, const char *name, void *payload)
{
git_buf submodulepath = GIT_BUF_INIT;
git_buf dirtypath = GIT_BUF_INIT;
git_repository *submodule_repo;
GIT_UNUSED(name);
GIT_UNUSED(payload);
/* remove submodule directory in preparation for init and repo_init */
cl_git_pass(git_buf_joinpath(
&submodulepath,
git_repository_workdir(g_repo),
git_submodule_path(sm)
));
git_futils_rmdir_r(git_buf_cstr(&submodulepath), NULL, GIT_RMDIR_REMOVE_FILES);
/* initialize submodule's repository */
cl_git_pass(git_submodule_repo_init(&submodule_repo, sm, 0));
/* create a file in the submodule workdir to make it dirty */
cl_git_pass(
git_buf_joinpath(&dirtypath, git_repository_workdir(submodule_repo), "dirty"));
force_create_file(git_buf_cstr(&dirtypath));
git_buf_free(&dirtypath);
git_buf_free(&submodulepath);
git_repository_free(submodule_repo);
return 0;
}
void test_checkout_typechange__checkout_with_conflicts(void)
{
int i;
......@@ -211,13 +276,17 @@ void test_checkout_typechange__checkout_with_conflicts(void)
git_futils_rmdir_r("typechanges/d", NULL, GIT_RMDIR_REMOVE_FILES);
p_mkdir("typechanges/d", 0777); /* intentionally empty dir */
force_create_file("typechanges/untracked");
cl_git_pass(git_submodule_foreach(g_repo, make_submodule_dirty, NULL));
opts.checkout_strategy = GIT_CHECKOUT_SAFE;
memset(&cts, 0, sizeof(cts));
cl_git_fail(git_checkout_tree(g_repo, obj, &opts));
cl_assert(cts.conflicts > 0);
cl_assert(cts.untracked > 0);
cl_assert_equal_i(cts.conflicts, g_typechange_expected_conflicts[i]);
cl_assert_equal_i(cts.untracked, g_typechange_expected_untracked[i]);
cl_assert_equal_i(cts.dirty, 0);
cl_assert_equal_i(cts.updates, 0);
cl_assert_equal_i(cts.ignored, 0);
opts.checkout_strategy =
GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
......
......@@ -33,5 +33,13 @@ void test_core_strtol__int64(void)
cl_assert(i == 2147483657LL);
cl_git_pass(git__strtol64(&i, " -2147483657 ", NULL, 10));
cl_assert(i == -2147483657LL);
cl_git_pass(git__strtol64(&i, " 9223372036854775807 ", NULL, 10));
cl_assert(i == INT64_MAX);
cl_git_pass(git__strtol64(&i, " -9223372036854775808 ", NULL, 10));
cl_assert(i == INT64_MIN);
cl_git_pass(git__strtol64(&i, " 0x7fffffffffffffff ", NULL, 16));
cl_assert(i == INT64_MAX);
cl_git_pass(git__strtol64(&i, " -0x8000000000000000 ", NULL, 16));
cl_assert(i == INT64_MIN);
}
......@@ -2,105 +2,103 @@
#include "git2/repository.h"
#include "git2/index.h"
git_repository *repo = NULL;
static git_repository *g_repo;
static git_odb *g_odb;
static git_index *g_index;
static git_oid g_empty_id;
void test_index_collision__initialize(void)
{
g_repo = cl_git_sandbox_init("empty_standard_repo");
cl_git_pass(git_repository_odb(&g_odb, g_repo));
cl_git_pass(git_repository_index(&g_index, g_repo));
cl_git_pass(git_odb_write(&g_empty_id, g_odb, "", 0, GIT_OBJ_BLOB));
}
void test_index_collision__cleanup(void)
{
git_index_free(g_index);
git_odb_free(g_odb);
cl_git_sandbox_cleanup();
repo = NULL;
}
void test_index_collision__add(void)
{
git_index *index;
git_index_entry entry;
git_oid tree_id;
git_tree *tree;
repo = cl_git_sandbox_init("empty_standard_repo");
cl_git_pass(git_repository_index(&index, repo));
memset(&entry, 0, sizeof(entry));
entry.ctime.seconds = 12346789;
entry.mtime.seconds = 12346789;
entry.mode = 0100644;
entry.file_size = 0;
git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
git_oid_cpy(&entry.id, &g_empty_id);
entry.path = "a/b";
cl_git_pass(git_index_add(index, &entry));
cl_git_pass(git_index_add(g_index, &entry));
/* create a tree/blob collision */
entry.path = "a/b/c";
cl_git_fail(git_index_add(index, &entry));
cl_git_fail(git_index_add(g_index, &entry));
cl_git_pass(git_index_write_tree(&tree_id, index));
cl_git_pass(git_tree_lookup(&tree, repo, &tree_id));
cl_git_pass(git_index_write_tree(&tree_id, g_index));
cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
git_tree_free(tree);
git_index_free(index);
}
void test_index_collision__add_with_highstage_1(void)
{
git_index *index;
git_index_entry entry;
repo = cl_git_sandbox_init("empty_standard_repo");
cl_git_pass(git_repository_index(&index, repo));
memset(&entry, 0, sizeof(entry));
entry.ctime.seconds = 12346789;
entry.mtime.seconds = 12346789;
entry.mode = 0100644;
entry.file_size = 0;
git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
git_oid_cpy(&entry.id, &g_empty_id);
entry.path = "a/b";
GIT_IDXENTRY_STAGE_SET(&entry, 2);
cl_git_pass(git_index_add(index, &entry));
cl_git_pass(git_index_add(g_index, &entry));
/* create a blob beneath the previous tree entry */
entry.path = "a/b/c";
entry.flags = 0;
cl_git_pass(git_index_add(index, &entry));
cl_git_pass(git_index_add(g_index, &entry));
/* create another tree entry above the blob */
entry.path = "a/b";
GIT_IDXENTRY_STAGE_SET(&entry, 1);
cl_git_pass(git_index_add(index, &entry));
git_index_free(index);
cl_git_pass(git_index_add(g_index, &entry));
}
void test_index_collision__add_with_highstage_2(void)
{
git_index *index;
git_index_entry entry;
repo = cl_git_sandbox_init("empty_standard_repo");
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_repository_index(&g_index, g_repo));
memset(&entry, 0, sizeof(entry));
entry.ctime.seconds = 12346789;
entry.mtime.seconds = 12346789;
entry.mode = 0100644;
entry.file_size = 0;
git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
git_oid_cpy(&entry.id, &g_empty_id);
entry.path = "a/b/c";
GIT_IDXENTRY_STAGE_SET(&entry, 1);
cl_git_pass(git_index_add(index, &entry));
cl_git_pass(git_index_add(g_index, &entry));
/* create a blob beneath the previous tree entry */
entry.path = "a/b/c";
GIT_IDXENTRY_STAGE_SET(&entry, 2);
cl_git_pass(git_index_add(index, &entry));
cl_git_pass(git_index_add(g_index, &entry));
/* create another tree entry above the blob */
entry.path = "a/b";
GIT_IDXENTRY_STAGE_SET(&entry, 3);
cl_git_pass(git_index_add(index, &entry));
git_index_free(index);
cl_git_pass(git_index_add(g_index, &entry));
}
......@@ -71,3 +71,58 @@ void test_index_read_index__maintains_stat_cache(void)
}
}
}
static bool roundtrip_with_read_index(const char *tree_idstr)
{
git_oid tree_id, new_tree_id;
git_tree *tree;
git_index *tree_index;
cl_git_pass(git_oid_fromstr(&tree_id, tree_idstr));
cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id));
cl_git_pass(git_index_new(&tree_index));
cl_git_pass(git_index_read_tree(tree_index, tree));
cl_git_pass(git_index_read_index(_index, tree_index));
cl_git_pass(git_index_write_tree(&new_tree_id, _index));
git_tree_free(tree);
git_index_free(tree_index);
return git_oid_equal(&tree_id, &new_tree_id);
}
void test_index_read_index__produces_treesame_indexes(void)
{
roundtrip_with_read_index("53fc32d17276939fc79ed05badaef2db09990016");
roundtrip_with_read_index("944c0f6e4dfa41595e6eb3ceecdb14f50fe18162");
roundtrip_with_read_index("1810dff58d8a660512d4832e740f692884338ccd");
roundtrip_with_read_index("d52a8fe84ceedf260afe4f0287bbfca04a117e83");
roundtrip_with_read_index("c36d8ea75da8cb510fcb0c408c1d7e53f9a99dbe");
roundtrip_with_read_index("7b2417a23b63e1fdde88c80e14b33247c6e5785a");
roundtrip_with_read_index("f82a8eb4cb20e88d1030fd10d89286215a715396");
roundtrip_with_read_index("fd093bff70906175335656e6ce6ae05783708765");
roundtrip_with_read_index("ae90f12eea699729ed24555e40b9fd669da12a12");
}
void test_index_read_index__read_and_writes(void)
{
git_oid tree_id, new_tree_id;
git_tree *tree;
git_index *tree_index, *new_index;
cl_git_pass(git_oid_fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12"));
cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id));
cl_git_pass(git_index_new(&tree_index));
cl_git_pass(git_index_read_tree(tree_index, tree));
cl_git_pass(git_index_read_index(_index, tree_index));
cl_git_pass(git_index_write(_index));
cl_git_pass(git_index_open(&new_index, git_index_path(_index)));
cl_git_pass(git_index_write_tree_to(&new_tree_id, new_index, _repo));
cl_assert_equal_oid(&tree_id, &new_tree_id);
git_tree_free(tree);
git_index_free(tree_index);
git_index_free(new_index);
}
......@@ -220,7 +220,7 @@ void test_object_cache__threadmania(void)
fn = (th & 1) ? cache_parsed : cache_raw;
#ifdef GIT_THREADS
cl_git_pass(git_thread_create(&t[th], NULL, fn, data));
cl_git_pass(git_thread_create(&t[th], fn, data));
#else
cl_assert(fn(data) == data);
git__free(data);
......@@ -267,7 +267,7 @@ void test_object_cache__fast_thread_rush(void)
data[th] = th;
#ifdef GIT_THREADS
cl_git_pass(
git_thread_create(&t[th], NULL, cache_quick, &data[th]));
git_thread_create(&t[th], cache_quick, &data[th]));
#else
cl_assert(cache_quick(&data[th]) == &data[th]);
#endif
......
......@@ -140,3 +140,40 @@ void test_object_tag_read__without_tagger_nor_message(void)
git_tag_free(tag);
git_repository_free(repo);
}
static const char *silly_tag = "object c054ccaefbf2da31c3b19178f9e3ef20a3867924\n\
type commit\n\
tag v1_0_1\n\
tagger Jamis Buck <jamis@37signals.com> 1107717917\n\
diff --git a/lib/sqlite3/version.rb b/lib/sqlite3/version.rb\n\
index 0b3bf69..4ee8fc2 100644\n\
--- a/lib/sqlite3/version.rb\n\
+++ b/lib/sqlite3/version.rb\n\
@@ -36,7 +36,7 @@ module SQLite3\n\
\n\
MAJOR = 1\n\
MINOR = 0\n\
- TINY = 0\n\
+ TINY = 1\n\
\n\
STRING = [ MAJOR, MINOR, TINY ].join( \".\" )\n\
\n\
-0600\n\
\n\
v1_0_1 release\n";
void test_object_tag_read__extra_header_fields(void)
{
git_tag *tag;
git_odb *odb;
git_oid id;
cl_git_pass(git_repository_odb__weakptr(&odb, g_repo));
cl_git_pass(git_odb_write(&id, odb, silly_tag, strlen(silly_tag), GIT_OBJ_TAG));
cl_git_pass(git_tag_lookup(&tag, g_repo, &id));
cl_assert_equal_s("v1_0_1 release\n", git_tag_message(tag));
git_tag_free(tag);
}
......@@ -2,29 +2,33 @@
#include "odb.h"
#include "filebuf.h"
#define TEST_REPO_PATH "redundant.git"
git_repository *g_repo;
git_odb *g_odb;
void test_odb_emptyobjects__initialize(void)
{
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
g_repo = cl_git_sandbox_init(TEST_REPO_PATH);
cl_git_pass(git_repository_odb(&g_odb, g_repo));
}
void test_odb_emptyobjects__cleanup(void)
{
git_repository_free(g_repo);
git_odb_free(g_odb);
cl_git_sandbox_cleanup();
}
void test_odb_emptyobjects__read(void)
void test_odb_emptyobjects__blob_notfound(void)
{
git_oid id;
git_oid id, written_id;
git_blob *blob;
cl_git_pass(git_oid_fromstr(&id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"));
cl_git_pass(git_blob_lookup(&blob, g_repo, &id));
cl_assert_equal_i(GIT_OBJ_BLOB, git_object_type((git_object *) blob));
cl_assert(git_blob_rawcontent(blob));
cl_assert_equal_s("", git_blob_rawcontent(blob));
cl_assert_equal_i(0, git_blob_rawsize(blob));
git_blob_free(blob);
cl_git_fail_with(GIT_ENOTFOUND, git_blob_lookup(&blob, g_repo, &id));
cl_git_pass(git_odb_write(&written_id, g_odb, "", 0, GIT_OBJ_BLOB));
cl_assert(git_path_exists(TEST_REPO_PATH "/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391"));
}
void test_odb_emptyobjects__read_tree(void)
......@@ -43,15 +47,12 @@ void test_odb_emptyobjects__read_tree(void)
void test_odb_emptyobjects__read_tree_odb(void)
{
git_oid id;
git_odb *odb;
git_odb_object *tree_odb;
cl_git_pass(git_oid_fromstr(&id, "4b825dc642cb6eb9a060e54bf8d69288fbee4904"));
cl_git_pass(git_repository_odb(&odb, g_repo));
cl_git_pass(git_odb_read(&tree_odb, odb, &id));
cl_git_pass(git_odb_read(&tree_odb, g_odb, &id));
cl_assert(git_odb_object_data(tree_odb));
cl_assert_equal_s("", git_odb_object_data(tree_odb));
cl_assert_equal_i(0, git_odb_object_size(tree_odb));
git_odb_object_free(tree_odb);
git_odb_free(odb);
}
......@@ -35,6 +35,19 @@ static void fetchhead_test_clone(void)
cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
}
static int count_references(void)
{
git_strarray array;
int refs;
cl_git_pass(git_reference_list(&array, g_repo));
refs = array.count;
git_strarray_free(&array);
return refs;
}
static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fetchhead)
{
git_remote *remote;
......@@ -101,3 +114,41 @@ void test_online_fetchhead__no_merges(void)
cl_git_pass(git_tag_delete(g_repo, "commit_tree"));
fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA3);
}
void test_online_fetchhead__explicit_dst_refspec_creates_branch(void)
{
git_reference *ref;
int refs;
fetchhead_test_clone();
refs = count_references();
fetchhead_test_fetch("refs/heads/first-merge:refs/heads/explicit-refspec", FETCH_HEAD_EXPLICIT_DATA);
cl_git_pass(git_branch_lookup(&ref, g_repo, "explicit-refspec", GIT_BRANCH_ALL));
cl_assert_equal_i(refs + 1, count_references());
}
void test_online_fetchhead__empty_dst_refspec_creates_no_branch(void)
{
git_reference *ref;
int refs;
fetchhead_test_clone();
refs = count_references();
fetchhead_test_fetch("refs/heads/first-merge", FETCH_HEAD_EXPLICIT_DATA);
cl_git_fail(git_branch_lookup(&ref, g_repo, "first-merge", GIT_BRANCH_ALL));
cl_assert_equal_i(refs, count_references());
}
void test_online_fetchhead__colon_only_dst_refspec_creates_no_branch(void)
{
int refs;
fetchhead_test_clone();
refs = count_references();
fetchhead_test_fetch("refs/heads/first-merge:", FETCH_HEAD_EXPLICIT_DATA);
cl_assert_equal_i(refs, count_references());
}
......@@ -118,12 +118,22 @@ void test_repo_discover__0(void)
cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs));
append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER_SUB);
ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
/* this must pass as ceiling_directories cannot prevent the current
* working directory to be checked */
ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path);
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, &sub_repository_path);
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs));
append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER);
ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
//this must pass as ceiling_directories cannot predent the current
//working directory to be checked
cl_git_pass(git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs));
ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path);
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs));
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs));
......
......@@ -196,8 +196,9 @@ void test_repo_open__failures(void)
&repo, "attr/sub", GIT_REPOSITORY_OPEN_NO_SEARCH, NULL));
/* fail with ceiling too low */
cl_git_pass(git_buf_joinpath(&ceiling, ceiling.ptr, "sub"));
cl_git_fail(git_repository_open_ext(&repo, "attr/sub", 0, ceiling.ptr));
cl_git_pass(git_buf_joinpath(&ceiling, ceiling.ptr, "sub"));
cl_git_fail(git_repository_open_ext(&repo, "attr/sub/sub", 0, ceiling.ptr));
/* fail with no repo */
cl_git_pass(p_mkdir("alternate", 0777));
......
......@@ -240,14 +240,18 @@ void test_reset_hard__switch_file_to_dir(void)
{
git_index_entry entry = {{ 0 }};
git_index *idx;
git_odb *odb;
git_object *commit;
git_tree *tree;
git_signature *sig;
git_oid src_tree_id, tgt_tree_id;
git_oid src_id, tgt_id;
cl_git_pass(git_repository_odb(&odb, repo));
cl_git_pass(git_odb_write(&entry.id, odb, "", 0, GIT_OBJ_BLOB));
git_odb_free(odb);
entry.mode = GIT_FILEMODE_BLOB;
cl_git_pass(git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"));
cl_git_pass(git_index_new(&idx));
cl_git_pass(git_signature_now(&sig, "foo", "bar"));
......
......@@ -945,6 +945,44 @@ void test_status_ignore__negative_directory_ignores(void)
assert_is_ignored("padded_parent/child8/bar.txt");
}
void test_status_ignore__unignore_entry_in_ignored_dir(void)
{
static const char *test_files[] = {
"empty_standard_repo/bar.txt",
"empty_standard_repo/parent/bar.txt",
"empty_standard_repo/parent/child/bar.txt",
"empty_standard_repo/nested/parent/child/bar.txt",
NULL
};
make_test_data("empty_standard_repo", test_files);
cl_git_mkfile(
"empty_standard_repo/.gitignore",
"bar.txt\n"
"!parent/child/bar.txt\n");
assert_is_ignored("bar.txt");
assert_is_ignored("parent/bar.txt");
refute_is_ignored("parent/child/bar.txt");
assert_is_ignored("nested/parent/child/bar.txt");
}
void test_status_ignore__do_not_unignore_basename_prefix(void)
{
static const char *test_files[] = {
"empty_standard_repo/foo_bar.txt",
NULL
};
make_test_data("empty_standard_repo", test_files);
cl_git_mkfile(
"empty_standard_repo/.gitignore",
"foo_bar.txt\n"
"!bar.txt\n");
assert_is_ignored("foo_bar.txt");
}
void test_status_ignore__filename_with_cr(void)
{
int ignored;
......
......@@ -75,7 +75,7 @@ void test_threads_refdb__iterator(void)
for (t = 0; t < THREADS; ++t) {
id[t] = t;
#ifdef GIT_THREADS
cl_git_pass(git_thread_create(&th[t], NULL, iterate_refs, &id[t]));
cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t]));
#else
th[t] = t;
iterate_refs(&id[t]);
......@@ -196,7 +196,7 @@ void test_threads_refdb__edit_while_iterate(void)
* for now by just running on a single thread...
*/
/* #ifdef GIT_THREADS */
/* cl_git_pass(git_thread_create(&th[t], NULL, fn, &id[t])); */
/* cl_git_pass(git_thread_create(&th[t], fn, &id[t])); */
/* #else */
fn(&id[t]);
/* #endif */
......@@ -211,7 +211,7 @@ void test_threads_refdb__edit_while_iterate(void)
for (t = 0; t < THREADS; ++t) {
id[t] = t;
cl_git_pass(git_thread_create(&th[t], NULL, iterate_refs, &id[t]));
cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t]));
}
for (t = 0; t < THREADS; ++t) {
......
......@@ -24,7 +24,7 @@ void run_in_parallel(
for (t = 0; t < threads; ++t) {
id[t] = t;
#ifdef GIT_THREADS
cl_git_pass(git_thread_create(&th[t], NULL, func, &id[t]));
cl_git_pass(git_thread_create(&th[t], func, &id[t]));
#else
cl_assert(func(&id[t]) == &id[t]);
#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