summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Lopez <seniorlopez@gmail.com>2018-01-02 13:29:49 -0800
committerBrian Lopez <seniorlopez@gmail.com>2018-01-02 13:29:49 -0800
commite8bc855834e188dd87515ef232758a70357f4c85 (patch)
tree5ed7b6d899a644b5c46d8ab90c0758a55900e9f9
parent72fbf05ceb088e6592b44d7656ed2bca14506696 (diff)
parent7610638ec829ffd6da6d5f74b5b14dbb32b74924 (diff)
downloadlibgit2-e8bc855834e188dd87515ef232758a70357f4c85.tar.gz
Merge remote-tracking branch 'origin/master' into charliesome/trailer-info
-rw-r--r--CMakeLists.txt8
-rw-r--r--git.git-authors1
-rw-r--r--include/git2/notes.h89
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/checkout.c7
-rw-r--r--src/diff_file.c4
-rw-r--r--src/fetchhead.c2
-rw-r--r--src/fileops.c10
-rw-r--r--src/fileops.h5
-rw-r--r--src/hash/hash_common_crypto.h17
-rw-r--r--src/hash/hash_win32.c30
-rw-r--r--src/indexer.c14
-rw-r--r--src/iterator.c37
-rw-r--r--src/iterator.h2
-rw-r--r--src/notes.c212
-rw-r--r--src/object.c13
-rw-r--r--src/object.h2
-rw-r--r--src/odb_loose.c195
-rw-r--r--src/pack-objects.c6
-rw-r--r--src/pack.c17
-rw-r--r--src/patch_parse.c50
-rw-r--r--src/push.c171
-rw-r--r--src/refdb_fs.c1
-rw-r--r--src/remote.c17
-rw-r--r--src/streams/openssl.c29
-rw-r--r--src/streams/stransport.c4
-rw-r--r--src/transports/local.c23
-rw-r--r--src/transports/winhttp.c17
-rw-r--r--src/util.c44
-rw-r--r--src/util.h1
-rw-r--r--src/zstream.c30
-rw-r--r--tests/core/string.c42
-rw-r--r--tests/diff/blob.c39
-rw-r--r--tests/fetchhead/nonetwork.c88
-rw-r--r--tests/merge/workdir/submodules.c36
-rw-r--r--tests/notes/notes.c274
-rw-r--r--tests/odb/largefiles.c114
-rw-r--r--tests/pack/indexer.c68
-rw-r--r--tests/patch/parse.c6
-rw-r--r--tests/patch/patch_common.h10
-rw-r--r--tests/refs/iterator.c84
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/50/c5dc8cdfe40c688eb0a0e23be54dd57cae2e782
-rw-r--r--tests/resources/merge-resolve/.gitted/objects/7a/a825857f87aea74ddf13d954568aa30dfcdeb4bin0 -> 117 bytes
-rw-r--r--tests/resources/merge-resolve/.gitted/refs/heads/delete-submodule1
44 files changed, 1397 insertions, 427 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 549f34ad8..bedf85819 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -43,7 +43,6 @@ OPTION( ENABLE_TRACE "Enables tracing support" OFF )
OPTION( LIBGIT2_FILENAME "Name of the produced binary" OFF )
OPTION( USE_SHA1DC "Use SHA-1 with collision detection" OFF )
-OPTION( USE_ICONV "Link with and use iconv library" OFF )
OPTION( USE_SSH "Link with libssh to enable SSH support" ON )
OPTION( USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON )
OPTION( USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF )
@@ -52,10 +51,15 @@ OPTION( CURL "Use curl for HTTP if available" ON)
OPTION( USE_EXT_HTTP_PARSER "Use system HTTP_Parser if available" ON)
OPTION( DEBUG_POOL "Enable debug pool allocator" OFF )
OPTION( ENABLE_WERROR "Enable compilation with -Werror" OFF )
+OPTION( USE_BUNDLED_ZLIB "Use the bundled version of zlib" OFF )
+
IF (UNIX AND NOT APPLE)
OPTION( ENABLE_REPRODUCIBLE_BUILDS "Enable reproducible builds" OFF )
ENDIF()
-OPTION( USE_BUNDLED_ZLIB "Use the bundled version of zlib" OFF )
+
+IF (APPLE)
+ OPTION( USE_ICONV "Link with and use iconv library" ON )
+ENDIF()
IF(MSVC)
# This option is only available when building with MSVC. By default, libgit2
diff --git a/git.git-authors b/git.git-authors
index 6a85224b4..3bc009fcc 100644
--- a/git.git-authors
+++ b/git.git-authors
@@ -53,6 +53,7 @@ ok Jeff King <peff@peff.net>
ok Johannes Schindelin <Johannes.Schindelin@gmx.de>
ok Johannes Sixt <j6t@kdbg.org>
ask Jonathan Nieder <jrnieder@gmail.com>
+ok Jonathan Tan <jonathantanmy@google.com>
ok Junio C Hamano <gitster@pobox.com>
ok Kristian Høgsberg <krh@redhat.com>
ok Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/include/git2/notes.h b/include/git2/notes.h
index 3a626cafd..853e5de59 100644
--- a/include/git2/notes.h
+++ b/include/git2/notes.h
@@ -52,6 +52,20 @@ GIT_EXTERN(int) git_note_iterator_new(
const char *notes_ref);
/**
+ * Creates a new iterator for notes from a commit
+ *
+ * The iterator must be freed manually by the user.
+ *
+ * @param out pointer to the iterator
+ * @param notes_commit a pointer to the notes commit object
+ *
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_note_commit_iterator_new(
+ git_note_iterator **out,
+ git_commit *notes_commit);
+
+/**
* Frees an git_note_iterator
*
* @param it pointer to the iterator
@@ -94,6 +108,25 @@ GIT_EXTERN(int) git_note_read(
const char *notes_ref,
const git_oid *oid);
+
+/**
+ * Read the note for an object from a note commit
+ *
+ * The note must be freed manually by the user.
+ *
+ * @param out pointer to the read note; NULL in case of error
+ * @param repo repository where to look up the note
+ * @param notes_commit a pointer to the notes commit object
+ * @param oid OID of the git object to read the note from
+ *
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_note_commit_read(
+ git_note **out,
+ git_repository *repo,
+ git_commit *notes_commit,
+ const git_oid *oid);
+
/**
* Get the note author
*
@@ -153,6 +186,36 @@ GIT_EXTERN(int) git_note_create(
const char *note,
int force);
+/**
+ * Add a note for an object from a commit
+ *
+ * This function will create a notes commit for a given object,
+ * the commit is a dangling commit, no reference is created.
+ *
+ * @param notes_commit_out pointer to store the commit (optional);
+ * NULL in case of error
+ * @param notes_blob_out a point to the id of a note blob (optional)
+ * @param repo repository where the note will live
+ * @param parent Pointer to parent note
+ * or NULL if this shall start a new notes tree
+ * @param author signature of the notes commit author
+ * @param committer signature of the notes commit committer
+ * @param oid OID of the git object to decorate
+ * @param note Content of the note to add for object oid
+ * @param allow_note_overwrite Overwrite existing note
+ *
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_note_commit_create(
+ git_oid *notes_commit_out,
+ git_oid *notes_blob_out,
+ git_repository *repo,
+ git_commit *parent,
+ const git_signature *author,
+ const git_signature *committer,
+ const git_oid *oid,
+ const char *note,
+ int allow_note_overwrite);
/**
* Remove the note for an object
@@ -174,6 +237,32 @@ GIT_EXTERN(int) git_note_remove(
const git_oid *oid);
/**
+ * Remove the note for an object
+ *
+ * @param notes_commit_out pointer to store the new notes commit (optional);
+ * NULL in case of error.
+ * When removing a note a new tree containing all notes
+ * sans the note to be removed is created and a new commit
+ * pointing to that tree is also created.
+ * In the case where the resulting tree is an empty tree
+ * a new commit pointing to this empty tree will be returned.
+ * @param repo repository where the note lives
+ * @param notes_commit a pointer to the notes commit object
+ * @param author signature of the notes commit author
+ * @param committer signature of the notes commit committer
+ * @param oid OID of the git object to remove the note from
+ *
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_note_commit_remove(
+ git_oid *notes_commit_out,
+ git_repository *repo,
+ git_commit *notes_commit,
+ const git_signature *author,
+ const git_signature *committer,
+ const git_oid *oid);
+
+/**
* Free a git_note object
*
* @param note git_note object
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e456ab725..2c82d1f59 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -310,7 +310,7 @@ ENDIF()
ADD_FEATURE_INFO(SPNEGO GIT_GSSAPI "SPNEGO authentication support")
# Optional external dependency: iconv
-IF (USE_ICONV OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
+IF (USE_ICONV)
FIND_PACKAGE(Iconv)
ENDIF()
IF (ICONV_FOUND)
diff --git a/src/checkout.c b/src/checkout.c
index caed6cdf1..528fbdf92 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2022,8 +2022,11 @@ static int checkout_write_entry(
(error = checkout_safe_for_update_only(data, fullpath->ptr, side->mode)) <= 0)
return error;
- return checkout_write_content(data,
- &side->id, fullpath->ptr, hint_path, side->mode, &st);
+ if (!S_ISGITLINK(side->mode))
+ return checkout_write_content(data,
+ &side->id, fullpath->ptr, hint_path, side->mode, &st);
+
+ return 0;
}
static int checkout_write_entries(
diff --git a/src/diff_file.c b/src/diff_file.c
index 270d59bbb..0813315f5 100644
--- a/src/diff_file.c
+++ b/src/diff_file.c
@@ -139,7 +139,6 @@ int git_diff_file_content__init_from_src(
memset(fc, 0, sizeof(*fc));
fc->repo = repo;
fc->file = as_file;
- fc->blob = src->blob;
if (!src->blob && !src->buf) {
fc->flags |= GIT_DIFF_FLAG__NO_DATA;
@@ -149,12 +148,15 @@ int git_diff_file_content__init_from_src(
fc->file->mode = GIT_FILEMODE_BLOB;
if (src->blob) {
+ git_blob_dup((git_blob **)&fc->blob, (git_blob *) src->blob);
fc->file->size = git_blob_rawsize(src->blob);
git_oid_cpy(&fc->file->id, git_blob_id(src->blob));
fc->file->id_abbrev = GIT_OID_HEXSZ;
fc->map.len = (size_t)fc->file->size;
fc->map.data = (char *)git_blob_rawcontent(src->blob);
+
+ fc->flags |= GIT_DIFF_FLAG__FREE_BLOB;
} else {
fc->file->size = src->buflen;
git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJ_BLOB);
diff --git a/src/fetchhead.c b/src/fetchhead.c
index ac25723d3..e55e7c85b 100644
--- a/src/fetchhead.c
+++ b/src/fetchhead.c
@@ -118,7 +118,7 @@ int git_fetchhead_write(git_repository *repo, git_vector *fetchhead_refs)
if (git_buf_joinpath(&path, repo->gitdir, GIT_FETCH_HEAD_FILE) < 0)
return -1;
- if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE) < 0) {
+ if (git_filebuf_open(&file, path.ptr, GIT_FILEBUF_APPEND, GIT_REFS_FILE_MODE) < 0) {
git_buf_free(&path);
return -1;
}
diff --git a/src/fileops.c b/src/fileops.c
index ad3f67e2b..58988c2d2 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -102,6 +102,16 @@ int git_futils_open_ro(const char *path)
return fd;
}
+int git_futils_truncate(const char *path, int mode)
+{
+ int fd = p_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
+ if (fd < 0)
+ return git_path_set_error(errno, path, "open");
+
+ close(fd);
+ return 0;
+}
+
git_off_t git_futils_filesize(git_file fd)
{
struct stat sb;
diff --git a/src/fileops.h b/src/fileops.h
index fd5441243..57b9d173e 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -248,6 +248,11 @@ extern int git_futils_cp_r(
extern int git_futils_open_ro(const char *path);
/**
+ * Truncate a file, creating it if it doesn't exist.
+ */
+extern int git_futils_truncate(const char *path, int mode);
+
+/**
* Get the filesize in bytes of a file
*/
extern git_off_t git_futils_filesize(git_file fd);
diff --git a/src/hash/hash_common_crypto.h b/src/hash/hash_common_crypto.h
index eeeddd0cc..4cd229d3c 100644
--- a/src/hash/hash_common_crypto.h
+++ b/src/hash/hash_common_crypto.h
@@ -16,6 +16,8 @@ struct git_hash_ctx {
CC_SHA1_CTX c;
};
+#define CC_LONG_MAX ((CC_LONG)-1)
+
#define git_hash_global_init() 0
#define git_hash_ctx_init(ctx) git_hash_init(ctx)
#define git_hash_ctx_cleanup(ctx)
@@ -27,10 +29,21 @@ GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
return 0;
}
-GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
+GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *_data, size_t len)
{
+ const unsigned char *data = _data;
+
assert(ctx);
- CC_SHA1_Update(&ctx->c, data, len);
+
+ while (len > 0) {
+ CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len;
+
+ CC_SHA1_Update(&ctx->c, data, chunk);
+
+ data += chunk;
+ len -= chunk;
+ }
+
return 0;
}
diff --git a/src/hash/hash_win32.c b/src/hash/hash_win32.c
index 4d53a57bd..20ba9a5fe 100644
--- a/src/hash/hash_win32.c
+++ b/src/hash/hash_win32.c
@@ -136,12 +136,21 @@ GIT_INLINE(int) hash_cryptoapi_init(git_hash_ctx *ctx)
return 0;
}
-GIT_INLINE(int) hash_cryptoapi_update(git_hash_ctx *ctx, const void *data, size_t len)
+GIT_INLINE(int) hash_cryptoapi_update(git_hash_ctx *ctx, const void *_data, size_t len)
{
+ const BYTE *data = (BYTE *)_data;
+
assert(ctx->ctx.cryptoapi.valid);
- if (!CryptHashData(ctx->ctx.cryptoapi.hash_handle, (const BYTE *)data, (DWORD)len, 0))
- return -1;
+ while (len > 0) {
+ DWORD chunk = (len > MAXDWORD) ? MAXDWORD : (DWORD)len;
+
+ if (!CryptHashData(ctx->ctx.cryptoapi.hash_handle, data, chunk, 0))
+ return -1;
+
+ data += chunk;
+ len -= chunk;
+ }
return 0;
}
@@ -202,10 +211,19 @@ GIT_INLINE(int) hash_cng_init(git_hash_ctx *ctx)
return 0;
}
-GIT_INLINE(int) hash_cng_update(git_hash_ctx *ctx, const void *data, size_t len)
+GIT_INLINE(int) hash_cng_update(git_hash_ctx *ctx, const void *_data, size_t len)
{
- if (ctx->prov->prov.cng.hash_data(ctx->ctx.cng.hash_handle, (PBYTE)data, (ULONG)len, 0) < 0)
- return -1;
+ PBYTE data = (PBYTE)_data;
+
+ while (len > 0) {
+ ULONG chunk = (len > ULONG_MAX) ? ULONG_MAX : (ULONG)len;
+
+ if (ctx->prov->prov.cng.hash_data(ctx->ctx.cng.hash_handle, data, chunk, 0) < 0)
+ return -1;
+
+ data += chunk;
+ len -= chunk;
+ }
return 0;
}
diff --git a/src/indexer.c b/src/indexer.c
index aedefe523..a5e842272 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -844,6 +844,7 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats)
static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
{
unsigned int i;
+ int error;
struct delta_info *delta;
int progressed = 0, non_null = 0, progress_cb_result;
@@ -858,8 +859,13 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
non_null = 1;
idx->off = delta->delta_off;
- if (git_packfile_unpack(&obj, idx->pack, &idx->off) < 0)
- continue;
+ if ((error = git_packfile_unpack(&obj, idx->pack, &idx->off)) < 0) {
+ if (error == GIT_PASSTHROUGH) {
+ /* We have not seen the base object, we'll try again later. */
+ continue;
+ }
+ return -1;
+ }
if (hash_and_save(idx, &obj, delta->delta_off) < 0)
continue;
@@ -951,6 +957,10 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack");
return -1;
}
+ if (idx->off + 20 > idx->pack->mwf.size) {
+ giterr_set(GITERR_INDEXER, "missing trailer at the end of the pack");
+ return -1;
+ }
packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ, &left);
if (packfile_trailer == NULL) {
diff --git a/src/iterator.c b/src/iterator.c
index 960031233..132b2c77c 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -23,6 +23,7 @@
#define iterator__has_been_accessed(I) iterator__flag(I,FIRST_ACCESS)
#define iterator__honor_ignores(I) iterator__flag(I,HONOR_IGNORES)
#define iterator__ignore_dot_git(I) iterator__flag(I,IGNORE_DOT_GIT)
+#define iterator__descend_symlinks(I) iterator__flag(I,DESCEND_SYMLINKS)
static void iterator_set_ignore_case(git_iterator *iter, bool ignore_case)
@@ -1491,10 +1492,41 @@ static int filesystem_iterator_current(
return 0;
}
+static int filesystem_iterator_is_dir(
+ bool *is_dir,
+ const filesystem_iterator *iter,
+ const filesystem_iterator_entry *entry)
+{
+ struct stat st;
+ git_buf fullpath = GIT_BUF_INIT;
+ int error = 0;
+
+ if (S_ISDIR(entry->st.st_mode)) {
+ *is_dir = 1;
+ goto done;
+ }
+
+ if (!iterator__descend_symlinks(iter) || !S_ISLNK(entry->st.st_mode)) {
+ *is_dir = 0;
+ goto done;
+ }
+
+ if ((error = git_buf_joinpath(&fullpath, iter->root, entry->path)) < 0 ||
+ (error = p_stat(fullpath.ptr, &st)) < 0)
+ goto done;
+
+ *is_dir = S_ISDIR(st.st_mode);
+
+done:
+ git_buf_free(&fullpath);
+ return error;
+}
+
static int filesystem_iterator_advance(
const git_index_entry **out, git_iterator *i)
{
filesystem_iterator *iter = (filesystem_iterator *)i;
+ bool is_dir;
int error = 0;
iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS;
@@ -1519,7 +1551,10 @@ static int filesystem_iterator_advance(
entry = frame->entries.contents[frame->next_idx];
frame->next_idx++;
- if (S_ISDIR(entry->st.st_mode)) {
+ if ((error = filesystem_iterator_is_dir(&is_dir, iter, entry)) < 0)
+ break;
+
+ if (is_dir) {
if (iterator__do_autoexpand(iter)) {
error = filesystem_iterator_frame_push(iter, entry);
diff --git a/src/iterator.h b/src/iterator.h
index 0bcb128d9..a6497d87b 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -39,6 +39,8 @@ typedef enum {
GIT_ITERATOR_DONT_PRECOMPOSE_UNICODE = (1u << 5),
/** include conflicts */
GIT_ITERATOR_INCLUDE_CONFLICTS = (1u << 6),
+ /** descend into symlinked directories */
+ GIT_ITERATOR_DESCEND_SYMLINKS = (1u << 7),
} git_iterator_flag_t;
typedef enum {
diff --git a/src/notes.c b/src/notes.c
index 75108b9c9..f63ef3667 100644
--- a/src/notes.c
+++ b/src/notes.c
@@ -268,7 +268,9 @@ static int insert_note_in_tree_enotfound_cb(git_tree **out,
GIT_FILEMODE_BLOB);
}
-static int note_write(git_oid *out,
+static int note_write(
+ git_oid *notes_commit_out,
+ git_oid *notes_blob_out,
git_repository *repo,
const git_signature *author,
const git_signature *committer,
@@ -294,13 +296,17 @@ static int note_write(git_oid *out,
insert_note_in_tree_enotfound_cb)) < 0)
goto cleanup;
- if (out)
- git_oid_cpy(out, &oid);
+ if (notes_blob_out)
+ git_oid_cpy(notes_blob_out, &oid);
+
error = git_commit_create(&oid, repo, notes_ref, author, committer,
NULL, GIT_NOTES_DEFAULT_MSG_ADD,
tree, *parents == NULL ? 0 : 1, (const git_commit **) parents);
+ if (notes_commit_out)
+ git_oid_cpy(notes_commit_out, &oid);
+
cleanup:
git_tree_free(tree);
return error;
@@ -363,7 +369,9 @@ cleanup:
return error;
}
-static int note_remove(git_repository *repo,
+static int note_remove(
+ git_oid *notes_commit_out,
+ git_repository *repo,
const git_signature *author, const git_signature *committer,
const char *notes_ref, git_tree *tree,
const char *target, git_commit **parents)
@@ -383,6 +391,12 @@ static int note_remove(git_repository *repo,
*parents == NULL ? 0 : 1,
(const git_commit **) parents);
+ if (error < 0)
+ goto cleanup;
+
+ if (notes_commit_out)
+ git_oid_cpy(notes_commit_out, &oid);
+
cleanup:
git_tree_free(tree_after_removal);
return error;
@@ -410,8 +424,7 @@ static int normalize_namespace(char **out, git_repository *repo, const char *not
return note_get_default_ref(out, repo);
}
-static int retrieve_note_tree_and_commit(
- git_tree **tree_out,
+static int retrieve_note_commit(
git_commit **commit_out,
char **notes_ref_out,
git_repository *repo,
@@ -429,34 +442,82 @@ static int retrieve_note_tree_and_commit(
if (git_commit_lookup(commit_out, repo, &oid) < 0)
return error;
- if ((error = git_commit_tree(tree_out, *commit_out)) < 0)
- return error;
-
return 0;
}
+int git_note_commit_read(
+ git_note **out,
+ git_repository *repo,
+ git_commit *notes_commit,
+ const git_oid *oid)
+{
+ int error;
+ git_tree *tree = NULL;
+ char target[GIT_OID_HEXSZ + 1];
+
+ git_oid_tostr(target, sizeof(target), oid);
+
+ if ((error = git_commit_tree(&tree, notes_commit)) < 0)
+ goto cleanup;
+
+ error = note_lookup(out, repo, notes_commit, tree, target);
+
+cleanup:
+ git_tree_free(tree);
+ return error;
+}
+
int git_note_read(git_note **out, git_repository *repo,
const char *notes_ref_in, const git_oid *oid)
{
int error;
- char *target = NULL, *notes_ref = NULL;
- git_tree *tree = NULL;
+ char *notes_ref = NULL;
git_commit *commit = NULL;
- target = git_oid_allocfmt(oid);
- GITERR_CHECK_ALLOC(target);
+ error = retrieve_note_commit(&commit, &notes_ref, repo, notes_ref_in);
- if (!(error = retrieve_note_tree_and_commit(
- &tree, &commit, &notes_ref, repo, notes_ref_in)))
- error = note_lookup(out, repo, commit, tree, target);
+ if (error < 0)
+ goto cleanup;
+ error = git_note_commit_read(out, repo, commit, oid);
+
+cleanup:
git__free(notes_ref);
- git__free(target);
- git_tree_free(tree);
git_commit_free(commit);
return error;
}
+int git_note_commit_create(
+ git_oid *notes_commit_out,
+ git_oid *notes_blob_out,
+ git_repository *repo,
+ git_commit *parent,
+ const git_signature *author,
+ const git_signature *committer,
+ const git_oid *oid,
+ const char *note,
+ int allow_note_overwrite)
+{
+ int error;
+ git_tree *tree = NULL;
+ char target[GIT_OID_HEXSZ + 1];
+
+ git_oid_tostr(target, sizeof(target), oid);
+
+ if (parent != NULL && (error = git_commit_tree(&tree, parent)) < 0)
+ goto cleanup;
+
+ error = note_write(notes_commit_out, notes_blob_out, repo, author,
+ committer, NULL, note, tree, target, &parent, allow_note_overwrite);
+
+ if (error < 0)
+ goto cleanup;
+
+cleanup:
+ git_tree_free(tree);
+ return error;
+}
+
int git_note_create(
git_oid *out,
git_repository *repo,
@@ -468,25 +529,59 @@ int git_note_create(
int allow_note_overwrite)
{
int error;
- char *target = NULL, *notes_ref = NULL;
- git_commit *commit = NULL;
- git_tree *tree = NULL;
-
- target = git_oid_allocfmt(oid);
- GITERR_CHECK_ALLOC(target);
+ char *notes_ref = NULL;
+ git_commit *existing_notes_commit = NULL;
+ git_reference *ref = NULL;
+ git_oid notes_blob_oid, notes_commit_oid;
- error = retrieve_note_tree_and_commit(&tree, &commit, &notes_ref, repo, notes_ref_in);
+ error = retrieve_note_commit(&existing_notes_commit, &notes_ref,
+ repo, notes_ref_in);
if (error < 0 && error != GIT_ENOTFOUND)
goto cleanup;
- error = note_write(out, repo, author, committer, notes_ref,
- note, tree, target, &commit, allow_note_overwrite);
+ error = git_note_commit_create(&notes_commit_oid,
+ &notes_blob_oid,
+ repo, existing_notes_commit, author,
+ committer, oid, note,
+ allow_note_overwrite);
+ if (error < 0)
+ goto cleanup;
+
+ error = git_reference_create(&ref, repo, notes_ref,
+ &notes_commit_oid, 1, NULL);
+
+ if (out != NULL)
+ git_oid_cpy(out, &notes_blob_oid);
cleanup:
git__free(notes_ref);
- git__free(target);
- git_commit_free(commit);
+ git_commit_free(existing_notes_commit);
+ git_reference_free(ref);
+ return error;
+}
+
+int git_note_commit_remove(
+ git_oid *notes_commit_out,
+ git_repository *repo,
+ git_commit *notes_commit,
+ const git_signature *author,
+ const git_signature *committer,
+ const git_oid *oid)
+{
+ int error;
+ git_tree *tree = NULL;
+ char target[GIT_OID_HEXSZ + 1];
+
+ git_oid_tostr(target, sizeof(target), oid);
+
+ if ((error = git_commit_tree(&tree, notes_commit)) < 0)
+ goto cleanup;
+
+ error = note_remove(notes_commit_out,
+ repo, author, committer, NULL, tree, target, &notes_commit);
+
+cleanup:
git_tree_free(tree);
return error;
}
@@ -496,22 +591,29 @@ int git_note_remove(git_repository *repo, const char *notes_ref_in,
const git_oid *oid)
{
int error;
- char *target = NULL, *notes_ref;
- git_commit *commit = NULL;
- git_tree *tree = NULL;
+ char *notes_ref_target = NULL;
+ git_commit *existing_notes_commit = NULL;
+ git_oid new_notes_commit;
+ git_reference *notes_ref = NULL;
- target = git_oid_allocfmt(oid);
- GITERR_CHECK_ALLOC(target);
+ error = retrieve_note_commit(&existing_notes_commit, &notes_ref_target,
+ repo, notes_ref_in);
- if (!(error = retrieve_note_tree_and_commit(
- &tree, &commit, &notes_ref, repo, notes_ref_in)))
- error = note_remove(
- repo, author, committer, notes_ref, tree, target, &commit);
+ if (error < 0)
+ goto cleanup;
- git__free(notes_ref);
- git__free(target);
- git_commit_free(commit);
- git_tree_free(tree);
+ error = git_note_commit_remove(&new_notes_commit, repo,
+ existing_notes_commit, author, committer, oid);
+ if (error < 0)
+ goto cleanup;
+
+ error = git_reference_create(&notes_ref, repo, notes_ref_target,
+ &new_notes_commit, 1, NULL);
+
+cleanup:
+ git__free(notes_ref_target);
+ git_reference_free(notes_ref);
+ git_commit_free(existing_notes_commit);
return error;
}
@@ -639,7 +741,6 @@ int git_note_foreach(
return error;
}
-
void git_note_iterator_free(git_note_iterator *it)
{
if (it == NULL)
@@ -648,6 +749,24 @@ void git_note_iterator_free(git_note_iterator *it)
git_iterator_free(it);
}
+int git_note_commit_iterator_new(
+ git_note_iterator **it,
+ git_commit *notes_commit)
+{
+ int error;
+ git_tree *tree;
+
+ if ((error = git_commit_tree(&tree, notes_commit)) < 0)
+ goto cleanup;
+
+ if ((error = git_iterator_for_tree(it, tree, NULL)) < 0)
+ git_iterator_free(*it);
+
+cleanup:
+ git_tree_free(tree);
+
+ return error;
+}
int git_note_iterator_new(
git_note_iterator **it,
@@ -656,19 +775,16 @@ int git_note_iterator_new(
{
int error;
git_commit *commit = NULL;
- git_tree *tree = NULL;
char *notes_ref;
- error = retrieve_note_tree_and_commit(&tree, &commit, &notes_ref, repo, notes_ref_in);
+ error = retrieve_note_commit(&commit, &notes_ref, repo, notes_ref_in);
if (error < 0)
goto cleanup;
- if ((error = git_iterator_for_tree(it, tree, NULL)) < 0)
- git_iterator_free(*it);
+ error = git_note_commit_iterator_new(it, commit);
cleanup:
git__free(notes_ref);
- git_tree_free(tree);
git_commit_free(commit);
return error;
diff --git a/src/object.c b/src/object.c
index 4d069a34c..48f561384 100644
--- a/src/object.c
+++ b/src/object.c
@@ -236,13 +236,22 @@ const char *git_object_type2string(git_otype type)
git_otype git_object_string2type(const char *str)
{
+ if (!str)
+ return GIT_OBJ_BAD;
+
+ return git_object_stringn2type(str, strlen(str));
+}
+
+git_otype git_object_stringn2type(const char *str, size_t len)
+{
size_t i;
- if (!str || !*str)
+ if (!str || !len || !*str)
return GIT_OBJ_BAD;
for (i = 0; i < ARRAY_SIZE(git_objects_table); i++)
- if (!strcmp(str, git_objects_table[i].str))
+ if (*git_objects_table[i].str &&
+ !git__prefixncmp(str, len, git_objects_table[i].str))
return (git_otype)i;
return GIT_OBJ_BAD;
diff --git a/src/object.h b/src/object.h
index ff61c1d33..e46c9cafa 100644
--- a/src/object.h
+++ b/src/object.h
@@ -30,6 +30,8 @@ int git_object__from_odb_object(
int git_object__resolve_to_type(git_object **obj, git_otype type);
+git_otype git_object_stringn2type(const char *str, size_t len);
+
int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header);
void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid);
diff --git a/src/odb_loose.c b/src/odb_loose.c
index 72b47f091..9900aae2a 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -16,6 +16,7 @@
#include "delta.h"
#include "filebuf.h"
#include "object.h"
+#include "zstream.h"
#include "git2/odb_backend.h"
#include "git2/types.h"
@@ -119,53 +120,58 @@ static size_t get_binary_object_header(obj_hdr *hdr, git_buf *obj)
return used;
}
-static size_t get_object_header(obj_hdr *hdr, unsigned char *data)
+static int parse_header(
+ obj_hdr *out,
+ size_t *out_len,
+ const unsigned char *_data,
+ size_t data_len)
{
- char c, typename[10];
- size_t size, used = 0;
+ const char *data = (char *)_data;
+ size_t i, typename_len, size_idx, size_len;
+ int64_t size;
- /*
- * type name string followed by space.
- */
- while ((c = data[used]) != ' ') {
- typename[used++] = c;
- if (used >= sizeof(typename))
- return 0;
+ *out_len = 0;
+
+ /* find the object type name */
+ for (i = 0, typename_len = 0; i < data_len; i++, typename_len++) {
+ if (data[i] == ' ')
+ break;
}
- typename[used] = 0;
- if (used == 0)
- return 0;
- hdr->type = git_object_string2type(typename);
- used++; /* consume the space */
- /*
- * length follows immediately in decimal (without
- * leading zeros).
- */
- size = data[used++] - '0';
- if (size > 9)
- return 0;
- if (size) {
- while ((c = data[used]) != '\0') {
- size_t d = c - '0';
- if (d > 9)
- break;
- used++;
- size = size * 10 + d;
- }
+ if (typename_len == data_len)
+ goto on_error;
+
+ out->type = git_object_stringn2type(data, typename_len);
+
+ size_idx = typename_len + 1;
+ for (i = size_idx, size_len = 0; i < data_len; i++, size_len++) {
+ if (data[i] == '\0')
+ break;
}
- hdr->size = size;
- /*
- * the length must be followed by a zero byte
- */
- if (data[used++] != '\0')
- return 0;
+ if (i == data_len)
+ goto on_error;
- return used;
-}
+ if (git__strntol64(&size, &data[size_idx], size_len, NULL, 10) < 0 ||
+ size < 0)
+ goto on_error;
+
+ if ((uint64_t)size > SIZE_MAX) {
+ giterr_set(GITERR_OBJECT, "object is larger than available memory");
+ return -1;
+ }
+ out->size = size;
+ if (GIT_ADD_SIZET_OVERFLOW(out_len, i, 1))
+ goto on_error;
+
+ return 0;
+
+on_error:
+ giterr_set(GITERR_OBJECT, "failed to parse loose object: invalid header");
+ return -1;
+}
/***********************************************************
*
@@ -269,45 +275,6 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
return 0;
}
-static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
-{
- unsigned char *buf, *head = hb;
- size_t tail, alloc_size;
-
- /*
- * allocate a buffer to hold the inflated data and copy the
- * initial sequence of inflated data from the tail of the
- * head buffer, if any.
- */
- if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr->size, 1) ||
- (buf = git__malloc(alloc_size)) == NULL) {
- inflateEnd(s);
- return NULL;
- }
- tail = s->total_out - used;
- if (used > 0 && tail > 0) {
- if (tail > hdr->size)
- tail = hdr->size;
- memcpy(buf, head + used, tail);
- }
- used = tail;
-
- /*
- * inflate the remainder of the object data, if any
- */
- if (hdr->size < used)
- inflateEnd(s);
- else {
- set_stream_output(s, buf + used, hdr->size - used);
- if (finish_inflate(s)) {
- git__free(buf);
- return NULL;
- }
- }
-
- return buf;
-}
-
/*
* At one point, there was a loose object format that was intended to
* mimic the format used in pack-files. This was to allow easy copying
@@ -354,43 +321,74 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
static int inflate_disk_obj(git_rawobj *out, git_buf *obj)
{
- unsigned char head[64], *buf;
- z_stream zs;
+ git_zstream zstream = GIT_ZSTREAM_INIT;
+ unsigned char head[64], *body = NULL;
+ size_t decompressed, head_len, body_len, alloc_size;
obj_hdr hdr;
- size_t used;
+ int error;
- /*
- * check for a pack-like loose object
- */
+ /* check for a pack-like loose object */
if (!is_zlib_compressed_data((unsigned char *)obj->ptr))
return inflate_packlike_loose_disk_obj(out, obj);
+ if ((error = git_zstream_init(&zstream, GIT_ZSTREAM_INFLATE)) < 0 ||
+ (error = git_zstream_set_input(&zstream, git_buf_cstr(obj), git_buf_len(obj))) < 0)
+ goto done;
+
+ decompressed = sizeof(head);
+
/*
- * inflate the initial part of the io buffer in order
- * to parse the object header (type and size).
- */
- if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK ||
- (used = get_object_header(&hdr, head)) == 0 ||
- !git_object_typeisloose(hdr.type))
- {
- abort_inflate(&zs);
+ * inflate the initial part of the compressed buffer in order to parse the
+ * header; read the largest header possible, then push back the remainder.
+ */
+ if ((error = git_zstream_get_output(head, &decompressed, &zstream)) < 0 ||
+ (error = parse_header(&hdr, &head_len, head, decompressed)) < 0)
+ goto done;
+
+ if (!git_object_typeisloose(hdr.type)) {
giterr_set(GITERR_ODB, "failed to inflate disk object");
- return -1;
+ error = -1;
+ goto done;
}
/*
* allocate a buffer and inflate the object data into it
* (including the initial sequence in the head buffer).
*/
- if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL)
- return -1;
- buf[hdr.size] = '\0';
+ if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr.size, 1) ||
+ (body = git__malloc(alloc_size)) == NULL) {
+ error = -1;
+ goto done;
+ }
- out->data = buf;
+ assert(decompressed >= head_len);
+ body_len = decompressed - head_len;
+
+ if (body_len)
+ memcpy(body, head + head_len, body_len);
+
+ decompressed = hdr.size - body_len;
+ if ((error = git_zstream_get_output(body + body_len, &decompressed, &zstream)) < 0)
+ goto done;
+
+ if (!git_zstream_done(&zstream)) {
+ giterr_set(GITERR_ZLIB, "failed to finish zlib inflation: stream aborted prematurely");
+ error = -1;
+ goto done;
+ }
+
+ body[hdr.size] = '\0';
+
+ out->data = body;
out->len = hdr.size;
out->type = hdr.type;
- return 0;
+done:
+ if (error < 0)
+ git__free(body);
+
+ git_zstream_free(&zstream);
+ return error;
}
@@ -435,6 +433,7 @@ static int read_header_loose(git_rawobj *out, git_buf *loc)
git_file fd;
z_stream zs;
obj_hdr header_obj;
+ size_t header_len;
unsigned char raw_buffer[16], inflated_buffer[64];
assert(out && loc);
@@ -460,7 +459,7 @@ static int read_header_loose(git_rawobj *out, git_buf *loc)
}
if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR)
- || get_object_header(&header_obj, inflated_buffer) == 0
+ || parse_header(&header_obj, &header_len, inflated_buffer, sizeof(inflated_buffer)) < 0
|| git_object_typeisloose(header_obj.type) == 0)
{
giterr_set(GITERR_ZLIB, "failed to read loose object header");
diff --git a/src/pack-objects.c b/src/pack-objects.c
index ef272e8f5..e9245143c 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -1642,7 +1642,7 @@ int insert_tree(git_packbuilder *pb, git_tree *tree)
if ((error = retrieve_object(&obj, pb, git_tree_id(tree))) < 0)
return error;
- if (obj->seen)
+ if (obj->seen || obj->uninteresting)
return 0;
obj->seen = 1;
@@ -1666,6 +1666,10 @@ int insert_tree(git_packbuilder *pb, git_tree *tree)
break;
case GIT_OBJ_BLOB:
+ if ((error = retrieve_object(&obj, pb, git_tree_id(tree))) < 0)
+ return error;
+ if (obj->uninteresting)
+ continue;
name = git_tree_entry_name(entry);
if ((error = git_packbuilder_insert(pb, entry_id, name)) < 0)
return error;
diff --git a/src/pack.c b/src/pack.c
index 7fd95c905..9ed3ec1af 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -716,8 +716,11 @@ int git_packfile_unpack(
error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, elem->size, elem->type);
git_mwindow_close(&w_curs);
- if (error < 0)
+ if (error < 0) {
+ /* We have transferred ownership of the data to the cache. */
+ obj->data = NULL;
break;
+ }
/* the current object becomes the new base, on which we apply the delta */
base = *obj;
@@ -934,19 +937,19 @@ git_off_t get_delta_base(
if (type == GIT_OBJ_OFS_DELTA) {
unsigned used = 0;
unsigned char c = base_info[used++];
- base_offset = c & 127;
+ size_t unsigned_base_offset = c & 127;
while (c & 128) {
if (left <= used)
return GIT_EBUFS;
- base_offset += 1;
- if (!base_offset || MSB(base_offset, 7))
+ unsigned_base_offset += 1;
+ if (!unsigned_base_offset || MSB(unsigned_base_offset, 7))
return 0; /* overflow */
c = base_info[used++];
- base_offset = (base_offset << 7) + (c & 127);
+ unsigned_base_offset = (unsigned_base_offset << 7) + (c & 127);
}
- base_offset = delta_obj_offset - base_offset;
- if (base_offset <= 0 || base_offset >= delta_obj_offset)
+ if (unsigned_base_offset == 0 || (size_t)delta_obj_offset <= unsigned_base_offset)
return 0; /* out of bound */
+ base_offset = delta_obj_offset - unsigned_base_offset;
*curpos += used;
} else if (type == GIT_OBJ_REF_DELTA) {
/* If we have the cooperative cache, search in it first */
diff --git a/src/patch_parse.c b/src/patch_parse.c
index 48afcc1ed..27c01e96f 100644
--- a/src/patch_parse.c
+++ b/src/patch_parse.c
@@ -53,11 +53,9 @@ static int header_path_len(git_patch_parse_ctx *ctx)
return len;
}
-static int parse_header_path_buf(git_buf *path, git_patch_parse_ctx *ctx)
+static int parse_header_path_buf(git_buf *path, git_patch_parse_ctx *ctx, size_t path_len)
{
- int path_len, error = 0;
-
- path_len = header_path_len(ctx);
+ int error;
if ((error = git_buf_put(path, ctx->parse_ctx.line, path_len)) < 0)
goto done;
@@ -81,7 +79,7 @@ done:
static int parse_header_path(char **out, git_patch_parse_ctx *ctx)
{
git_buf path = GIT_BUF_INIT;
- int error = parse_header_path_buf(&path, ctx);
+ int error = parse_header_path_buf(&path, ctx, header_path_len(ctx));
*out = git_buf_detach(&path);
@@ -91,13 +89,33 @@ static int parse_header_path(char **out, git_patch_parse_ctx *ctx)
static int parse_header_git_oldpath(
git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{
- return parse_header_path(&patch->old_path, ctx);
+ git_buf old_path = GIT_BUF_INIT;
+ int error;
+
+ if ((error = parse_header_path_buf(&old_path, ctx, ctx->parse_ctx.line_len - 1)) < 0)
+ goto out;
+
+ patch->old_path = git_buf_detach(&old_path);
+
+out:
+ git_buf_free(&old_path);
+ return error;
}
static int parse_header_git_newpath(
git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{
- return parse_header_path(&patch->new_path, ctx);
+ git_buf new_path = GIT_BUF_INIT;
+ int error;
+
+ if ((error = parse_header_path_buf(&new_path, ctx, ctx->parse_ctx.line_len - 1)) < 0)
+ goto out;
+
+ patch->new_path = git_buf_detach(&new_path);
+
+out:
+ git_buf_free(&new_path);
+ return error;
}
static int parse_header_mode(uint16_t *mode, git_patch_parse_ctx *ctx)
@@ -213,7 +231,7 @@ static int parse_header_rename(
{
git_buf path = GIT_BUF_INIT;
- if (parse_header_path_buf(&path, ctx) < 0)
+ if (parse_header_path_buf(&path, ctx, header_path_len(ctx)) < 0)
return -1;
/* Note: the `rename from` and `rename to` lines include the literal
@@ -303,6 +321,22 @@ static int parse_header_start(git_patch_parsed *patch, git_patch_parse_ctx *ctx)
return git_parse_err("corrupt new path in git diff header at line %"PRIuZ,
ctx->parse_ctx.line_num);
+ /*
+ * We cannot expect to be able to always parse paths correctly at this
+ * point. Due to the possibility of unquoted names, whitespaces in
+ * filenames and custom prefixes we have to allow that, though, and just
+ * proceeed here. We then hope for the "---" and "+++" lines to fix that
+ * for us.
+ */
+ if (!git_parse_ctx_contains(&ctx->parse_ctx, "\n", 1)) {
+ git_parse_advance_chars(&ctx->parse_ctx, ctx->parse_ctx.line_len - 1);
+
+ git__free(patch->header_old_path);
+ patch->header_old_path = NULL;
+ git__free(patch->header_new_path);
+ patch->header_new_path = NULL;
+ }
+
return 0;
}
diff --git a/src/push.c b/src/push.c
index 41b66df06..85b683e62 100644
--- a/src/push.c
+++ b/src/push.c
@@ -263,12 +263,11 @@ static int enqueue_tag(git_object **out, git_push *push, git_oid *id)
return error;
}
-static int revwalk(git_vector *commits, git_push *push)
+static int queue_objects(git_push *push)
{
git_remote_head *head;
push_spec *spec;
git_revwalk *rw;
- git_oid oid;
unsigned int i;
int error = -1;
@@ -353,176 +352,10 @@ static int revwalk(git_vector *commits, git_push *push)
git_revwalk_hide(rw, &head->oid);
}
- while ((error = git_revwalk_next(&oid, rw)) == 0) {
- git_oid *o = git__malloc(GIT_OID_RAWSZ);
- if (!o) {
- error = -1;
- goto on_error;
- }
- git_oid_cpy(o, &oid);
- if ((error = git_vector_insert(commits, o)) < 0)
- goto on_error;
- }
+ error = git_packbuilder_insert_walk(push->pb, rw);
on_error:
git_revwalk_free(rw);
- return error == GIT_ITEROVER ? 0 : error;
-}
-
-static int enqueue_object(
- const git_tree_entry *entry,
- git_packbuilder *pb)
-{
- switch (git_tree_entry_type(entry)) {
- case GIT_OBJ_COMMIT:
- return 0;
- case GIT_OBJ_TREE:
- return git_packbuilder_insert_tree(pb, entry->oid);
- default:
- return git_packbuilder_insert(pb, entry->oid, entry->filename);
- }
-}
-
-static int queue_differences(
- git_tree *base,
- git_tree *delta,
- git_packbuilder *pb)
-{
- git_tree *b_child = NULL, *d_child = NULL;
- size_t b_length = git_tree_entrycount(base);
- size_t d_length = git_tree_entrycount(delta);
- size_t i = 0, j = 0;
- int error;
-
- while (i < b_length && j < d_length) {
- const git_tree_entry *b_entry = git_tree_entry_byindex(base, i);
- const git_tree_entry *d_entry = git_tree_entry_byindex(delta, j);
- int cmp = 0;
-
- if (!git_oid__cmp(b_entry->oid, d_entry->oid))
- goto loop;
-
- cmp = strcmp(b_entry->filename, d_entry->filename);
-
- /* If the entries are both trees and they have the same name but are
- * different, then we'll recurse after adding the right-hand entry */
- if (!cmp &&
- git_tree_entry__is_tree(b_entry) &&
- git_tree_entry__is_tree(d_entry)) {
- /* Add the right-hand entry */
- if ((error = git_packbuilder_insert(pb, d_entry->oid,
- d_entry->filename)) < 0)
- goto on_error;
-
- /* Acquire the subtrees and recurse */
- if ((error = git_tree_lookup(&b_child,
- git_tree_owner(base), b_entry->oid)) < 0 ||
- (error = git_tree_lookup(&d_child,
- git_tree_owner(delta), d_entry->oid)) < 0 ||
- (error = queue_differences(b_child, d_child, pb)) < 0)
- goto on_error;
-
- git_tree_free(b_child); b_child = NULL;
- git_tree_free(d_child); d_child = NULL;
- }
- /* If the object is new or different in the right-hand tree,
- * then enumerate it */
- else if (cmp >= 0 &&
- (error = enqueue_object(d_entry, pb)) < 0)
- goto on_error;
-
- loop:
- if (cmp <= 0) i++;
- if (cmp >= 0) j++;
- }
-
- /* Drain the right-hand tree of entries */
- for (; j < d_length; j++)
- if ((error = enqueue_object(git_tree_entry_byindex(delta, j), pb)) < 0)
- goto on_error;
-
- error = 0;
-
-on_error:
- if (b_child)
- git_tree_free(b_child);
-
- if (d_child)
- git_tree_free(d_child);
-
- return error;
-}
-
-static int queue_objects(git_push *push)
-{
- git_vector commits = GIT_VECTOR_INIT;
- git_oid *oid;
- size_t i;
- unsigned j;
- int error;
-
- if ((error = revwalk(&commits, push)) < 0)
- goto on_error;
-
- git_vector_foreach(&commits, i, oid) {
- git_commit *parent = NULL, *commit;
- git_tree *tree = NULL, *ptree = NULL;
- size_t parentcount;
-
- if ((error = git_commit_lookup(&commit, push->repo, oid)) < 0)
- goto on_error;
-
- /* Insert the commit */
- if ((error = git_packbuilder_insert(push->pb, oid, NULL)) < 0)
- goto loop_error;
-
- parentcount = git_commit_parentcount(commit);
-
- if (!parentcount) {
- if ((error = git_packbuilder_insert_tree(push->pb,
- git_commit_tree_id(commit))) < 0)
- goto loop_error;
- } else {
- if ((error = git_tree_lookup(&tree, push->repo,
- git_commit_tree_id(commit))) < 0 ||
- (error = git_packbuilder_insert(push->pb,
- git_commit_tree_id(commit), NULL)) < 0)
- goto loop_error;
-
- /* For each parent, add the items which are different */
- for (j = 0; j < parentcount; j++) {
- if ((error = git_commit_parent(&parent, commit, j)) < 0 ||
- (error = git_commit_tree(&ptree, parent)) < 0 ||
- (error = queue_differences(ptree, tree, push->pb)) < 0)
- goto loop_error;
-
- git_tree_free(ptree); ptree = NULL;
- git_commit_free(parent); parent = NULL;
- }
- }
-
- error = 0;
-
- loop_error:
- if (tree)
- git_tree_free(tree);
-
- if (ptree)
- git_tree_free(ptree);
-
- if (parent)
- git_commit_free(parent);
-
- git_commit_free(commit);
-
- if (error < 0)
- goto on_error;
- }
-
- error = 0;
-
-on_error:
- git_vector_free_deep(&commits);
return error;
}
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index ade734c6a..140879d23 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -2035,6 +2035,7 @@ int git_refdb_backend_fs(
if ((!git_repository__cvar(&t, backend->repo, GIT_CVAR_FSYNCOBJECTFILES) && t) ||
git_repository__fsync_gitdir)
backend->fsync = 1;
+ backend->iterator_flags |= GIT_ITERATOR_DESCEND_SYMLINKS;
backend->parent.exists = &refdb_fs_backend__exists;
backend->parent.lookup = &refdb_fs_backend__lookup;
diff --git a/src/remote.c b/src/remote.c
index 303911760..4d675af82 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -1541,6 +1541,20 @@ cleanup:
return error;
}
+static int truncate_fetch_head(const char *gitdir)
+{
+ git_buf path = GIT_BUF_INIT;
+ int error;
+
+ if ((error = git_buf_joinpath(&path, gitdir, GIT_FETCH_HEAD_FILE)) < 0)
+ return error;
+
+ error = git_futils_truncate(path.ptr, GIT_REFS_FILE_MODE);
+ git_buf_free(&path);
+
+ return error;
+}
+
int git_remote_update_tips(
git_remote *remote,
const git_remote_callbacks *callbacks,
@@ -1571,6 +1585,9 @@ int git_remote_update_tips(
else
tagopt = download_tags;
+ if ((error = truncate_fetch_head(git_repository_path(remote->repo))) < 0)
+ goto out;
+
if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
goto out;
diff --git a/src/streams/openssl.c b/src/streams/openssl.c
index 2b246002f..9d566074c 100644
--- a/src/streams/openssl.c
+++ b/src/streams/openssl.c
@@ -332,7 +332,7 @@ static int check_host_name(const char *name, const char *host)
static int verify_server_cert(SSL *ssl, const char *host)
{
- X509 *cert;
+ X509 *cert = NULL;
X509_NAME *peer_name;
ASN1_STRING *str;
unsigned char *peer_cn = NULL;
@@ -341,7 +341,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
struct in6_addr addr6;
struct in_addr addr4;
void *addr;
- int i = -1,j;
+ int i = -1, j, error = 0;
if (SSL_get_verify_result(ssl) != X509_V_OK) {
giterr_set(GITERR_SSL, "the SSL certificate is invalid");
@@ -362,8 +362,9 @@ static int verify_server_cert(SSL *ssl, const char *host)
cert = SSL_get_peer_certificate(ssl);
if (!cert) {
+ error = -1;
giterr_set(GITERR_SSL, "the server did not provide a certificate");
- return -1;
+ goto cleanup;
}
/* Check the alternative names */
@@ -401,8 +402,9 @@ static int verify_server_cert(SSL *ssl, const char *host)
if (matched == 0)
goto cert_fail_name;
- if (matched == 1)
- return 0;
+ if (matched == 1) {
+ goto cleanup;
+ }
/* If no alternative names are available, check the common name */
peer_name = X509_get_subject_name(cert);
@@ -444,18 +446,21 @@ static int verify_server_cert(SSL *ssl, const char *host)
if (check_host_name((char *)peer_cn, host) < 0)
goto cert_fail_name;
- OPENSSL_free(peer_cn);
+ goto cleanup;
- return 0;
+cert_fail_name:
+ error = GIT_ECERTIFICATE;
+ giterr_set(GITERR_SSL, "hostname does not match certificate");
+ goto cleanup;
on_error:
- OPENSSL_free(peer_cn);
- return ssl_set_error(ssl, 0);
+ error = ssl_set_error(ssl, 0);
+ goto cleanup;
-cert_fail_name:
+cleanup:
+ X509_free(cert);
OPENSSL_free(peer_cn);
- giterr_set(GITERR_SSL, "hostname does not match certificate");
- return GIT_ECERTIFICATE;
+ return error;
}
typedef struct {
diff --git a/src/streams/stransport.c b/src/streams/stransport.c
index 64a5dd76f..cca17bb94 100644
--- a/src/streams/stransport.c
+++ b/src/streams/stransport.c
@@ -83,8 +83,10 @@ static int stransport_connect(git_stream *stream)
}
if (sec_res == kSecTrustResultDeny || sec_res == kSecTrustResultRecoverableTrustFailure ||
- sec_res == kSecTrustResultFatalTrustFailure)
+ sec_res == kSecTrustResultFatalTrustFailure) {
+ giterr_set(GITERR_SSL, "untrusted connection error");
return GIT_ECERTIFICATE;
+ }
return 0;
diff --git a/src/transports/local.c b/src/transports/local.c
index 733ed2c20..ae117db29 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -507,6 +507,21 @@ static int local_counting(int stage, unsigned int current, unsigned int total, v
return error;
}
+static int foreach_reference_cb(git_reference *reference, void *payload)
+{
+ git_revwalk *walk = (git_revwalk *)payload;
+
+ int error = git_revwalk_hide(walk, git_reference_target(reference));
+ /* The reference is in the local repository, so the target may not
+ * exist on the remote. It also may not be a commit. */
+ if (error == GIT_ENOTFOUND || error == GITERR_INVALID) {
+ giterr_clear();
+ error = 0;
+ }
+
+ return error;
+}
+
static int local_download_pack(
git_transport *transport,
git_repository *repo,
@@ -546,11 +561,6 @@ static int local_download_pack(
if (git_object_type(obj) == GIT_OBJ_COMMIT) {
/* Revwalker includes only wanted commits */
error = git_revwalk_push(walk, &rhead->oid);
- if (!error && !git_oid_iszero(&rhead->loid)) {
- error = git_revwalk_hide(walk, &rhead->loid);
- if (error == GIT_ENOTFOUND)
- error = 0;
- }
} else {
/* Tag or some other wanted object. Add it on its own */
error = git_packbuilder_insert_recur(pack, &rhead->oid, rhead->name);
@@ -560,6 +570,9 @@ static int local_download_pack(
goto cleanup;
}
+ if ((error = git_reference_foreach(repo, foreach_reference_cb, walk)))
+ goto cleanup;
+
if ((error = git_packbuilder_insert_walk(pack, walk)))
goto cleanup;
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index 98905ab61..6dad1d38a 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -172,9 +172,15 @@ static int apply_default_credentials(HINTERNET request, int mechanisms)
* is "medium" which applies to the intranet and sounds like it would correspond
* to Internet Explorer security zones, but in fact does not. */
DWORD data = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
+ DWORD native_scheme = 0;
- if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) == 0 &&
- (mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE) == 0) {
+ if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) != 0)
+ native_scheme |= WINHTTP_AUTH_SCHEME_NTLM;
+
+ if ((mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE) != 0)
+ native_scheme |= WINHTTP_AUTH_SCHEME_NEGOTIATE;
+
+ if (!native_scheme) {
giterr_set(GITERR_NET, "invalid authentication scheme");
return -1;
}
@@ -182,6 +188,9 @@ static int apply_default_credentials(HINTERNET request, int mechanisms)
if (!WinHttpSetOption(request, WINHTTP_OPTION_AUTOLOGON_POLICY, &data, sizeof(DWORD)))
return -1;
+ if (!WinHttpSetCredentials(request, WINHTTP_AUTH_TARGET_SERVER, native_scheme, NULL, NULL, NULL))
+ return -1;
+
return 0;
}
@@ -606,12 +615,12 @@ static int parse_unauthorized_response(
if (WINHTTP_AUTH_SCHEME_NTLM & supported) {
*allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
*allowed_types |= GIT_CREDTYPE_DEFAULT;
- *allowed_mechanisms = GIT_WINHTTP_AUTH_NEGOTIATE;
+ *allowed_mechanisms |= GIT_WINHTTP_AUTH_NTLM;
}
if (WINHTTP_AUTH_SCHEME_NEGOTIATE & supported) {
*allowed_types |= GIT_CREDTYPE_DEFAULT;
- *allowed_mechanisms = GIT_WINHTTP_AUTH_NEGOTIATE;
+ *allowed_mechanisms |= GIT_WINHTTP_AUTH_NEGOTIATE;
}
if (WINHTTP_AUTH_SCHEME_BASIC & supported) {
diff --git a/src/util.c b/src/util.c
index 6ae5cdaec..1760a315e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -252,35 +252,47 @@ void git__strtolower(char *str)
git__strntolower(str, strlen(str));
}
-int git__prefixcmp(const char *str, const char *prefix)
+GIT_INLINE(int) prefixcmp(const char *str, size_t str_n, const char *prefix, bool icase)
{
- for (;;) {
- unsigned char p = *(prefix++), s;
+ int s, p;
+
+ while (str_n--) {
+ s = (unsigned char)*str++;
+ p = (unsigned char)*prefix++;
+
+ if (icase) {
+ s = git__tolower(s);
+ p = git__tolower(p);
+ }
+
if (!p)
return 0;
- if ((s = *(str++)) != p)
+
+ if (s != p)
return s - p;
}
+
+ return (0 - *prefix);
}
-int git__prefixcmp_icase(const char *str, const char *prefix)
+int git__prefixcmp(const char *str, const char *prefix)
{
- return strncasecmp(str, prefix, strlen(prefix));
+ return prefixcmp(str, SIZE_MAX, prefix, false);
}
-int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
+int git__prefixncmp(const char *str, size_t str_n, const char *prefix)
{
- int s, p;
-
- while(str_n--) {
- s = (unsigned char)git__tolower(*str++);
- p = (unsigned char)git__tolower(*prefix++);
+ return prefixcmp(str, str_n, prefix, false);
+}
- if (s != p)
- return s - p;
- }
+int git__prefixcmp_icase(const char *str, const char *prefix)
+{
+ return prefixcmp(str, SIZE_MAX, prefix, true);
+}
- return (0 - *prefix);
+int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
+{
+ return prefixcmp(str, str_n, prefix, true);
}
int git__suffixcmp(const char *str, const char *suffix)
diff --git a/src/util.h b/src/util.h
index 7c9a54ff1..80ee8e647 100644
--- a/src/util.h
+++ b/src/util.h
@@ -180,6 +180,7 @@ GIT_INLINE(void) git__free(void *ptr)
extern int git__prefixcmp(const char *str, const char *prefix);
extern int git__prefixcmp_icase(const char *str, const char *prefix);
+extern int git__prefixncmp(const char *str, size_t str_n, const char *prefix);
extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix);
extern int git__suffixcmp(const char *str, const char *suffix);
diff --git a/src/zstream.c b/src/zstream.c
index 4895bdb16..963c9a344 100644
--- a/src/zstream.c
+++ b/src/zstream.c
@@ -14,17 +14,22 @@
#define ZSTREAM_BUFFER_SIZE (1024 * 1024)
#define ZSTREAM_BUFFER_MIN_EXTRA 8
-static int zstream_seterr(git_zstream *zs)
+GIT_INLINE(int) zstream_seterr(git_zstream *zs)
{
- if (zs->zerr == Z_OK || zs->zerr == Z_STREAM_END)
+ switch (zs->zerr) {
+ case Z_OK:
+ case Z_STREAM_END:
+ case Z_BUF_ERROR: /* not fatal; we retry with a larger buffer */
return 0;
-
- if (zs->zerr == Z_MEM_ERROR)
+ case Z_MEM_ERROR:
giterr_set_oom();
- else if (zs->z.msg)
- giterr_set_str(GITERR_ZLIB, zs->z.msg);
- else
- giterr_set(GITERR_ZLIB, "unknown compression error");
+ break;
+ default:
+ if (zs->z.msg)
+ giterr_set_str(GITERR_ZLIB, zs->z.msg);
+ else
+ giterr_set(GITERR_ZLIB, "unknown compression error");
+ }
return -1;
}
@@ -98,8 +103,9 @@ int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
/* set up in data */
zstream->z.next_in = (Bytef *)zstream->in;
zstream->z.avail_in = (uInt)zstream->in_len;
+
if ((size_t)zstream->z.avail_in != zstream->in_len) {
- zstream->z.avail_in = INT_MAX;
+ zstream->z.avail_in = UINT_MAX;
zflush = Z_NO_FLUSH;
} else {
zflush = Z_FINISH;
@@ -110,7 +116,7 @@ int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
zstream->z.next_out = out;
zstream->z.avail_out = (uInt)out_remain;
if ((size_t)zstream->z.avail_out != out_remain)
- zstream->z.avail_out = INT_MAX;
+ zstream->z.avail_out = UINT_MAX;
out_queued = (size_t)zstream->z.avail_out;
/* compress next chunk */
@@ -119,8 +125,8 @@ int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream)
else
zstream->zerr = deflate(&zstream->z, zflush);
- if (zstream->zerr == Z_STREAM_ERROR)
- return zstream_seterr(zstream);
+ if (zstream_seterr(zstream))
+ return -1;
out_used = (out_queued - zstream->z.avail_out);
out_remain -= out_used;
diff --git a/tests/core/string.c b/tests/core/string.c
index 90e8fa027..85db0c662 100644
--- a/tests/core/string.c
+++ b/tests/core/string.c
@@ -40,6 +40,48 @@ void test_core_string__2(void)
cl_assert(git__strcasesort_cmp("fooBar", "foobar") < 0);
}
+/* compare prefixes with len */
+void test_core_string__prefixncmp(void)
+{
+ cl_assert(git__prefixncmp("", 0, "") == 0);
+ cl_assert(git__prefixncmp("a", 1, "") == 0);
+ cl_assert(git__prefixncmp("", 0, "a") < 0);
+ cl_assert(git__prefixncmp("a", 1, "b") < 0);
+ cl_assert(git__prefixncmp("b", 1, "a") > 0);
+ cl_assert(git__prefixncmp("ab", 2, "a") == 0);
+ cl_assert(git__prefixncmp("ab", 1, "a") == 0);
+ cl_assert(git__prefixncmp("ab", 2, "ac") < 0);
+ cl_assert(git__prefixncmp("a", 1, "ac") < 0);
+ cl_assert(git__prefixncmp("ab", 1, "ac") < 0);
+ cl_assert(git__prefixncmp("ab", 2, "aa") > 0);
+ cl_assert(git__prefixncmp("ab", 1, "aa") < 0);
+}
+
+/* compare prefixes with len */
+void test_core_string__prefixncmp_icase(void)
+{
+ cl_assert(git__prefixncmp_icase("", 0, "") == 0);
+ cl_assert(git__prefixncmp_icase("a", 1, "") == 0);
+ cl_assert(git__prefixncmp_icase("", 0, "a") < 0);
+ cl_assert(git__prefixncmp_icase("a", 1, "b") < 0);
+ cl_assert(git__prefixncmp_icase("A", 1, "b") < 0);
+ cl_assert(git__prefixncmp_icase("a", 1, "B") < 0);
+ cl_assert(git__prefixncmp_icase("b", 1, "a") > 0);
+ cl_assert(git__prefixncmp_icase("B", 1, "a") > 0);
+ cl_assert(git__prefixncmp_icase("b", 1, "A") > 0);
+ cl_assert(git__prefixncmp_icase("ab", 2, "a") == 0);
+ cl_assert(git__prefixncmp_icase("Ab", 2, "a") == 0);
+ cl_assert(git__prefixncmp_icase("ab", 2, "A") == 0);
+ cl_assert(git__prefixncmp_icase("ab", 1, "a") == 0);
+ cl_assert(git__prefixncmp_icase("ab", 2, "ac") < 0);
+ cl_assert(git__prefixncmp_icase("Ab", 2, "ac") < 0);
+ cl_assert(git__prefixncmp_icase("ab", 2, "Ac") < 0);
+ cl_assert(git__prefixncmp_icase("a", 1, "ac") < 0);
+ cl_assert(git__prefixncmp_icase("ab", 1, "ac") < 0);
+ cl_assert(git__prefixncmp_icase("ab", 2, "aa") > 0);
+ cl_assert(git__prefixncmp_icase("ab", 1, "aa") < 0);
+}
+
void test_core_string__strcmp(void)
{
cl_assert(git__strcmp("", "") == 0);
diff --git a/tests/diff/blob.c b/tests/diff/blob.c
index c3933c313..05cc28218 100644
--- a/tests/diff/blob.c
+++ b/tests/diff/blob.c
@@ -1,6 +1,19 @@
#include "clar_libgit2.h"
#include "diff_helpers.h"
+#define BLOB_DIFF \
+ "diff --git a/file b/file\n" \
+ "index 45141a7..4d713dc 100644\n" \
+ "--- a/file\n" \
+ "+++ b/file\n" \
+ "@@ -1 +1,6 @@\n" \
+ " Hello from the root\n" \
+ "+\n" \
+ "+Some additional lines\n" \
+ "+\n" \
+ "+Down here below\n" \
+ "+\n"
+
static git_repository *g_repo = NULL;
static diff_expects expected;
static git_diff_options opts;
@@ -65,6 +78,32 @@ static void assert_one_modified(
cl_assert_equal_i(dels, exp->line_dels);
}
+void test_diff_blob__patch_with_freed_blobs(void)
+{
+ git_oid a_oid, b_oid;
+ git_blob *a, *b;
+ git_patch *p;
+ git_buf buf = GIT_BUF_INIT;
+
+ /* tests/resources/attr/root_test1 */
+ cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
+ cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));
+ /* tests/resources/attr/root_test2 */
+ cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
+ cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4));
+
+ cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, NULL));
+
+ git_blob_free(a);
+ git_blob_free(b);
+
+ cl_git_pass(git_patch_to_buf(&buf, p));
+ cl_assert_equal_s(buf.ptr, BLOB_DIFF);
+
+ git_patch_free(p);
+ git_buf_free(&buf);
+}
+
void test_diff_blob__can_compare_text_blobs(void)
{
git_blob *a, *b, *c;
diff --git a/tests/fetchhead/nonetwork.c b/tests/fetchhead/nonetwork.c
index ea4b70e4a..4dabb577e 100644
--- a/tests/fetchhead/nonetwork.c
+++ b/tests/fetchhead/nonetwork.c
@@ -353,20 +353,25 @@ void test_fetchhead_nonetwork__quote_in_branch_name(void)
}
static bool found_master;
-static bool find_master_called;
+static bool found_haacked;
+static bool find_master_haacked_called;
-int find_master(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload)
+int find_master_haacked(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload)
{
GIT_UNUSED(remote_url);
GIT_UNUSED(oid);
GIT_UNUSED(payload);
- find_master_called = true;
+ find_master_haacked_called = true;
if (!strcmp("refs/heads/master", ref_name)) {
cl_assert(is_merge);
found_master = true;
}
+ if (!strcmp("refs/heads/haacked", ref_name)) {
+ cl_assert(is_merge);
+ found_haacked = true;
+ }
return 0;
}
@@ -375,10 +380,12 @@ void test_fetchhead_nonetwork__create_when_refpecs_given(void)
{
git_remote *remote;
git_buf path = GIT_BUF_INIT;
- char *refspec = "refs/heads/master";
+ char *refspec1 = "refs/heads/master";
+ char *refspec2 = "refs/heads/haacked";
+ char *refspecs[] = { refspec1, refspec2 };
git_strarray specs = {
- &refspec,
- 1,
+ refspecs,
+ 2,
};
cl_set_cleanup(&cleanup_repository, "./test1");
@@ -391,9 +398,74 @@ void test_fetchhead_nonetwork__create_when_refpecs_given(void)
cl_git_pass(git_remote_fetch(remote, &specs, NULL, NULL));
cl_assert(git_path_exists(path.ptr));
- cl_git_pass(git_repository_fetchhead_foreach(g_repo, find_master, NULL));
- cl_assert(find_master_called);
+ cl_git_pass(git_repository_fetchhead_foreach(g_repo, find_master_haacked, NULL));
+ cl_assert(find_master_haacked_called);
cl_assert(found_master);
+ cl_assert(found_haacked);
+
+ git_remote_free(remote);
+ git_buf_free(&path);
+}
+
+static bool count_refs_called;
+struct prefix_count {
+ const char *prefix;
+ int count;
+ int expected;
+};
+
+int count_refs(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload)
+{
+ int i;
+ struct prefix_count *prefix_counts = (struct prefix_count *) payload;
+
+ GIT_UNUSED(remote_url);
+ GIT_UNUSED(oid);
+ GIT_UNUSED(is_merge);
+
+ count_refs_called = true;
+
+ for (i = 0; prefix_counts[i].prefix; i++) {
+ if (!git__prefixcmp(ref_name, prefix_counts[i].prefix))
+ prefix_counts[i].count++;
+ }
+
+ return 0;
+}
+
+void test_fetchhead_nonetwork__create_with_multiple_refspecs(void)
+{
+ git_remote *remote;
+ git_buf path = GIT_BUF_INIT;
+
+ cl_set_cleanup(&cleanup_repository, "./test1");
+ cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
+
+ cl_git_pass(git_remote_create(&remote, g_repo, "origin", cl_fixture("testrepo.git")));
+ git_remote_free(remote);
+ cl_git_pass(git_remote_add_fetch(g_repo, "origin", "+refs/notes/*:refs/origin/notes/*"));
+ /* Pick up the new refspec */
+ cl_git_pass(git_remote_lookup(&remote, g_repo, "origin"));
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), "FETCH_HEAD"));
+ cl_assert(!git_path_exists(path.ptr));
+ cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL));
+ cl_assert(git_path_exists(path.ptr));
+
+ {
+ int i;
+ struct prefix_count prefix_counts[] = {
+ {"refs/notes/", 0, 1},
+ {"refs/heads/", 0, 12},
+ {"refs/tags/", 0, 7},
+ {NULL, 0, 0},
+ };
+
+ cl_git_pass(git_repository_fetchhead_foreach(g_repo, count_refs, &prefix_counts));
+ cl_assert(count_refs_called);
+ for (i = 0; prefix_counts[i].prefix; i++)
+ cl_assert_equal_i(prefix_counts[i].expected, prefix_counts[i].count);
+ }
git_remote_free(remote);
git_buf_free(&path);
diff --git a/tests/merge/workdir/submodules.c b/tests/merge/workdir/submodules.c
index 7c18c2ffb..c4cc188a8 100644
--- a/tests/merge/workdir/submodules.c
+++ b/tests/merge/workdir/submodules.c
@@ -12,6 +12,7 @@ static git_repository *repo;
#define SUBMODULE_MAIN_BRANCH "submodules"
#define SUBMODULE_OTHER_BRANCH "submodules-branch"
#define SUBMODULE_OTHER2_BRANCH "submodules-branch2"
+#define SUBMODULE_DELETE_BRANCH "delete-submodule"
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
@@ -93,3 +94,38 @@ void test_merge_workdir_submodules__take_changed(void)
git_reference_free(their_ref);
git_reference_free(our_ref);
}
+
+
+void test_merge_workdir_submodules__update_delete_conflict(void)
+{
+ git_reference *our_ref, *their_ref;
+ git_commit *our_commit;
+ git_annotated_commit *their_head;
+ git_index *index;
+
+ struct merge_index_entry merge_index_entries[] = {
+ { 0100644, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", 0, ".gitmodules" },
+ { 0100644, "5887a5e516c53bd58efb0f02ec6aa031b6fe9ad7", 0, "file1.txt" },
+ { 0100644, "4218670ab81cc219a9f94befb5c5dad90ec52648", 0, "file2.txt" },
+ { 0160000, "d3d806a4bef96889117fd7ebac0e3cb5ec152932", 1, "submodule"},
+ { 0160000, "297aa6cd028b3336c7802c7a6f49143da4e1602d", 3, "submodule" },
+ };
+
+ cl_git_pass(git_reference_lookup(&our_ref, repo, "refs/heads/" SUBMODULE_DELETE_BRANCH));
+ cl_git_pass(git_commit_lookup(&our_commit, repo, git_reference_target(our_ref)));
+ cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL));
+
+ cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_MAIN_BRANCH));
+ cl_git_pass(git_annotated_commit_from_ref(&their_head, repo, their_ref));
+
+ cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_head, 1, NULL, NULL));
+
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_assert(merge_test_index(index, merge_index_entries, 5));
+
+ git_index_free(index);
+ git_annotated_commit_free(their_head);
+ git_commit_free(our_commit);
+ git_reference_free(their_ref);
+ git_reference_free(our_ref);
+}
diff --git a/tests/notes/notes.c b/tests/notes/notes.c
index a91bf5bdf..9626f53b3 100644
--- a/tests/notes/notes.c
+++ b/tests/notes/notes.c
@@ -73,6 +73,128 @@ static int note_list_cb(
return 0;
}
+struct note_create_payload {
+ const char *note_oid;
+ const char *object_oid;
+ unsigned seen;
+};
+
+static int note_list_create_cb(
+ const git_oid *blob_oid, const git_oid *annotated_obj_id, void *payload)
+{
+ git_oid expected_note_oid, expected_target_oid;
+ struct note_create_payload *notes = payload;
+ size_t i;
+
+ for (i = 0; notes[i].note_oid != NULL; i++) {
+ cl_git_pass(git_oid_fromstr(&expected_note_oid, notes[i].note_oid));
+
+ if (git_oid_cmp(&expected_note_oid, blob_oid) != 0)
+ continue;
+
+ cl_git_pass(git_oid_fromstr(&expected_target_oid, notes[i].object_oid));
+
+ if (git_oid_cmp(&expected_target_oid, annotated_obj_id) != 0)
+ continue;
+
+ notes[i].seen = 1;
+ return 0;
+ }
+
+ cl_fail("Did not see expected note");
+ return 0;
+}
+
+void assert_notes_seen(struct note_create_payload payload[], size_t n)
+{
+ size_t seen = 0, i;
+
+ for (i = 0; payload[i].note_oid != NULL; i++) {
+ if (payload[i].seen)
+ seen++;
+ }
+
+ cl_assert_equal_i(seen, n);
+}
+
+void test_notes_notes__can_create_a_note(void)
+{
+ git_oid note_oid;
+ static struct note_create_payload can_create_a_note[] = {
+ { "1c9b1bc36730582a42d56eeee0dc58673d7ae869", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", 0 },
+ { NULL, NULL, 0 }
+ };
+
+ create_note(&note_oid, "refs/notes/i-can-see-dead-notes", can_create_a_note[0].object_oid, "I decorate 4a20\n");
+
+ cl_git_pass(git_note_foreach(_repo, "refs/notes/i-can-see-dead-notes", note_list_create_cb, &can_create_a_note));
+
+ assert_notes_seen(can_create_a_note, 1);
+}
+
+void test_notes_notes__can_create_a_note_from_commit(void)
+{
+ git_oid oid;
+ git_oid notes_commit_out;
+ git_reference *ref;
+ static struct note_create_payload can_create_a_note_from_commit[] = {
+ { "1c9b1bc36730582a42d56eeee0dc58673d7ae869", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", 0 },
+ { NULL, NULL, 0 }
+ };
+
+ cl_git_pass(git_oid_fromstr(&oid, can_create_a_note_from_commit[0].object_oid));
+
+ cl_git_pass(git_note_commit_create(&notes_commit_out, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 1));
+
+ /* create_from_commit will not update any ref,
+ * so we must manually create the ref, that points to the commit */
+ cl_git_pass(git_reference_create(&ref, _repo, "refs/notes/i-can-see-dead-notes", &notes_commit_out, 0, NULL));
+
+ cl_git_pass(git_note_foreach(_repo, "refs/notes/i-can-see-dead-notes", note_list_create_cb, &can_create_a_note_from_commit));
+
+ assert_notes_seen(can_create_a_note_from_commit, 1);
+
+ git_reference_free(ref);
+}
+
+
+/* Test that we can create a note from a commit, given an existing commit */
+void test_notes_notes__can_create_a_note_from_commit_given_an_existing_commit(void)
+{
+ git_oid oid;
+ git_oid notes_commit_out;
+ git_commit *existing_notes_commit = NULL;
+ git_reference *ref;
+ static struct note_create_payload can_create_a_note_from_commit_given_an_existing_commit[] = {
+ { "1c9b1bc36730582a42d56eeee0dc58673d7ae869", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", 0 },
+ { "1aaf94147c21f981e0a20bf57b89137c5a6aae52", "9fd738e8f7967c078dceed8190330fc8648ee56a", 0 },
+ { NULL, NULL, 0 }
+ };
+
+ cl_git_pass(git_oid_fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"));
+
+ cl_git_pass(git_note_commit_create(&notes_commit_out, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 0));
+
+ cl_git_pass(git_oid_fromstr(&oid, "9fd738e8f7967c078dceed8190330fc8648ee56a"));
+
+ git_commit_lookup(&existing_notes_commit, _repo, &notes_commit_out);
+
+ cl_assert(existing_notes_commit);
+
+ cl_git_pass(git_note_commit_create(&notes_commit_out, NULL, _repo, existing_notes_commit, _sig, _sig, &oid, "I decorate 9fd7\n", 0));
+
+ /* create_from_commit will not update any ref,
+ * so we must manually create the ref, that points to the commit */
+ cl_git_pass(git_reference_create(&ref, _repo, "refs/notes/i-can-see-dead-notes", &notes_commit_out, 0, NULL));
+
+ cl_git_pass(git_note_foreach(_repo, "refs/notes/i-can-see-dead-notes", note_list_create_cb, &can_create_a_note_from_commit_given_an_existing_commit));
+
+ assert_notes_seen(can_create_a_note_from_commit_given_an_existing_commit, 2);
+
+ git_commit_free(existing_notes_commit);
+ git_reference_free(ref);
+}
+
/*
* $ git notes --ref i-can-see-dead-notes add -m "I decorate a65f" a65fedf39aefe402d3bb6e24df4d4f5fe4547750
* $ git notes --ref i-can-see-dead-notes add -m "I decorate c478" c47800c7266a2be04c571c04d5a6614691ea99bd
@@ -253,6 +375,71 @@ static char *messages[] = {
#define MESSAGES_COUNT (sizeof(messages)/sizeof(messages[0])) - 1
+/* Test that we can read a note */
+void test_notes_notes__can_read_a_note(void)
+{
+ git_oid note_oid, target_oid;
+ git_note *note;
+
+ create_note(&note_oid, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 4a20\n");
+
+ cl_git_pass(git_oid_fromstr(&target_oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"));
+
+ cl_git_pass(git_note_read(&note, _repo, "refs/notes/i-can-see-dead-notes", &target_oid));
+
+ cl_assert_equal_s(git_note_message(note), "I decorate 4a20\n");
+
+ git_note_free(note);
+}
+
+/* Test that we can read a note with from commit api */
+void test_notes_notes__can_read_a_note_from_a_commit(void)
+{
+ git_oid oid, notes_commit_oid;
+ git_commit *notes_commit;
+ git_note *note;
+
+ cl_git_pass(git_oid_fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"));
+
+ cl_git_pass(git_note_commit_create(&notes_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 1));
+
+ git_commit_lookup(&notes_commit, _repo, &notes_commit_oid);
+
+ cl_assert(notes_commit);
+
+ cl_git_pass(git_note_commit_read(&note, _repo, notes_commit, &oid));
+
+ cl_assert_equal_s(git_note_message(note), "I decorate 4a20\n");
+
+ git_commit_free(notes_commit);
+ git_note_free(note);
+}
+
+/* Test that we can read a commit with no note fails */
+void test_notes_notes__attempt_to_read_a_note_from_a_commit_with_no_note_fails(void)
+{
+ git_oid oid, notes_commit_oid;
+ git_commit *notes_commit;
+ git_note *note;
+
+ cl_git_pass(git_oid_fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"));
+
+ cl_git_pass(git_note_commit_create(&notes_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 1));
+
+ git_commit_lookup(&notes_commit, _repo, &notes_commit_oid);
+
+ cl_git_pass(git_note_commit_remove(&notes_commit_oid, _repo, notes_commit, _sig, _sig, &oid));
+ git_commit_free(notes_commit);
+
+ git_commit_lookup(&notes_commit, _repo, &notes_commit_oid);
+
+ cl_assert(notes_commit);
+
+ cl_git_fail_with(GIT_ENOTFOUND, git_note_commit_read(&note, _repo, notes_commit, &oid));
+
+ git_commit_free(notes_commit);
+}
+
/*
* $ git ls-tree refs/notes/fanout
* 040000 tree 4b22b35d44b5a4f589edf3dc89196399771796ea 84
@@ -298,6 +485,50 @@ void test_notes_notes__can_read_a_note_in_an_existing_fanout(void)
git_note_free(note);
}
+/* Can remove a note */
+void test_notes_notes__can_remove_a_note(void)
+{
+ git_oid note_oid, target_oid;
+ git_note *note;
+
+ create_note(&note_oid, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 4a20\n");
+
+ cl_git_pass(git_oid_fromstr(&target_oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"));
+ cl_git_pass(git_note_remove(_repo, "refs/notes/i-can-see-dead-notes", _sig, _sig, &target_oid));
+
+ cl_git_fail(git_note_read(&note, _repo, "refs/notes/i-can-see-dead-notes", &target_oid));
+}
+
+/* Can remove a note from a commit */
+void test_notes_notes__can_remove_a_note_from_commit(void)
+{
+ git_oid oid, notes_commit_oid;
+ git_note *note = NULL;
+ git_commit *existing_notes_commit;
+ git_reference *ref;
+
+ cl_git_pass(git_oid_fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"));
+
+ cl_git_pass(git_note_commit_create(&notes_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 0));
+
+ git_commit_lookup(&existing_notes_commit, _repo, &notes_commit_oid);
+
+ cl_assert(existing_notes_commit);
+
+ cl_git_pass(git_note_commit_remove(&notes_commit_oid, _repo, existing_notes_commit, _sig, _sig, &oid));
+
+ /* remove_from_commit will not update any ref,
+ * so we must manually create the ref, that points to the commit */
+ cl_git_pass(git_reference_create(&ref, _repo, "refs/notes/i-can-see-dead-notes", &notes_commit_oid, 0, NULL));
+
+ cl_git_fail(git_note_read(&note, _repo, "refs/notes/i-can-see-dead-notes", &oid));
+
+ git_commit_free(existing_notes_commit);
+ git_reference_free(ref);
+ git_note_free(note);
+}
+
+
void test_notes_notes__can_remove_a_note_in_an_existing_fanout(void)
{
git_oid target_oid;
@@ -388,3 +619,46 @@ void test_notes_notes__empty_iterate(void)
cl_git_fail(git_note_iterator_new(&iter, _repo, "refs/notes/commits"));
}
+
+void test_notes_notes__iterate_from_commit(void)
+{
+ git_note_iterator *iter;
+ git_note *note;
+ git_oid note_id, annotated_id;
+ git_oid oids[2];
+ git_oid notes_commit_oids[2];
+ git_commit *notes_commits[2];
+ const char* note_message[] = {
+ "I decorate a65f\n",
+ "I decorate c478\n"
+ };
+ int i, err;
+
+ cl_git_pass(git_oid_fromstr(&(oids[0]), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
+ cl_git_pass(git_oid_fromstr(&(oids[1]), "c47800c7266a2be04c571c04d5a6614691ea99bd"));
+
+ cl_git_pass(git_note_commit_create(&notes_commit_oids[0], NULL, _repo, NULL, _sig, _sig, &(oids[0]), note_message[0], 0));
+
+ git_commit_lookup(&notes_commits[0], _repo, &notes_commit_oids[0]);
+ cl_assert(notes_commits[0]);
+
+ cl_git_pass(git_note_commit_create(&notes_commit_oids[1], NULL, _repo, notes_commits[0], _sig, _sig, &(oids[1]), note_message[1], 0));
+
+ git_commit_lookup(&notes_commits[1], _repo, &notes_commit_oids[1]);
+ cl_assert(notes_commits[1]);
+
+ cl_git_pass(git_note_commit_iterator_new(&iter, notes_commits[1]));
+
+ for (i = 0; (err = git_note_next(&note_id, &annotated_id, iter)) >= 0; ++i) {
+ cl_git_pass(git_note_commit_read(&note, _repo, notes_commits[1], &annotated_id));
+ cl_assert_equal_s(git_note_message(note), note_message[i]);
+ git_note_free(note);
+ }
+
+ cl_assert_equal_i(GIT_ITEROVER, err);
+ cl_assert_equal_i(2, i);
+
+ git_note_iterator_free(iter);
+ git_commit_free(notes_commits[0]);
+ git_commit_free(notes_commits[1]);
+}
diff --git a/tests/odb/largefiles.c b/tests/odb/largefiles.c
new file mode 100644
index 000000000..22f136df5
--- /dev/null
+++ b/tests/odb/largefiles.c
@@ -0,0 +1,114 @@
+#include "clar_libgit2.h"
+#include "git2/odb_backend.h"
+
+static git_repository *repo;
+static git_odb *odb;
+
+void test_odb_largefiles__initialize(void)
+{
+ repo = cl_git_sandbox_init("testrepo.git");
+ cl_git_pass(git_repository_odb(&odb, repo));
+}
+
+void test_odb_largefiles__cleanup(void)
+{
+ git_odb_free(odb);
+ cl_git_sandbox_cleanup();
+}
+
+static void writefile(git_oid *oid)
+{
+ static git_odb_stream *stream;
+ git_buf buf = GIT_BUF_INIT;
+ size_t i;
+
+ for (i = 0; i < 3041; i++)
+ cl_git_pass(git_buf_puts(&buf, "Hello, world.\n"));
+
+ cl_git_pass(git_odb_open_wstream(&stream, odb, 5368709122, GIT_OBJ_BLOB));
+ for (i = 0; i < 126103; i++)
+ cl_git_pass(git_odb_stream_write(stream, buf.ptr, buf.size));
+
+ cl_git_pass(git_odb_stream_finalize_write(oid, stream));
+
+ git_odb_stream_free(stream);
+ git_buf_free(&buf);
+}
+
+void test_odb_largefiles__write_from_memory(void)
+{
+ git_oid expected, oid;
+ git_buf buf = GIT_BUF_INIT;
+ size_t i;
+
+#ifndef GIT_ARCH_64
+ cl_skip();
+#endif
+
+ if (!cl_is_env_set("GITTEST_INVASIVE_FS_SIZE") ||
+ !cl_is_env_set("GITTEST_INVASIVE_MEMORY") ||
+ !cl_is_env_set("GITTEST_SLOW"))
+ cl_skip();
+
+ for (i = 0; i < (3041*126103); i++)
+ cl_git_pass(git_buf_puts(&buf, "Hello, world.\n"));
+
+ git_oid_fromstr(&expected, "3fb56989cca483b21ba7cb0a6edb229d10e1c26c");
+ cl_git_pass(git_odb_write(&oid, odb, buf.ptr, buf.size, GIT_OBJ_BLOB));
+
+ cl_assert_equal_oid(&expected, &oid);
+}
+
+void test_odb_largefiles__streamwrite(void)
+{
+ git_oid expected, oid;
+
+ if (!cl_is_env_set("GITTEST_INVASIVE_FS_SIZE") ||
+ !cl_is_env_set("GITTEST_SLOW"))
+ cl_skip();
+
+ git_oid_fromstr(&expected, "3fb56989cca483b21ba7cb0a6edb229d10e1c26c");
+ writefile(&oid);
+
+ cl_assert_equal_oid(&expected, &oid);
+}
+
+void test_odb_largefiles__read_into_memory(void)
+{
+ git_oid oid;
+ git_odb_object *obj;
+
+#ifndef GIT_ARCH_64
+ cl_skip();
+#endif
+
+ if (!cl_is_env_set("GITTEST_INVASIVE_FS_SIZE") ||
+ !cl_is_env_set("GITTEST_INVASIVE_MEMORY") ||
+ !cl_is_env_set("GITTEST_SLOW"))
+ cl_skip();
+
+ writefile(&oid);
+ cl_git_pass(git_odb_read(&obj, odb, &oid));
+
+ git_odb_object_free(obj);
+}
+
+void test_odb_largefiles__read_into_memory_rejected_on_32bit(void)
+{
+ git_oid oid;
+ git_odb_object *obj = NULL;
+
+#ifdef GIT_ARCH_64
+ cl_skip();
+#endif
+
+ if (!cl_is_env_set("GITTEST_INVASIVE_FS_SIZE") ||
+ !cl_is_env_set("GITTEST_INVASIVE_MEMORY") ||
+ !cl_is_env_set("GITTEST_SLOW"))
+ cl_skip();
+
+ writefile(&oid);
+ cl_git_fail(git_odb_read(&obj, odb, &oid));
+
+ git_odb_object_free(obj);
+}
diff --git a/tests/pack/indexer.c b/tests/pack/indexer.c
index a28ee3e07..f3c2204bd 100644
--- a/tests/pack/indexer.c
+++ b/tests/pack/indexer.c
@@ -41,6 +41,29 @@ static const unsigned char thin_pack[] = {
static const unsigned int thin_pack_len = 78;
/*
+ * Packfile with one object. It references an object which is not in the
+ * packfile and has a corrupt length (states the deltified stream is 1 byte
+ * long, where it is actually 6).
+ */
+static const unsigned char corrupt_thin_pack[] = {
+ 0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
+ 0x71, 0xe6, 0x8f, 0xe8, 0x12, 0x9b, 0x54, 0x6b, 0x10, 0x1a, 0xee, 0x95,
+ 0x10, 0xc5, 0x32, 0x8e, 0x7f, 0x21, 0xca, 0x1d, 0x18, 0x78, 0x9c, 0x63,
+ 0x62, 0x66, 0x4e, 0xcb, 0xcf, 0x07, 0x00, 0x02, 0xac, 0x01, 0x4d, 0x07,
+ 0x67, 0x03, 0xc5, 0x40, 0x99, 0x49, 0xb1, 0x3b, 0x7d, 0xae, 0x9b, 0x0e,
+ 0xdd, 0xde, 0xc6, 0x76, 0x43, 0x24, 0x64
+};
+static const unsigned int corrupt_thin_pack_len = 67;
+
+/*
+ * Packfile with a missing trailer.
+ */
+static const unsigned char missing_trailer_pack[] = {
+ 0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x50, 0xf4, 0x3b,
+};
+static const unsigned int missing_trailer_pack_len = 12;
+
+/*
* Packfile that causes the packfile stream to open in a way in which it leaks
* the stream reader.
*/
@@ -71,6 +94,22 @@ void test_pack_indexer__out_of_order(void)
git_indexer_free(idx);
}
+void test_pack_indexer__missing_trailer(void)
+{
+ git_indexer *idx = 0;
+ git_transfer_progress stats = { 0 };
+
+ cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL));
+ cl_git_pass(git_indexer_append(
+ idx, missing_trailer_pack, missing_trailer_pack_len, &stats));
+ cl_git_fail(git_indexer_commit(idx, &stats));
+
+ cl_assert(giterr_last() != NULL);
+ cl_assert_equal_i(giterr_last()->klass, GITERR_INDEXER);
+
+ git_indexer_free(idx);
+}
+
void test_pack_indexer__leaky(void)
{
git_indexer *idx = 0;
@@ -153,6 +192,35 @@ void test_pack_indexer__fix_thin(void)
}
}
+void test_pack_indexer__corrupt_length(void)
+{
+ git_indexer *idx = NULL;
+ git_transfer_progress stats = { 0 };
+ git_repository *repo;
+ git_odb *odb;
+ git_oid id, should_id;
+
+ cl_git_pass(git_repository_init(&repo, "thin.git", true));
+ cl_git_pass(git_repository_odb(&odb, repo));
+
+ /* Store the missing base into your ODB so the indexer can fix the pack */
+ cl_git_pass(git_odb_write(&id, odb, base_obj, base_obj_len, GIT_OBJ_BLOB));
+ git_oid_fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18");
+ cl_assert_equal_oid(&should_id, &id);
+
+ cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL, NULL));
+ cl_git_pass(git_indexer_append(
+ idx, corrupt_thin_pack, corrupt_thin_pack_len, &stats));
+ cl_git_fail(git_indexer_commit(idx, &stats));
+
+ cl_assert(giterr_last() != NULL);
+ cl_assert_equal_i(giterr_last()->klass, GITERR_ZLIB);
+
+ git_indexer_free(idx);
+ git_odb_free(odb);
+ git_repository_free(repo);
+}
+
static int find_tmp_file_recurs(void *opaque, git_buf *path)
{
int error = 0;
diff --git a/tests/patch/parse.c b/tests/patch/parse.c
index 8350ac2dd..a40ad7b23 100644
--- a/tests/patch/parse.c
+++ b/tests/patch/parse.c
@@ -102,3 +102,9 @@ void test_patch_parse__invalid_patches_fails(void)
strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER), NULL));
}
+void test_patch_parse__files_with_whitespaces_succeeds(void)
+{
+ git_patch *patch;
+ cl_git_pass(git_patch_from_buffer(&patch, PATCH_NAME_WHITESPACE, strlen(PATCH_NAME_WHITESPACE), NULL));
+ git_patch_free(patch);
+}
diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h
index a20ebd617..e838e6089 100644
--- a/tests/patch/patch_common.h
+++ b/tests/patch/patch_common.h
@@ -575,6 +575,16 @@
"+added line with no nl\n" \
"\\ No newline at end of file\n"
+#define PATCH_NAME_WHITESPACE \
+ "diff --git a/file with spaces.txt b/file with spaces.txt\n" \
+ "index 9432026..83759c0 100644\n" \
+ "--- a/file with spaces.txt\n" \
+ "+++ b/file with spaces.txt\n" \
+ "@@ -0,3 +0,2 @@\n" \
+ " and this\n" \
+ "-is additional context\n" \
+ " below it!\n" \
+
#define PATCH_CORRUPT_GIT_HEADER \
"diff --git a/file.txt\n" \
"index 9432026..0f39b9a 100644\n" \
diff --git a/tests/refs/iterator.c b/tests/refs/iterator.c
index c77451309..56f6ce505 100644
--- a/tests/refs/iterator.c
+++ b/tests/refs/iterator.c
@@ -6,12 +6,12 @@ static git_repository *repo;
void test_refs_iterator__initialize(void)
{
- cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+ repo = cl_git_sandbox_init("testrepo.git");
}
void test_refs_iterator__cleanup(void)
{
- git_repository_free(repo);
+ cl_git_sandbox_cleanup();
}
static const char *refnames[] = {
@@ -36,6 +36,36 @@ static const char *refnames[] = {
"refs/tags/taggerless",
"refs/tags/test",
"refs/tags/wrapped_tag",
+ NULL
+};
+
+static const char *refnames_with_symlink[] = {
+ "refs/heads/br2",
+ "refs/heads/cannot-fetch",
+ "refs/heads/chomped",
+ "refs/heads/haacked",
+ "refs/heads/link/a",
+ "refs/heads/link/b",
+ "refs/heads/link/c",
+ "refs/heads/link/d",
+ "refs/heads/master",
+ "refs/heads/not-good",
+ "refs/heads/packed",
+ "refs/heads/packed-test",
+ "refs/heads/subtrees",
+ "refs/heads/test",
+ "refs/heads/track-local",
+ "refs/heads/trailing",
+ "refs/notes/fanout",
+ "refs/remotes/test/master",
+ "refs/tags/annotated_tag_to_blob",
+ "refs/tags/e90810b",
+ "refs/tags/hard_tag",
+ "refs/tags/point_to_blob",
+ "refs/tags/taggerless",
+ "refs/tags/test",
+ "refs/tags/wrapped_tag",
+ NULL
};
static int refcmp_cb(const void *a, const void *b)
@@ -46,21 +76,21 @@ static int refcmp_cb(const void *a, const void *b)
return strcmp(refa->name, refb->name);
}
-static void assert_all_refnames_match(git_vector *output)
+static void assert_all_refnames_match(const char **expected, git_vector *names)
{
size_t i;
git_reference *ref;
- cl_assert_equal_sz(output->length, ARRAY_SIZE(refnames));
-
- git_vector_sort(output);
+ git_vector_sort(names);
- git_vector_foreach(output, i, ref) {
- cl_assert_equal_s(ref->name, refnames[i]);
+ git_vector_foreach(names, i, ref) {
+ cl_assert(expected[i] != NULL);
+ cl_assert_equal_s(expected[i], ref->name);
git_reference_free(ref);
}
+ cl_assert(expected[i] == NULL);
- git_vector_free(output);
+ git_vector_free(names);
}
void test_refs_iterator__list(void)
@@ -82,7 +112,7 @@ void test_refs_iterator__list(void)
git_reference_iterator_free(iter);
- assert_all_refnames_match(&output);
+ assert_all_refnames_match(refnames, &output);
}
void test_refs_iterator__empty(void)
@@ -115,7 +145,29 @@ void test_refs_iterator__foreach(void)
git_vector output;
cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
cl_git_pass(git_reference_foreach(repo, refs_foreach_cb, &output));
- assert_all_refnames_match(&output);
+ assert_all_refnames_match(refnames, &output);
+}
+
+void test_refs_iterator__foreach_through_symlink(void)
+{
+ git_vector output;
+
+#ifdef GIT_WIN32
+ cl_skip();
+#endif
+
+ cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
+
+ cl_git_pass(p_mkdir("refs", 0777));
+ cl_git_mkfile("refs/a", "1234567890123456789012345678901234567890");
+ cl_git_mkfile("refs/b", "1234567890123456789012345678901234567890");
+ cl_git_mkfile("refs/c", "1234567890123456789012345678901234567890");
+ cl_git_mkfile("refs/d", "1234567890123456789012345678901234567890");
+
+ cl_git_pass(p_symlink("../../../refs", "testrepo.git/refs/heads/link"));
+
+ cl_git_pass(git_reference_foreach(repo, refs_foreach_cb, &output));
+ assert_all_refnames_match(refnames_with_symlink, &output);
}
static int refs_foreach_cancel_cb(git_reference *reference, void *payload)
@@ -156,12 +208,11 @@ void test_refs_iterator__foreach_name(void)
cl_git_pass(
git_reference_foreach_name(repo, refs_foreach_name_cb, &output));
- cl_assert_equal_sz(output.length, ARRAY_SIZE(refnames));
git_vector_sort(&output);
git_vector_foreach(&output, i, name) {
- cl_assert_equal_s(name, refnames[i]);
- git__free(name);
+ cl_assert(refnames[i] != NULL);
+ cl_assert_equal_s(refnames[i], name);
}
git_vector_free(&output);
@@ -194,7 +245,7 @@ void test_refs_iterator__concurrent_delete(void)
const char *name;
int error;
- git_repository_free(repo);
+ cl_git_sandbox_cleanup();
repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_reference_iterator_new(&iter, repo));
@@ -215,7 +266,4 @@ void test_refs_iterator__concurrent_delete(void)
cl_assert_equal_i(GIT_ITEROVER, error);
cl_assert_equal_i(full_count, concurrent_count);
-
- cl_git_sandbox_cleanup();
- repo = NULL;
}
diff --git a/tests/resources/merge-resolve/.gitted/objects/50/c5dc8cdfe40c688eb0a0e23be54dd57cae2e78 b/tests/resources/merge-resolve/.gitted/objects/50/c5dc8cdfe40c688eb0a0e23be54dd57cae2e78
new file mode 100644
index 000000000..c04baa14b
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/50/c5dc8cdfe40c688eb0a0e23be54dd57cae2e78
@@ -0,0 +1,2 @@
+x]
+0})Jv">x/I6ZhIӞ*aeZC`F6;KLO).y8N^ }a'Ѱ S*gpmHp_sh/O>.PiF?,kJZGoJT \ No newline at end of file
diff --git a/tests/resources/merge-resolve/.gitted/objects/7a/a825857f87aea74ddf13d954568aa30dfcdeb4 b/tests/resources/merge-resolve/.gitted/objects/7a/a825857f87aea74ddf13d954568aa30dfcdeb4
new file mode 100644
index 000000000..b9c06303b
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/objects/7a/a825857f87aea74ddf13d954568aa30dfcdeb4
Binary files differ
diff --git a/tests/resources/merge-resolve/.gitted/refs/heads/delete-submodule b/tests/resources/merge-resolve/.gitted/refs/heads/delete-submodule
new file mode 100644
index 000000000..1951316d5
--- /dev/null
+++ b/tests/resources/merge-resolve/.gitted/refs/heads/delete-submodule
@@ -0,0 +1 @@
+50c5dc8cdfe40c688eb0a0e23be54dd57cae2e78