summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@github.com>2016-10-01 19:00:49 -0500
committerGitHub <noreply@github.com>2016-10-01 19:00:49 -0500
commite9f10cdad1f513cb334f7534b3ea72a94431c95c (patch)
tree54316f6d13ee041a51d3c48ecc309670cddb517a
parent211e117a0590583a720c53172406f34186c543bd (diff)
parentadfece0df2153234970ded1b0552c5150e7f0c53 (diff)
downloadlibgit2-e9f10cdad1f513cb334f7534b3ea72a94431c95c.tar.gz
Merge pull request #3948 from libgit2/cmn/v24-updates
Backport fixes to v0.24
-rw-r--r--CMakeLists.txt23
-rw-r--r--README.md50
-rw-r--r--docs/checkout-internals.md29
-rw-r--r--include/git2/checkout.h7
-rw-r--r--src/array.h2
-rw-r--r--src/blame_git.c26
-rw-r--r--src/checkout.c18
-rw-r--r--src/common.h2
-rw-r--r--src/delta-apply.c41
-rw-r--r--src/delta-apply.h12
-rw-r--r--src/filebuf.c2
-rw-r--r--src/global.c20
-rw-r--r--src/ignore.c61
-rw-r--r--src/index.c21
-rw-r--r--src/merge.c1
-rw-r--r--src/mwindow.c27
-rw-r--r--src/mwindow.h3
-rw-r--r--src/odb.c11
-rw-r--r--src/odb_loose.c2
-rw-r--r--src/odb_pack.c3
-rw-r--r--src/openssl_stream.c5
-rw-r--r--src/pack-objects.c2
-rw-r--r--src/pack.c11
-rw-r--r--src/refspec.c6
-rw-r--r--src/remote.c20
-rw-r--r--src/repository.c50
-rw-r--r--src/stransport_stream.c24
-rw-r--r--src/sysdir.c88
-rw-r--r--src/sysdir.h5
-rw-r--r--src/tag.c10
-rw-r--r--src/thread-utils.h56
-rw-r--r--src/transports/http.c3
-rw-r--r--src/transports/smart_pkt.c1
-rw-r--r--src/transports/smart_protocol.c11
-rw-r--r--src/tree.c2
-rw-r--r--src/unix/pthread.h54
-rw-r--r--src/util.c6
-rw-r--r--src/win32/precompiled.h2
-rw-r--r--src/win32/pthread.h92
-rw-r--r--src/win32/thread.c (renamed from src/win32/pthread.c)130
-rw-r--r--src/win32/thread.h62
-rw-r--r--tests/checkout/index.c5
-rw-r--r--tests/checkout/tree.c67
-rw-r--r--tests/checkout/typechange.c85
-rw-r--r--tests/core/strtol.c8
-rw-r--r--tests/index/collision.c60
-rw-r--r--tests/index/read_index.c55
-rw-r--r--tests/object/cache.c4
-rw-r--r--tests/object/tag/read.c37
-rw-r--r--tests/odb/emptyobjects.c29
-rw-r--r--tests/online/fetchhead.c51
-rw-r--r--tests/repo/discover.c12
-rw-r--r--tests/repo/open.c3
-rw-r--r--tests/reset/hard.c6
-rw-r--r--tests/status/ignore.c38
-rw-r--r--tests/threads/refdb.c6
-rw-r--r--tests/threads/thread_helpers.c2
57 files changed, 969 insertions, 500 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c79b2637c..0f9cff575 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/README.md b/README.md
index 8ea787b3e..b69a18a38 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/docs/checkout-internals.md b/docs/checkout-internals.md
index 6147ffdd8..e0b2583b5 100644
--- a/docs/checkout-internals.md
+++ b/docs/checkout-internals.md
@@ -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.
-
diff --git a/include/git2/checkout.h b/include/git2/checkout.h
index 6cf9ed8bd..4a9dbb021 100644
--- a/include/git2/checkout.h
+++ b/include/git2/checkout.h
@@ -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
diff --git a/src/array.h b/src/array.h
index 490e6be20..78d321e82 100644
--- a/src/array.h
+++ b/src/array.h
@@ -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;
diff --git a/src/blame_git.c b/src/blame_git.c
index 700207edb..96785c75b 100644
--- a/src/blame_git.c
+++ b/src/blame_git.c
@@ -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);
diff --git a/src/checkout.c b/src/checkout.c
index deeee62e0..1bea00da8 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -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;
}
diff --git a/src/common.h b/src/common.h
index 9abd605cb..51fb9186e 100644
--- a/src/common.h
+++ b/src/common.h
@@ -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"
diff --git a/src/delta-apply.c b/src/delta-apply.c
index 89745faa0..02ec7b75e 100644
--- a/src/delta-apply.c
+++ b/src/delta-apply.c
@@ -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)
diff --git a/src/delta-apply.h b/src/delta-apply.h
index d7d99d04c..eeeb78682 100644
--- a/src/delta-apply.h
+++ b/src/delta-apply.h
@@ -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
diff --git a/src/filebuf.c b/src/filebuf.c
index 101d5082a..507f6a942 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -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) {
diff --git a/src/global.c b/src/global.c
index adf353d35..198bc1e80 100644
--- a/src/global.c
+++ b/src/global.c
@@ -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();
diff --git a/src/ignore.c b/src/ignore.c
index ac2af4f58..dcbd5c1ca 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -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;
diff --git a/src/index.c b/src/index.c
index 63e47965a..32f585faf 100644
--- a/src/index.c
+++ b/src/index.c
@@ -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) {
diff --git a/src/merge.c b/src/merge.c
index d2f92ccce..174cbfb58 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -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;
diff --git a/src/mwindow.c b/src/mwindow.c
index d3e9be78b..8a5b5caee 100644
--- a/src/mwindow.c
+++ b/src/mwindow.c
@@ -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);
diff --git a/src/mwindow.h b/src/mwindow.h
index 63418e458..bdde9e0a4 100644
--- a/src/mwindow.h
+++ b/src/mwindow.h
@@ -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);
diff --git a/src/odb.c b/src/odb.c
index cb0f70623..1ecfe937f 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -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
diff --git a/src/odb_loose.c b/src/odb_loose.c
index 9d9bffd21..3c33160d0 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -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;
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 5a57864ad..0764207e5 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -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;
diff --git a/src/openssl_stream.c b/src/openssl_stream.c
index a65f5586e..9d97bae00 100644
--- a/src/openssl_stream.c
+++ b/src/openssl_stream.c
@@ -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;
}
diff --git a/src/pack-objects.c b/src/pack-objects.c
index 11e13f7d4..29231e028 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -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");
diff --git a/src/pack.c b/src/pack.c
index e7003e66d..6a700e29f 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -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
diff --git a/src/refspec.c b/src/refspec.c
index debde8692..d200e5609 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -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));
diff --git a/src/remote.c b/src/remote.c
index 8b7203ee2..15a00dd28 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -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)
diff --git a/src/repository.c b/src/repository.c
index 8a6fef0f6..c19790a8c 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -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)) {
diff --git a/src/stransport_stream.c b/src/stransport_stream.c
index 33b6c5c38..9d87d6029 100644
--- a/src/stransport_stream.c
+++ b/src/stransport_stream.c
@@ -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);
}
diff --git a/src/sysdir.c b/src/sysdir.c
index bf53d830f..29e53e239 100644
--- a/src/sysdir.c
+++ b/src/sysdir.c
@@ -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(
diff --git a/src/sysdir.h b/src/sysdir.h
index 12874fc85..11878981c 100644
--- a/src/sysdir.h
+++ b/src/sysdir.h
@@ -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__ */
diff --git a/src/tag.c b/src/tag.c
index c4bce1f22..fe840fe82 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -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;
diff --git a/src/thread-utils.h b/src/thread-utils.h
index 14c8a41ff..f0161989f 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -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 */
diff --git a/src/transports/http.c b/src/transports/http.c
index 88b124bf7..f0efd956a 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -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) {
diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c
index 2ea57bb64..2297cc94f 100644
--- a/src/transports/smart_pkt.c
+++ b/src/transports/smart_pkt.c
@@ -433,6 +433,7 @@ int git_pkt_parse_line(
* line?
*/
if (len == PKT_LEN_SIZE) {
+ *head = NULL;
*out = line;
return 0;
}
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index 02e1ecf74..3448fa7fb 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -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 */
diff --git a/src/tree.c b/src/tree.c
index 6ce460c6d..3874e45f4 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -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;
diff --git a/src/unix/pthread.h b/src/unix/pthread.h
new file mode 100644
index 000000000..0f3f17927
--- /dev/null
+++ b/src/unix/pthread.h
@@ -0,0 +1,54 @@
+/*
+ * 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__ */
diff --git a/src/util.c b/src/util.c
index 9e67f4347..cc4b43241 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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;
}
diff --git a/src/win32/precompiled.h b/src/win32/precompiled.h
index 33ce106d3..10ca0b80c 100644
--- a/src/win32/precompiled.h
+++ b/src/win32/precompiled.h
@@ -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"
diff --git a/src/win32/pthread.h b/src/win32/pthread.h
deleted file mode 100644
index e4826ca7f..000000000
--- a/src/win32/pthread.h
+++ /dev/null
@@ -1,92 +0,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 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
diff --git a/src/win32/pthread.c b/src/win32/thread.c
index a1cc18932..80d56ce5d 100644
--- a/src/win32/pthread.c
+++ b/src/win32/thread.c
@@ -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;
-}
diff --git a/src/win32/thread.h b/src/win32/thread.h
new file mode 100644
index 000000000..0d01822a6
--- /dev/null
+++ b/src/win32/thread.h
@@ -0,0 +1,62 @@
+/*
+ * 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__ */
diff --git a/tests/checkout/index.c b/tests/checkout/index.c
index 8af3e5684..ca63dc3f8 100644
--- a/tests/checkout/index.c
+++ b/tests/checkout/index.c
@@ -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);
}
diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c
index 5680b86df..4a0314a9e 100644
--- a/tests/checkout/tree.c
+++ b/tests/checkout/tree.c
@@ -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));
+}
diff --git a/tests/checkout/typechange.c b/tests/checkout/typechange.c
index b4959a351..8a5110caa 100644
--- a/tests/checkout/typechange.c
+++ b/tests/checkout/typechange.c
@@ -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;
diff --git a/tests/core/strtol.c b/tests/core/strtol.c
index 8765e042b..0d3b6a5e6 100644
--- a/tests/core/strtol.c
+++ b/tests/core/strtol.c
@@ -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);
}
diff --git a/tests/index/collision.c b/tests/index/collision.c
index 19c1548e9..ad5827e0b 100644
--- a/tests/index/collision.c
+++ b/tests/index/collision.c
@@ -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));
}
diff --git a/tests/index/read_index.c b/tests/index/read_index.c
index 82a771d54..6d14bc9fd 100644
--- a/tests/index/read_index.c
+++ b/tests/index/read_index.c
@@ -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);
+}
diff --git a/tests/object/cache.c b/tests/object/cache.c
index bdf12da7a..680f23630 100644
--- a/tests/object/cache.c
+++ b/tests/object/cache.c
@@ -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
diff --git a/tests/object/tag/read.c b/tests/object/tag/read.c
index c9787a413..8f28afd54 100644
--- a/tests/object/tag/read.c
+++ b/tests/object/tag/read.c
@@ -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);
+}
diff --git a/tests/odb/emptyobjects.c b/tests/odb/emptyobjects.c
index 783d05197..61bb2b82c 100644
--- a/tests/odb/emptyobjects.c
+++ b/tests/odb/emptyobjects.c
@@ -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);
}
diff --git a/tests/online/fetchhead.c b/tests/online/fetchhead.c
index 200edacfd..9aaad253c 100644
--- a/tests/online/fetchhead.c
+++ b/tests/online/fetchhead.c
@@ -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());
+}
diff --git a/tests/repo/discover.c b/tests/repo/discover.c
index 86bd7458f..358daee9f 100644
--- a/tests/repo/discover.c
+++ b/tests/repo/discover.c
@@ -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));
diff --git a/tests/repo/open.c b/tests/repo/open.c
index d3d087231..7cdd182a7 100644
--- a/tests/repo/open.c
+++ b/tests/repo/open.c
@@ -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));
diff --git a/tests/reset/hard.c b/tests/reset/hard.c
index e461f8093..69ef41e50 100644
--- a/tests/reset/hard.c
+++ b/tests/reset/hard.c
@@ -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"));
diff --git a/tests/status/ignore.c b/tests/status/ignore.c
index c318046da..c4878b2dd 100644
--- a/tests/status/ignore.c
+++ b/tests/status/ignore.c
@@ -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;
diff --git a/tests/threads/refdb.c b/tests/threads/refdb.c
index 6589e3922..f869bcb44 100644
--- a/tests/threads/refdb.c
+++ b/tests/threads/refdb.c
@@ -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) {
diff --git a/tests/threads/thread_helpers.c b/tests/threads/thread_helpers.c
index 760a7bd33..54bf6097d 100644
--- a/tests/threads/thread_helpers.c
+++ b/tests/threads/thread_helpers.c
@@ -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