From f57403919a48f79c409d84f8f879412a7429e260 Mon Sep 17 00:00:00 2001 From: Tony Kelman Date: Tue, 7 Jul 2015 06:55:05 -0400 Subject: [PATCH 01/29] Fix undefined reference with old versions of openssl Versions prior to 0.9.8f did not have this function, rhel/centos5 are still on a heavily backported version of 0.9.8e and theoretically supported until March 2017 Without this ifdef, I get the following link failure: ``` CMakeFiles/libgit2_clar.dir/src/openssl_stream.c.o: In function `openssl_connect': openssl_stream.c:(.text+0x45a): undefined reference to `SSL_set_tlsext_host_name' collect2: error: ld returned 1 exit status make[6]: *** [libgit2_clar] Error 1 ``` --- src/openssl_stream.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openssl_stream.c b/src/openssl_stream.c index 958252e9f..4df7c6b7c 100644 --- a/src/openssl_stream.c +++ b/src/openssl_stream.c @@ -324,7 +324,9 @@ int openssl_connect(git_stream *stream) SSL_set_bio(st->ssl, bio, bio); /* specify the host in case SNI is needed */ +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_set_tlsext_host_name(st->ssl, st->host); +#endif if ((ret = SSL_connect(st->ssl)) <= 0) return ssl_set_error(st->ssl, ret); From 9ff89eaaa17b2642a2d0f8c53983e1d465fac936 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 7 Jul 2015 16:59:14 -0500 Subject: [PATCH 02/29] merge_files: don't add trailing newlines When invoked with three files that each lack a trailing newline, the merge result should also lack a trailing newline. --- tests/merge/files.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/merge/files.c b/tests/merge/files.c index 7f461abff..2fd90d066 100644 --- a/tests/merge/files.c +++ b/tests/merge/files.c @@ -249,3 +249,42 @@ void test_merge_files__automerge_whitespace_change(void) git_merge_file_result_free(&result); } + +void test_merge_files__doesnt_add_newline(void) +{ + git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT, + ours = GIT_MERGE_FILE_INPUT_INIT, + theirs = GIT_MERGE_FILE_INPUT_INIT; + git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT; + git_merge_file_result result = {0}; + const char *expected = "Zero\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\nTen"; + + ancestor.ptr = "0\n1\n2\n3\n4\n5 XXX\n6YYY\n7\n8\n9\n10"; + ancestor.size = strlen(ancestor.ptr); + ancestor.path = "testfile.txt"; + ancestor.mode = 0100755; + + ours.ptr = "Zero\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\n10"; + ours.size = strlen(ours.ptr); + ours.path = "testfile.txt"; + ours.mode = 0100755; + + theirs.ptr = "0\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\nTen"; + theirs.size = strlen(theirs.ptr); + theirs.path = "testfile.txt"; + theirs.mode = 0100755; + + opts.flags |= GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE; + cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, &opts)); + + cl_assert_equal_i(1, result.automergeable); + + cl_assert_equal_s("testfile.txt", result.path); + cl_assert_equal_i(0100755, result.mode); + + cl_assert_equal_i(strlen(expected), result.len); + cl_assert_equal_strn(expected, result.ptr, result.len); + + git_merge_file_result_free(&result); +} + From ba6b288426420add9820aa54f3564c59ac74ca88 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 7 Jul 2015 16:46:20 -0500 Subject: [PATCH 03/29] revert: correct test that added trailing newline --- tests/revert/workdir.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/revert/workdir.c b/tests/revert/workdir.c index 7ccf0f937..9f83bd842 100644 --- a/tests/revert/workdir.c +++ b/tests/revert/workdir.c @@ -334,16 +334,18 @@ void test_revert_workdir__again_after_edit_two(void) cl_assert(merge_test_index(repo_index, merge_index_entries, 3)); cl_git_pass(git_futils_readbuffer(&diff_buf, "revert/file.txt")); - cl_assert(strcmp(diff_buf.ptr, "a\n" \ - "<<<<<<< HEAD\n" \ - "=======\n" \ - "a\n" \ - ">>>>>>> parent of 97e52d5... Revert me\n" \ - "a\n" \ - "a\n" \ - "a\n" \ - "a\n" \ - "ab\n") == 0); + cl_assert_equal_s( + "a\n" \ + "<<<<<<< HEAD\n" \ + "=======\n" \ + "a\n" \ + ">>>>>>> parent of 97e52d5... Revert me\n" \ + "a\n" \ + "a\n" \ + "a\n" \ + "a\n" \ + "ab", + diff_buf.ptr); git_commit_free(revert_commit); git_commit_free(head_commit); From 75d0b81abf41e419ad07cd12f3c8577fd431830b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 7 Jul 2015 16:46:48 -0500 Subject: [PATCH 04/29] xdiff: upgrade to core git 2.4.5 Upgrade xdiff to version used in core git 2.4.5 (0df0541). Corrects an issue where an LF is added at EOF while applying an unrelated change (ba31180), cleans up some unused code (be89977 and e5b0662), and provides an improved callback to avoid leaking internal (to xdiff) structures (467d348). This also adds some additional functionality that we do not yet take advantage of, namely the ability to ignore changes whose lines are all blank (36617af). --- src/blame_git.c | 25 +++++++++------------ src/xdiff/xdiff.h | 18 ++++++++++------ src/xdiff/xdiffi.c | 48 +++++++++++++++++++++++++++++++++++++---- src/xdiff/xdiffi.h | 1 + src/xdiff/xemit.c | 49 ++++++++++++++++++++++++++++++++++++------ src/xdiff/xemit.h | 2 +- src/xdiff/xhistogram.c | 2 +- src/xdiff/xmerge.c | 4 ++-- src/xdiff/xpatience.c | 2 +- src/xdiff/xprepare.c | 21 +++++++++--------- src/xdiff/xutils.c | 42 +++++++++++------------------------- src/xdiff/xutils.h | 1 + 12 files changed, 138 insertions(+), 77 deletions(-) diff --git a/src/blame_git.c b/src/blame_git.c index e863efe2e..f481426aa 100644 --- a/src/blame_git.c +++ b/src/blame_git.c @@ -304,21 +304,16 @@ static void blame_chunk( } static int my_emit( - xdfenv_t *xe, - xdchange_t *xscr, - xdemitcb_t *ecb, - xdemitconf_t const *xecfg) + long start_a, long count_a, + long start_b, long count_b, + void *cb_data) { - xdchange_t *xch = xscr; - GIT_UNUSED(xe); - GIT_UNUSED(xecfg); - while (xch) { - blame_chunk_cb_data *d = ecb->priv; - blame_chunk(d->blame, d->tlno, d->plno, xch->i2, d->target, d->parent); - d->plno = xch->i1 + xch->chg1; - d->tlno = xch->i2 + xch->chg2; - xch = xch->next; - } + blame_chunk_cb_data *d = (blame_chunk_cb_data *)cb_data; + + blame_chunk(d->blame, d->tlno, d->plno, start_b, d->target, d->parent); + d->plno = start_a + count_a; + d->tlno = start_b + count_b; + return 0; } @@ -352,7 +347,7 @@ static int diff_hunks(mmfile_t file_a, mmfile_t file_b, void *cb_data) xdemitconf_t xecfg = {0}; xdemitcb_t ecb = {0}; - xecfg.emit_func = (void(*)(void))my_emit; + xecfg.hunk_func = my_emit; ecb.priv = cb_data; trim_common_tail(&file_a, &file_b, 0); diff --git a/src/xdiff/xdiff.h b/src/xdiff/xdiff.h index cb8b235b5..e2f1e892b 100644 --- a/src/xdiff/xdiff.h +++ b/src/xdiff/xdiff.h @@ -32,14 +32,14 @@ extern "C" { #define XDF_IGNORE_WHITESPACE (1 << 2) #define XDF_IGNORE_WHITESPACE_CHANGE (1 << 3) #define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 4) -#define XDF_PATIENCE_DIFF (1 << 5) -#define XDF_HISTOGRAM_DIFF (1 << 6) #define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE | XDF_IGNORE_WHITESPACE_AT_EOL) -#define XDL_PATCH_NORMAL '-' -#define XDL_PATCH_REVERSE '+' -#define XDL_PATCH_MODEMASK ((1 << 8) - 1) -#define XDL_PATCH_IGNOREBSPACE (1 << 8) +#define XDF_PATIENCE_DIFF (1 << 5) +#define XDF_HISTOGRAM_DIFF (1 << 6) +#define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF) +#define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK) + +#define XDF_IGNORE_BLANK_LINES (1 << 7) #define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_COMMON (1 << 1) @@ -88,13 +88,17 @@ typedef struct s_xdemitcb { typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv); +typedef int (*xdl_emit_hunk_consume_func_t)(long start_a, long count_a, + long start_b, long count_b, + void *cb_data); + typedef struct s_xdemitconf { long ctxlen; long interhunkctxlen; unsigned long flags; find_func_t find_func; void *find_func_priv; - void (*emit_func)(void); + xdl_emit_hunk_consume_func_t hunk_func; } xdemitconf_t; typedef struct s_bdiffparam { diff --git a/src/xdiff/xdiffi.c b/src/xdiff/xdiffi.c index 84aa0fcfe..2358a2d63 100644 --- a/src/xdiff/xdiffi.c +++ b/src/xdiff/xdiffi.c @@ -328,10 +328,10 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdalgoenv_t xenv; diffdata_t dd1, dd2; - if (xpp->flags & XDF_PATIENCE_DIFF) + if (XDF_DIFF_ALG(xpp->flags) == XDF_PATIENCE_DIFF) return xdl_do_patience_diff(mf1, mf2, xpp, xe); - if (xpp->flags & XDF_HISTOGRAM_DIFF) + if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF) return xdl_do_histogram_diff(mf1, mf2, xpp, xe); if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) { @@ -394,6 +394,7 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, xch->i2 = i2; xch->chg1 = chg1; xch->chg2 = chg2; + xch->ignore = 0; return xch; } @@ -538,13 +539,49 @@ void xdl_free_script(xdchange_t *xscr) { } } +static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, + xdemitconf_t const *xecfg) +{ + xdchange_t *xch, *xche; + + for (xch = xscr; xch; xch = xche->next) { + xche = xdl_get_hunk(&xch, xecfg); + if (!xch) + break; + if (xecfg->hunk_func(xch->i1, xche->i1 + xche->chg1 - xch->i1, + xch->i2, xche->i2 + xche->chg2 - xch->i2, + ecb->priv) < 0) + return -1; + } + return 0; +} + +static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags) +{ + xdchange_t *xch; + + for (xch = xscr; xch; xch = xch->next) { + int ignore = 1; + xrecord_t **rec; + long i; + + rec = &xe->xdf1.recs[xch->i1]; + for (i = 0; i < xch->chg1 && ignore; i++) + ignore = xdl_blankline(rec[i]->ptr, rec[i]->size, flags); + + rec = &xe->xdf2.recs[xch->i2]; + for (i = 0; i < xch->chg2 && ignore; i++) + ignore = xdl_blankline(rec[i]->ptr, rec[i]->size, flags); + + xch->ignore = ignore; + } +} int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb) { xdchange_t *xscr; xdfenv_t xe; - emit_func_t ef = xecfg->emit_func ? - (emit_func_t)xecfg->emit_func : xdl_emit_diff; + emit_func_t ef = xecfg->hunk_func ? xdl_call_hunk_func : xdl_emit_diff; if (xdl_do_diff(mf1, mf2, xpp, &xe) < 0) { @@ -558,6 +595,9 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, return -1; } if (xscr) { + if (xpp->flags & XDF_IGNORE_BLANK_LINES) + xdl_mark_ignorable(xscr, &xe, xpp->flags); + if (ef(&xe, xscr, ecb, xecfg) < 0) { xdl_free_script(xscr); diff --git a/src/xdiff/xdiffi.h b/src/xdiff/xdiffi.h index 7a92ea9c4..8b81206c9 100644 --- a/src/xdiff/xdiffi.h +++ b/src/xdiff/xdiffi.h @@ -41,6 +41,7 @@ typedef struct s_xdchange { struct s_xdchange *next; long i1, i2; long chg1, chg2; + int ignore; } xdchange_t; diff --git a/src/xdiff/xemit.c b/src/xdiff/xemit.c index e3e63d902..750a97294 100644 --- a/src/xdiff/xemit.c +++ b/src/xdiff/xemit.c @@ -56,16 +56,51 @@ static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t * /* * Starting at the passed change atom, find the latest change atom to be included * inside the differential hunk according to the specified configuration. + * Also advance xscr if the first changes must be discarded. */ -xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) { - xdchange_t *xch, *xchp; +xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) +{ + xdchange_t *xch, *xchp, *lxch; long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen; + long max_ignorable = xecfg->ctxlen; + unsigned long ignored = 0; /* number of ignored blank lines */ - for (xchp = xscr, xch = xscr->next; xch; xchp = xch, xch = xch->next) - if (xch->i1 - (xchp->i1 + xchp->chg1) > max_common) + /* remove ignorable changes that are too far before other changes */ + for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) { + xch = xchp->next; + + if (xch == NULL || + xch->i1 - (xchp->i1 + xchp->chg1) >= max_ignorable) + *xscr = xch; + } + + if (*xscr == NULL) + return NULL; + + lxch = *xscr; + + for (xchp = *xscr, xch = xchp->next; xch; xchp = xch, xch = xch->next) { + long distance = xch->i1 - (xchp->i1 + xchp->chg1); + if (distance > max_common) break; - return xchp; + if (distance < max_ignorable && (!xch->ignore || lxch == xchp)) { + lxch = xch; + ignored = 0; + } else if (distance < max_ignorable && xch->ignore) { + ignored += xch->chg2; + } else if (lxch != xchp && + xch->i1 + ignored - (lxch->i1 + lxch->chg1) > max_common) { + break; + } else if (!xch->ignore) { + lxch = xch; + ignored = 0; + } else { + ignored += xch->chg2; + } + } + + return lxch; } @@ -144,7 +179,9 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, return xdl_emit_common(xe, xscr, ecb, xecfg); for (xch = xscr; xch; xch = xche->next) { - xche = xdl_get_hunk(xch, xecfg); + xche = xdl_get_hunk(&xch, xecfg); + if (!xch) + break; s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0); s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0); diff --git a/src/xdiff/xemit.h b/src/xdiff/xemit.h index c2e2e8302..d29710770 100644 --- a/src/xdiff/xemit.h +++ b/src/xdiff/xemit.h @@ -27,7 +27,7 @@ typedef int (*emit_func_t)(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); -xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg); +xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg); int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); diff --git a/src/xdiff/xhistogram.c b/src/xdiff/xhistogram.c index c84812893..500d8112a 100644 --- a/src/xdiff/xhistogram.c +++ b/src/xdiff/xhistogram.c @@ -258,7 +258,7 @@ static int fall_back_to_classic_diff(struct histindex *index, int line1, int count1, int line2, int count2) { xpparam_t xpp; - xpp.flags = index->xpp->flags & ~XDF_HISTOGRAM_DIFF; + xpp.flags = index->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK; return xdl_fall_back_diff(index->env, &xpp, line1, count1, line2, count2); diff --git a/src/xdiff/xmerge.c b/src/xdiff/xmerge.c index 84e424672..b11e59817 100644 --- a/src/xdiff/xmerge.c +++ b/src/xdiff/xmerge.c @@ -245,11 +245,11 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, dest ? dest + size : NULL); /* Postimage from side #1 */ if (m->mode & 1) - size += xdl_recs_copy(xe1, m->i1, m->chg1, 1, + size += xdl_recs_copy(xe1, m->i1, m->chg1, (m->mode & 2), dest ? dest + size : NULL); /* Postimage from side #2 */ if (m->mode & 2) - size += xdl_recs_copy(xe2, m->i2, m->chg2, 1, + size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, dest ? dest + size : NULL); } else continue; diff --git a/src/xdiff/xpatience.c b/src/xdiff/xpatience.c index fdd7d0263..04e1a1ab2 100644 --- a/src/xdiff/xpatience.c +++ b/src/xdiff/xpatience.c @@ -288,7 +288,7 @@ static int fall_back_to_classic_diff(struct hashmap *map, int line1, int count1, int line2, int count2) { xpparam_t xpp; - xpp.flags = map->xpp->flags & ~XDF_PATIENCE_DIFF; + xpp.flags = map->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK; return xdl_fall_back_diff(map->env, &xpp, line1, count1, line2, count2); diff --git a/src/xdiff/xprepare.c b/src/xdiff/xprepare.c index e419f4f72..63a22c630 100644 --- a/src/xdiff/xprepare.c +++ b/src/xdiff/xprepare.c @@ -181,7 +181,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *)))) goto abort; - if (xpp->flags & XDF_HISTOGRAM_DIFF) + if (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF) hbits = hsize = 0; else { hbits = xdl_hashbits((unsigned int) narec); @@ -209,8 +209,8 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_ crec->ha = hav; recs[nrec++] = crec; - if (!(xpp->flags & XDF_HISTOGRAM_DIFF) && - xdl_classify_record(pass, cf, rhash, hbits, crec) < 0) + if ((XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) && + xdl_classify_record(pass, cf, rhash, hbits, crec) < 0) goto abort; } } @@ -273,16 +273,15 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, * (nrecs) will be updated correctly anyway by * xdl_prepare_ctx(). */ - sample = xpp->flags & XDF_HISTOGRAM_DIFF ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1; + sample = (XDF_DIFF_ALG(xpp->flags) == XDF_HISTOGRAM_DIFF + ? XDL_GUESS_NLINES2 : XDL_GUESS_NLINES1); enl1 = xdl_guess_lines(mf1, sample) + 1; enl2 = xdl_guess_lines(mf2, sample) + 1; - if (!(xpp->flags & XDF_HISTOGRAM_DIFF) && - xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0) { - + if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF && + xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0) return -1; - } if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) { @@ -296,9 +295,9 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, return -1; } - if (!(xpp->flags & XDF_PATIENCE_DIFF) && - !(xpp->flags & XDF_HISTOGRAM_DIFF) && - xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) { + if ((XDF_DIFF_ALG(xpp->flags) != XDF_PATIENCE_DIFF) && + (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) && + xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) { xdl_free_ctx(&xe->xdf2); xdl_free_ctx(&xe->xdf1); diff --git a/src/xdiff/xutils.c b/src/xdiff/xutils.c index bb7bdee49..30f2a30ac 100644 --- a/src/xdiff/xutils.c +++ b/src/xdiff/xutils.c @@ -120,35 +120,6 @@ void *xdl_cha_alloc(chastore_t *cha) { return data; } - -void *xdl_cha_first(chastore_t *cha) { - chanode_t *sncur; - - if (!(cha->sncur = sncur = cha->head)) - return NULL; - - cha->scurr = 0; - - return (char *) sncur + sizeof(chanode_t) + cha->scurr; -} - - -void *xdl_cha_next(chastore_t *cha) { - chanode_t *sncur; - - if (!(sncur = cha->sncur)) - return NULL; - cha->scurr += cha->isize; - if (cha->scurr == sncur->icurr) { - if (!(sncur = cha->sncur = sncur->next)) - return NULL; - cha->scurr = 0; - } - - return (char *) sncur + sizeof(chanode_t) + cha->scurr; -} - - long xdl_guess_lines(mmfile_t *mf, long sample) { long nl = 0, size, tsize = 0; char const *data, *cur, *top; @@ -170,6 +141,19 @@ long xdl_guess_lines(mmfile_t *mf, long sample) { return nl + 1; } +int xdl_blankline(const char *line, long size, long flags) +{ + long i; + + if (!(flags & XDF_WHITESPACE_FLAGS)) + return (size <= 1); + + for (i = 0; i < size && XDL_ISSPACE(line[i]); i++) + ; + + return (i == size); +} + int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) { int i1, i2; diff --git a/src/xdiff/xutils.h b/src/xdiff/xutils.h index 714719a89..8f952a8e6 100644 --- a/src/xdiff/xutils.h +++ b/src/xdiff/xutils.h @@ -34,6 +34,7 @@ void *xdl_cha_alloc(chastore_t *cha); void *xdl_cha_first(chastore_t *cha); void *xdl_cha_next(chastore_t *cha); long xdl_guess_lines(mmfile_t *mf, long sample); +int xdl_blankline(const char *line, long size, long flags); int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags); unsigned long xdl_hash_record(char const **data, char const *top, long flags); unsigned int xdl_hashbits(unsigned int size); From a4743de87362e0d26a1c7092ce965ef4ed2b6dd9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 10 Jul 2015 09:21:59 -0500 Subject: [PATCH 05/29] xdiff: cleanup some warnings --- src/xdiff/xdiffi.c | 2 ++ src/xdiff/xemit.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xdiff/xdiffi.c b/src/xdiff/xdiffi.c index 2358a2d63..0620e5fff 100644 --- a/src/xdiff/xdiffi.c +++ b/src/xdiff/xdiffi.c @@ -544,6 +544,8 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, { xdchange_t *xch, *xche; + (void)xe; + for (xch = xscr; xch; xch = xche->next) { xche = xdl_get_hunk(&xch, xecfg); if (!xch) diff --git a/src/xdiff/xemit.c b/src/xdiff/xemit.c index 750a97294..600fd1fdd 100644 --- a/src/xdiff/xemit.c +++ b/src/xdiff/xemit.c @@ -90,7 +90,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) } else if (distance < max_ignorable && xch->ignore) { ignored += xch->chg2; } else if (lxch != xchp && - xch->i1 + ignored - (lxch->i1 + lxch->chg1) > max_common) { + xch->i1 + ignored - (lxch->i1 + lxch->chg1) > (unsigned long)max_common) { break; } else if (!xch->ignore) { lxch = xch; From f2dc6b77eeaa828fbad46900eb7419b4b43d7744 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 30 Jun 2015 13:41:01 +0000 Subject: [PATCH 06/29] khash: add eol so picky compilers stop warning --- src/khash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/khash.h b/src/khash.h index 818ac833b..71eb583d5 100644 --- a/src/khash.h +++ b/src/khash.h @@ -619,4 +619,4 @@ typedef const char *kh_cstr_t; #define KHASH_MAP_INIT_STR(name, khval_t) \ KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal) -#endif /* __AC_KHASH_H */ \ No newline at end of file +#endif /* __AC_KHASH_H */ From 1207b8f2a7dd155a4158ba8abc61d5d519d748f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 11 Jul 2015 13:32:57 +0200 Subject: [PATCH 07/29] submdule: reproduce double-reporting of a submodule in foreach When we rename a submodule, we should be merging two sets of information based on whether their path is the same. We currently only deduplicate on equal name, which causes us to double-report. --- tests/submodule/lookup.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/submodule/lookup.c b/tests/submodule/lookup.c index 4d40e2279..9b2b3aa19 100644 --- a/tests/submodule/lookup.c +++ b/tests/submodule/lookup.c @@ -1,6 +1,7 @@ #include "clar_libgit2.h" #include "submodule_helpers.h" #include "git2/sys/repository.h" +#include "repository.h" #include "fileops.h" static git_repository *g_repo = NULL; @@ -103,10 +104,27 @@ static int sm_lookup_cb(git_submodule *sm, const char *name, void *payload) void test_submodule_lookup__foreach(void) { + git_config *cfg; sm_lookup_data data; + memset(&data, 0, sizeof(data)); cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data)); cl_assert_equal_i(8, data.count); + + memset(&data, 0, sizeof(data)); + + /* Change the path for a submodule so it doesn't match the name */ + cl_git_pass(git_config_open_ondisk(&cfg, "submod2/.gitmodules")); + + cl_git_pass(git_config_set_string(cfg, "submodule.smchangedindex.path", "sm_changed_index")); + cl_git_pass(git_config_set_string(cfg, "submodule.smchangedindex.url", "../submod2_target")); + cl_git_pass(git_config_delete_entry(cfg, "submodule.sm_changed_index.path")); + cl_git_pass(git_config_delete_entry(cfg, "submodule.sm_changed_index.url")); + + git_config_free(cfg); + + cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data)); + cl_assert_equal_i(8, data.count); } void test_submodule_lookup__lookup_even_with_unborn_head(void) From e48dd86ecae27dcf688ad4e4c9f786fd420a18b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 11 Jul 2015 18:31:28 +0200 Subject: [PATCH 08/29] submodule: lookup the submodule by path if available If we get the path from the gitmodules file, look up the submodule we're interested in by path, rather then by name. Otherwise we might get duplicate results. --- src/submodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/submodule.c b/src/submodule.c index fb3d4bf1e..892c98304 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -1647,7 +1647,7 @@ static int submodule_load_from_config( } else { khiter_t pos; git_strmap *map = data->map; - pos = git_strmap_lookup_index(map, name.ptr); + pos = git_strmap_lookup_index(map, path ? path : name.ptr); if (git_strmap_valid_index(map, pos)) { sm = git_strmap_value_at(map, pos); } else { From 7624b91fd3f27cb5149e9f1199d4b03f88dd152b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 11 Jul 2015 18:51:36 +0200 Subject: [PATCH 09/29] errors: add EDIRECTORY This is to be returned when the operation which the user asked for is not possible to do on a directory. --- include/git2/errors.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/git2/errors.h b/include/git2/errors.h index a81aa05d9..e189e55f1 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -48,6 +48,7 @@ typedef enum { GIT_EEOF = -20, /**< Unexpected EOF */ GIT_EINVALID = -21, /**< Invalid operation or input */ GIT_EUNCOMMITTED = -22, /**< Uncommitted changes in index prevented operation */ + GIT_EDIRECTORY = -23, /**< The operation is not valid for a directory */ GIT_PASSTHROUGH = -30, /**< Internal only */ GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */ From aafaa491ba890a478c77947c6ac5b8a750dc54a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 11 Jul 2015 19:03:38 +0200 Subject: [PATCH 10/29] blob: fail to create a blob from a dir with EDIRECTORY This also affects `git_index_add_bypath()` by providing a better error message and a specific error code when a directory is passed. --- src/blob.c | 6 ++++++ tests/index/bypath.c | 23 +++++++++++++++++++++++ tests/submodule/add.c | 1 + 3 files changed, 30 insertions(+) create mode 100644 tests/index/bypath.c diff --git a/src/blob.c b/src/blob.c index 07c4d92c8..ad0f4ac62 100644 --- a/src/blob.c +++ b/src/blob.c @@ -185,6 +185,12 @@ int git_blob__create_from_paths( (error = git_repository_odb(&odb, repo)) < 0) goto done; + if (S_ISDIR(st.st_mode)) { + giterr_set(GITERR_ODB, "cannot create blob from '%s'; it is a directory", content_path); + error = GIT_EDIRECTORY; + goto done; + } + if (out_st) memcpy(out_st, &st, sizeof(st)); diff --git a/tests/index/bypath.c b/tests/index/bypath.c new file mode 100644 index 000000000..08c9934ea --- /dev/null +++ b/tests/index/bypath.c @@ -0,0 +1,23 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "../submodule/submodule_helpers.h" + +static git_repository *g_repo; +static git_index *g_idx; + +void test_index_bypath__initialize(void) +{ + g_repo = setup_fixture_submod2(); + cl_git_pass(git_repository_index__weakptr(&g_idx, g_repo)); +} + +void test_index_bypath__cleanup(void) +{ + g_repo = NULL; + g_idx = NULL; +} + +void test_index_bypath__add_directory(void) +{ + cl_git_fail_with(GIT_EDIRECTORY, git_index_add_bypath(g_idx, "just_a_dir")); +} diff --git a/tests/submodule/add.c b/tests/submodule/add.c index 01625d3aa..c3b3e6364 100644 --- a/tests/submodule/add.c +++ b/tests/submodule/add.c @@ -4,6 +4,7 @@ #include "submodule_helpers.h" #include "config/config_helpers.h" #include "fileops.h" +#include "repository.h" static git_repository *g_repo = NULL; From 678c4aacf5e0ca347516292bea12c8ccbc718b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 11 Jul 2015 19:41:03 +0200 Subject: [PATCH 11/29] index: allow add_bypath to update submodules Similarly to how git itself does it, allow the index update operation to stage a change in a submodule's HEAD. --- src/index.c | 24 ++++++++++++++++++++++-- tests/index/bypath.c | 12 ++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/index.c b/src/index.c index 5ce5522f8..501498e9e 100644 --- a/src/index.c +++ b/src/index.c @@ -1236,10 +1236,30 @@ int git_index_add_bypath(git_index *index, const char *path) assert(index && path); - if ((ret = index_entry_init(&entry, index, path)) < 0 || - (ret = index_insert(index, &entry, 1, false)) < 0) + if ((ret = index_entry_init(&entry, index, path)) == 0) + ret = index_insert(index, &entry, 1, false); + + /* If we were given a directory, let's see if it's a submodule */ + if (ret < 0 && ret != GIT_EDIRECTORY) return ret; + if (ret == GIT_EDIRECTORY) { + git_submodule *sm; + git_error_state err; + + giterr_capture(&err, ret); + + ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path); + if (ret == GIT_ENOTFOUND) + return giterr_restore(&err); + else + git__free(err.error_msg.message); + + ret = git_submodule_add_to_index(sm, false); + git_submodule_free(sm); + return ret; + } + /* Adding implies conflict was resolved, move conflict entries to REUC */ if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND) return ret; diff --git a/tests/index/bypath.c b/tests/index/bypath.c index 08c9934ea..ddb766a22 100644 --- a/tests/index/bypath.c +++ b/tests/index/bypath.c @@ -21,3 +21,15 @@ void test_index_bypath__add_directory(void) { cl_git_fail_with(GIT_EDIRECTORY, git_index_add_bypath(g_idx, "just_a_dir")); } + +void test_index_bypath__add_submodule(void) +{ + unsigned int status; + const char *sm_name = "sm_changed_head"; + + cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0)); + cl_assert_equal_i(GIT_SUBMODULE_STATUS_WD_MODIFIED, status & GIT_SUBMODULE_STATUS_WD_MODIFIED); + cl_git_pass(git_index_add_bypath(g_idx, sm_name)); + cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0)); + cl_assert_equal_i(0, status & GIT_SUBMODULE_STATUS_WD_MODIFIED); +} From 34ff34fd6aed33836be2eab096b41d69a74453f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 12 Jul 2015 13:28:03 +0200 Subject: [PATCH 12/29] filter: make sure to close the stream even on error When the stream list init or write fail, we must also make sure to close the stream, as that's the function contract. --- src/filter.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/filter.c b/src/filter.c index e25d37c35..4006351f8 100644 --- a/src/filter.c +++ b/src/filter.c @@ -947,18 +947,20 @@ int git_filter_list_stream_data( { git_vector filter_streams = GIT_VECTOR_INIT; git_writestream *stream_start; - int error = 0; + int error = 0, close_error; git_buf_sanitize(data); - if ((error = stream_list_init( - &stream_start, &filter_streams, filters, target)) == 0 && - (error = - stream_start->write(stream_start, data->ptr, data->size)) == 0) - error = stream_start->close(stream_start); + if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0) + goto out; + error = stream_start->write(stream_start, data->ptr, data->size); + +out: + close_error = stream_start->close(stream_start); stream_list_free(&filter_streams); - return error; + /* propagate the stream init or write error */ + return error < 0 ? error : close_error; } int git_filter_list_stream_blob( From 38dc9940313343ebee3100c8e7912fb117c0346b Mon Sep 17 00:00:00 2001 From: Matthew Plough Date: Tue, 30 Jun 2015 19:00:41 -0400 Subject: [PATCH 13/29] Fix #3094 - improve use of portable size_t/ssize_t format specifiers. The header src/cc-compat.h defines portable format specifiers PRIuZ, PRIdZ, and PRIxZ. The original report highlighted the need to use these specifiers in examples/network/fetch.c. For this commit, I checked all C source and header files not in deps/ and transitioned to the appropriate format specifier where appropriate. --- examples/network/fetch.c | 4 ++-- src/cache.c | 8 ++++---- src/checkout.c | 4 ++-- src/merge.c | 6 +++--- src/rebase.c | 4 ++-- src/stash.c | 2 +- src/transports/http.c | 2 +- src/transports/smart_pkt.c | 2 +- tests/blame/blame_helpers.c | 2 +- tests/clar_libgit2.c | 4 ++-- tests/merge/merge_helpers.c | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/network/fetch.c b/examples/network/fetch.c index 67444cb4a..6be12406b 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -143,10 +143,10 @@ int fetch(git_repository *repo, int argc, char **argv) * network. */ if (stats->local_objects > 0) { - printf("\rReceived %d/%d objects in %zu bytes (used %d local objects)\n", + printf("\rReceived %d/%d objects in %" PRIuZ " bytes (used %d local objects)\n", stats->indexed_objects, stats->total_objects, stats->received_bytes, stats->local_objects); } else{ - printf("\rReceived %d/%d objects in %zu bytes\n", + printf("\rReceived %d/%d objects in %" PRIuZ "bytes\n", stats->indexed_objects, stats->total_objects, stats->received_bytes); } diff --git a/src/cache.c b/src/cache.c index 2f3ad1563..ca5173c0d 100644 --- a/src/cache.c +++ b/src/cache.c @@ -50,16 +50,16 @@ void git_cache_dump_stats(git_cache *cache) if (kh_size(cache->map) == 0) return; - printf("Cache %p: %d items cached, %d bytes\n", - cache, kh_size(cache->map), (int)cache->used_memory); + printf("Cache %p: %d items cached, %"PRIdZ" bytes\n", + cache, kh_size(cache->map), cache->used_memory); kh_foreach_value(cache->map, object, { char oid_str[9]; - printf(" %s%c %s (%d)\n", + printf(" %s%c %s (%"PRIuZ")\n", git_object_type2string(object->type), object->flags == GIT_CACHE_STORE_PARSED ? '*' : ' ', git_oid_tostr(oid_str, sizeof(oid_str), &object->oid), - (int)object->size + object->size ); }); } diff --git a/src/checkout.c b/src/checkout.c index a94d509d3..4b3acbcce 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1299,8 +1299,8 @@ static int checkout_get_actions( if (counts[CHECKOUT_ACTION__CONFLICT] > 0 && (data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0) { - giterr_set(GITERR_CHECKOUT, "%d %s checkout", - (int)counts[CHECKOUT_ACTION__CONFLICT], + giterr_set(GITERR_CHECKOUT, "%"PRIuZ" %s checkout", + counts[CHECKOUT_ACTION__CONFLICT], counts[CHECKOUT_ACTION__CONFLICT] == 1 ? "conflict prevents" : "conflicts prevent"); error = GIT_ECONFLICT; diff --git a/src/merge.c b/src/merge.c index 9d6252ea8..863ac8f2d 100644 --- a/src/merge.c +++ b/src/merge.c @@ -79,7 +79,7 @@ int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_reposito unsigned int i; if (length < 2) { - giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %u.", length); + giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %" PRIuZ ".", length); return -1; } @@ -185,7 +185,7 @@ int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, co assert(out && repo && input_array); if (length < 2) { - giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %u.", length); + giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %" PRIuZ ".", length); return -1; } @@ -2451,7 +2451,7 @@ int git_merge__check_result(git_repository *repo, git_index *index_new) goto done; if ((conflicts = index_conflicts + wd_conflicts) > 0) { - giterr_set(GITERR_MERGE, "%d uncommitted change%s would be overwritten by merge", + giterr_set(GITERR_MERGE, "%" PRIuZ " uncommitted change%s would be overwritten by merge", conflicts, (conflicts != 1) ? "s" : ""); error = GIT_ECONFLICT; } diff --git a/src/rebase.c b/src/rebase.c index 8da7b4f7f..17536c030 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -436,7 +436,7 @@ static int rebase_setupfiles_merge(git_rebase *rebase) size_t i; int error = 0; - if ((error = rebase_setupfile(rebase, END_FILE, -1, "%d\n", git_array_size(rebase->operations))) < 0 || + if ((error = rebase_setupfile(rebase, END_FILE, -1, "%" PRIuZ "\n", git_array_size(rebase->operations))) < 0 || (error = rebase_setupfile(rebase, ONTO_NAME_FILE, -1, "%s\n", rebase->onto_name)) < 0) goto done; @@ -789,7 +789,7 @@ static int rebase_next_merge( normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit); if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 || - (error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%d\n", rebase->current+1)) < 0 || + (error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%" PRIuZ "\n", rebase->current+1)) < 0 || (error = rebase_setupfile(rebase, CURRENT_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, current_idstr)) < 0 || (error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, NULL)) < 0 || (error = git_merge__check_result(rebase->repo, index)) < 0 || diff --git a/src/stash.c b/src/stash.c index acf89442a..fcb1112ac 100644 --- a/src/stash.c +++ b/src/stash.c @@ -770,7 +770,7 @@ static int ensure_clean_index(git_repository *repo, git_index *index) goto done; if (git_diff_num_deltas(index_diff) > 0) { - giterr_set(GITERR_STASH, "%d uncommitted changes exist in the index", + giterr_set(GITERR_STASH, "%" PRIuZ " uncommitted changes exist in the index", git_diff_num_deltas(index_diff)); error = GIT_EUNCOMMITTED; } diff --git a/src/transports/http.c b/src/transports/http.c index dd4426475..1ed292be5 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -511,7 +511,7 @@ static int write_chunk(git_stream *io, const char *buffer, size_t len) git_buf buf = GIT_BUF_INIT; /* Chunk header */ - git_buf_printf(&buf, "%X\r\n", (unsigned)len); + git_buf_printf(&buf, "%" PRIxZ "\r\n", len); if (git_buf_oom(&buf)) return -1; diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index d214c9fa5..9ccbd8085 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -523,7 +523,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca if (len > 0xffff) { giterr_set(GITERR_NET, - "Tried to produce packet with invalid length %d", len); + "Tried to produce packet with invalid length %" PRIuZ, len); return -1; } diff --git a/tests/blame/blame_helpers.c b/tests/blame/blame_helpers.c index 21cd1a615..b305ba1e3 100644 --- a/tests/blame/blame_helpers.c +++ b/tests/blame/blame_helpers.c @@ -4,7 +4,7 @@ void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...) { va_list arglist; - printf("Hunk %zd (line %d +%d): ", idx, + printf("Hunk %"PRIuZ" (line %d +%d): ", idx, hunk->final_start_line_number, hunk->lines_in_hunk-1); va_start(arglist, fmt); diff --git a/tests/clar_libgit2.c b/tests/clar_libgit2.c index dabc47a09..b14af44a9 100644 --- a/tests/clar_libgit2.c +++ b/tests/clar_libgit2.c @@ -483,8 +483,8 @@ void clar__assert_equal_file( for (pos = 0; pos < bytes && expected_data[pos] == buf[pos]; ++pos) /* find differing byte offset */; p_snprintf( - buf, sizeof(buf), "file content mismatch at byte %d", - (int)(total_bytes + pos)); + buf, sizeof(buf), "file content mismatch at byte %"PRIdZ, + (ssize_t)(total_bytes + pos)); p_close(fd); clar__fail(file, line, path, buf, 1); } diff --git a/tests/merge/merge_helpers.c b/tests/merge/merge_helpers.c index 33710f403..f81471424 100644 --- a/tests/merge/merge_helpers.c +++ b/tests/merge/merge_helpers.c @@ -110,7 +110,7 @@ void merge__dump_index_entries(git_vector *index_entries) size_t i; const git_index_entry *index_entry; - printf ("\nINDEX [%d]:\n", (int)index_entries->length); + printf ("\nINDEX [%"PRIuZ"]:\n", index_entries->length); for (i = 0; i < index_entries->length; i++) { index_entry = index_entries->contents[i]; From a89a756d872c9e3e60637590adacf3f8eba70aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 13 Jul 2015 08:39:35 +0200 Subject: [PATCH 14/29] submodule: add failing test for backslash in url --- tests/submodule/lookup.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/submodule/lookup.c b/tests/submodule/lookup.c index 9b2b3aa19..ecea694e5 100644 --- a/tests/submodule/lookup.c +++ b/tests/submodule/lookup.c @@ -151,6 +151,29 @@ void test_submodule_lookup__lookup_even_with_missing_index(void) test_submodule_lookup__simple_lookup(); /* baseline should still pass */ } +void test_submodule_lookup__backslashes(void) +{ + git_config *cfg; + git_submodule *sm; + git_repository *subrepo; + git_buf buf = GIT_BUF_INIT; + const char *backslashed_path = "..\\submod2_target"; + + cl_git_pass(git_config_open_ondisk(&cfg, "submod2/.gitmodules")); + cl_git_pass(git_config_set_string(cfg, "submodule.sm_unchanged.url", backslashed_path)); + git_config_free(cfg); + + cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); + cl_assert_equal_s(backslashed_path, git_submodule_url(sm)); + cl_git_pass(git_submodule_open(&subrepo, sm)); + + cl_git_pass(git_submodule_resolve_url(&buf, g_repo, backslashed_path)); + + git_buf_free(&buf); + git_submodule_free(sm); + git_repository_free(subrepo); +} + static void baseline_tests(void) { /* small baseline that should work even if we change the index or make From 55bc135130d4601cdc3fd4fec4ad044c6c8ff5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 13 Jul 2015 09:08:32 +0200 Subject: [PATCH 15/29] submodule: normalize slashes in resolve_url Our path functions expect to work with slashes, so convert a path with backslashes into one with slashes at the top of the function. --- src/submodule.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/submodule.c b/src/submodule.c index 892c98304..3d028747f 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -781,11 +781,25 @@ const char *git_submodule_url(git_submodule *submodule) int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url) { int error = 0; + git_buf normalized = GIT_BUF_INIT; assert(out && repo && url); git_buf_sanitize(out); + if (strchr(url, '\\')) { + char *p; + if ((error = git_buf_puts(&normalized, url)) < 0) + return error; + + for (p = normalized.ptr; *p; p++) { + if (*p == '\\') + *p = '/'; + } + + url = normalized.ptr; + } + if (git_path_is_relative(url)) { if (!(error = get_url_base(out, repo))) error = git_path_apply_relative(out, url); @@ -796,6 +810,7 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur error = -1; } + git_buf_free(&normalized); return error; } From 2563101b4ff1b19e304fedb51ec0d2ac361e2522 Mon Sep 17 00:00:00 2001 From: Fallso Date: Tue, 14 Jul 2015 15:33:56 +0100 Subject: [PATCH 16/29] Fix macro redefinition warning --- src/thread-utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/thread-utils.c b/src/thread-utils.c index c3baf411a..dc9b2f09e 100644 --- a/src/thread-utils.c +++ b/src/thread-utils.c @@ -8,7 +8,9 @@ #include "thread-utils.h" #ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN +#endif # include #elif defined(hpux) || defined(__hpux) || defined(_hpux) # include From 555b3518966e396910e10adc6fa7d24b4a9955d0 Mon Sep 17 00:00:00 2001 From: Ryan Roden-Corrent Date: Mon, 20 Jul 2015 09:21:36 -0400 Subject: [PATCH 17/29] Document git_fetch_options struct and fix typo. git_fetch_options was missing from the API docs because it lacked a documentation comment above the struct declaration. I used the git_checkout_options docstring as a template. Also fixes a typo in git_remote_prune_refs (remote, not reamote). --- include/git2/remote.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index e47f00881..444fe5276 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -511,6 +511,14 @@ typedef enum { GIT_REMOTE_DOWNLOAD_TAGS_ALL, } git_remote_autotag_option_t; +/** + * Fetch options structure. + * + * Zero out for defaults. Initialize with `GIT_FETCH_OPTIONS_INIT` macro to + * correctly set the `version` field. E.g. + * + * git_fetch_options opts = GIT_FETCH_OPTIONS_INIT; + */ typedef struct { int version; @@ -739,7 +747,7 @@ GIT_EXTERN(int) git_remote_prune_refs(const git_remote *remote); * stored here for further processing by the caller. Always free this * strarray on successful return. * @param repo the repository in which to rename - * @param name the current name of the reamote + * @param name the current name of the remote * @param new_name the new name the remote should bear * @return 0, GIT_EINVALIDSPEC, GIT_EEXISTS or an error code */ From ac1a5e20b8bf9e2bd00ec1d38b1cc16f43d074f8 Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 21 Jul 2015 23:36:39 +0200 Subject: [PATCH 18/29] Make libgit2 work on Windows Vista again (fixes issue #3316) Signed-off-by: Sven Strickroth --- src/path.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/path.c b/src/path.c index 2558058dd..3e63f06d4 100644 --- a/src/path.c +++ b/src/path.c @@ -12,6 +12,7 @@ #include "win32/posix.h" #include "win32/buffer.h" #include "win32/w32_util.h" +#include "win32/version.h" #else #include #endif @@ -1085,7 +1086,7 @@ int git_path_direach( #if defined(GIT_WIN32) && !defined(__MINGW32__) /* Using _FIND_FIRST_EX_LARGE_FETCH may increase performance in Windows 7 - * and better. Prior versions will ignore this. + * and better. */ #ifndef FIND_FIRST_EX_LARGE_FETCH # define FIND_FIRST_EX_LARGE_FETCH 2 @@ -1099,6 +1100,10 @@ int git_path_diriter_init( git_win32_path path_filter; git_buf hack = {0}; + static int is_win7_or_later = -1; + if (is_win7_or_later < 0) + is_win7_or_later = git_has_win32_version(6, 1, 0); + assert(diriter && path); memset(diriter, 0, sizeof(git_path_diriter)); @@ -1122,11 +1127,11 @@ int git_path_diriter_init( diriter->handle = FindFirstFileExW( path_filter, - FindExInfoBasic, + is_win7_or_later ? FindExInfoBasic : FindExInfoStandard, &diriter->current, FindExSearchNameMatch, NULL, - FIND_FIRST_EX_LARGE_FETCH); + is_win7_or_later ? FIND_FIRST_EX_LARGE_FETCH : 0); if (diriter->handle == INVALID_HANDLE_VALUE) { giterr_set(GITERR_OS, "Could not open directory '%s'", path); From a4ded362b415f8b3d6beaa6b9699cf3322061b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 26 Jul 2015 17:19:22 +0200 Subject: [PATCH 19/29] iterator: skip over errors in diriter init An error here will typically mean that the directory was removed between the time we iterated the parent and the time we wanted to visit it in which case we should ignore it. Other kinds of errors such as permissions (or transient errors) also better dealt with by pretending we didn't see it. --- src/iterator.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/iterator.c b/src/iterator.c index a312afb3a..cf51a340d 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1027,8 +1027,11 @@ static int dirload_with_stat( strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ? git__strncasecmp : git__strncmp; - if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0) + /* Any error here is equivalent to the dir not existing, skip over it */ + if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0) { + error = GIT_ENOTFOUND; goto done; + } while ((error = git_path_diriter_next(&diriter)) == 0) { if ((error = git_path_diriter_fullpath(&path, &path_len, &diriter)) < 0) From c5d4317887da470c54174ae1248c527662c5a8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 27 Jul 2015 13:31:06 +0200 Subject: [PATCH 20/29] iterator: adjust unreadable-dir test to new behaviour We don't want the iterator to make us stop whenever we hit an unreadable dir. We should instead move over to the next item. --- tests/repo/iterator.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c index 26e8954fe..bb2d3a186 100644 --- a/tests/repo/iterator.c +++ b/tests/repo/iterator.c @@ -928,7 +928,7 @@ void test_repo_iterator__fs2(void) git_iterator_free(i); } -void test_repo_iterator__fs_preserves_error(void) +void test_repo_iterator__unreadable_dir(void) { git_iterator *i; const git_index_entry *e; @@ -951,10 +951,6 @@ void test_repo_iterator__fs_preserves_error(void) cl_git_pass(git_iterator_advance(&e, i)); /* a */ cl_git_fail(git_iterator_advance(&e, i)); /* b */ - cl_assert(giterr_last()); - cl_assert(giterr_last()->message != NULL); - /* skip 'c/' empty directory */ - cl_git_pass(git_iterator_advance(&e, i)); /* d */ cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&e, i)); cl_must_pass(p_chmod("empty_standard_repo/r/b", 0777)); From a91dff893141c2565db69c1d05909218773bc735 Mon Sep 17 00:00:00 2001 From: Anders Borum Date: Wed, 29 Jul 2015 22:23:00 +0200 Subject: [PATCH 21/29] case-insensitive check for WWW-Authenticate header Fixes issue #3338 --- src/transports/http.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transports/http.c b/src/transports/http.c index 1ed292be5..e3d90de11 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -255,7 +255,7 @@ static int on_header_ready(http_subtransport *t) GITERR_CHECK_ALLOC(t->content_type); } } - else if (!strcmp("WWW-Authenticate", git_buf_cstr(name))) { + else if (!strcasecmp("WWW-Authenticate", git_buf_cstr(name))) { char *dup = git__strdup(git_buf_cstr(value)); GITERR_CHECK_ALLOC(dup); From e5a7724969047686ce4695af9100809dec309244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 1 Aug 2015 15:38:04 +0200 Subject: [PATCH 22/29] Cherry-pick PR #3332: Resolve documentation warnings --- CMakeLists.txt | 1 + include/git2/repository.h | 2 +- include/git2/sys/config.h | 2 +- include/git2/sys/diff.h | 8 ++++---- include/git2/sys/odb_backend.h | 2 +- include/git2/sys/refdb_backend.h | 2 +- src/path.h | 2 +- src/push.h | 4 +++- 8 files changed, 13 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c55ddd1a..fc91dabfd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,6 +412,7 @@ ELSE () SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") ENDIF () + ADD_C_FLAG_IF_SUPPORTED(-Wdocumentation) ADD_C_FLAG_IF_SUPPORTED(-Wno-missing-field-initializers) ADD_C_FLAG_IF_SUPPORTED(-Wstrict-aliasing=2) ADD_C_FLAG_IF_SUPPORTED(-Wstrict-prototypes) diff --git a/include/git2/repository.h b/include/git2/repository.h index ce56fef0f..cf268ef85 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -745,7 +745,7 @@ GIT_EXTERN(int) git_repository_ident(const char **name, const char **email, cons * * @param repo the repository to configure * @param name the name to use for the reflog entries - * @param name the email to use for the reflog entries + * @param email the email to use for the reflog entries */ GIT_EXTERN(int) git_repository_set_ident(git_repository *repo, const char *name, const char *email); diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index b5b7df15f..044e34417 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -76,7 +76,7 @@ struct git_config_backend { * Initializes a `git_config_backend` with default values. Equivalent to * creating an instance with GIT_CONFIG_BACKEND_INIT. * - * @param opts the `git_config_backend` struct to initialize. + * @param backend the `git_config_backend` struct to initialize. * @param version Version of struct; pass `GIT_CONFIG_BACKEND_VERSION` * @return Zero on success; -1 on failure. */ diff --git a/include/git2/sys/diff.h b/include/git2/sys/diff.h index 034d5c478..aefd7b997 100644 --- a/include/git2/sys/diff.h +++ b/include/git2/sys/diff.h @@ -38,7 +38,7 @@ GIT_EXTERN(int) git_diff_print_callback__to_buf( const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, - void *payload); /*< payload must be a `git_buf *` */ + void *payload); /**< payload must be a `git_buf *` */ /** * Diff print callback that writes to stdio FILE handle. @@ -58,7 +58,7 @@ GIT_EXTERN(int) git_diff_print_callback__to_file_handle( const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, - void *payload); /*< payload must be a `FILE *` */ + void *payload); /**< payload must be a `FILE *` */ /** @@ -66,8 +66,8 @@ GIT_EXTERN(int) git_diff_print_callback__to_file_handle( */ typedef struct { unsigned int version; - size_t stat_calls; /*< Number of stat() calls performed */ - size_t oid_calculations; /*< Number of ID calculations */ + size_t stat_calls; /**< Number of stat() calls performed */ + size_t oid_calculations; /**< Number of ID calculations */ } git_diff_perfdata; #define GIT_DIFF_PERFDATA_VERSION 1 diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h index 0a51c6dba..fe102ff3c 100644 --- a/include/git2/sys/odb_backend.h +++ b/include/git2/sys/odb_backend.h @@ -93,7 +93,7 @@ struct git_odb_backend { * Initializes a `git_odb_backend` with default values. Equivalent to * creating an instance with GIT_ODB_BACKEND_INIT. * - * @param opts the `git_odb_backend` struct to initialize. + * @param backend the `git_odb_backend` struct to initialize. * @param version Version the struct; pass `GIT_ODB_BACKEND_VERSION` * @return Zero on success; -1 on failure. */ diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index d943e550f..8b004a7e0 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -175,7 +175,7 @@ struct git_refdb_backend { * Initializes a `git_refdb_backend` with default values. Equivalent to * creating an instance with GIT_REFDB_BACKEND_INIT. * - * @param opts the `git_refdb_backend` struct to initialize + * @param backend the `git_refdb_backend` struct to initialize * @param version Version of struct; pass `GIT_REFDB_BACKEND_VERSION` * @return Zero on success; -1 on failure. */ diff --git a/src/path.h b/src/path.h index 5927a5381..e6be06faa 100644 --- a/src/path.h +++ b/src/path.h @@ -319,7 +319,7 @@ extern int git_path_cmp( * @param callback Function to invoke on each path. Passed the `payload` * and the buffer containing the current path. The path should not * be modified in any way. Return non-zero to stop iteration. - * @param state Passed to fn as the first ath. + * @param payload Passed to fn as the first ath. */ extern int git_path_walk_up( git_buf *pathbuf, diff --git a/src/push.h b/src/push.h index 094f96ca9..a847ee0d0 100644 --- a/src/push.h +++ b/src/push.h @@ -83,7 +83,7 @@ int git_push_add_refspec(git_push *push, const char *refspec); * Update remote tips after a push * * @param push The push object - * @param signature The identity to use when updating reflogs + * @param callbacks the callbacks to use for this connection * * @return 0 or an error code */ @@ -100,6 +100,7 @@ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks); * order to find out which updates were accepted or rejected. * * @param push The push object + * @param callbacks the callbacks to use for this connection * * @return 0 or an error code */ @@ -117,6 +118,7 @@ int git_push_finish(git_push *push, const git_remote_callbacks *callbacks); * * @param push The push object * @param cb The callback to call on each object + * @param data The payload passed to the callback * * @return 0 on success, non-zero callback return value, or error code */ From a299d0af1bc752cd10a2b33d092dac02c99a5b95 Mon Sep 17 00:00:00 2001 From: Stefan Widgren Date: Fri, 31 Jul 2015 16:23:11 +0200 Subject: [PATCH 23/29] Remove extra semicolon outside of a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this change, compiling with gcc and pedantic generates warning: ISO C does not allow extra ‘;’ outside of a function. --- src/describe.c | 2 +- src/indexer.c | 2 +- src/pack-objects.c | 2 +- src/pack.c | 4 ++-- src/revwalk.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/describe.c b/src/describe.c index 5aea927c1..48f04e858 100644 --- a/src/describe.c +++ b/src/describe.c @@ -19,7 +19,7 @@ #include "vector.h" #include "repository.h" -GIT__USE_OIDMAP; +GIT__USE_OIDMAP /* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */ diff --git a/src/indexer.c b/src/indexer.c index 512addf48..9aa092556 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -18,7 +18,7 @@ #include "oidmap.h" #include "zstream.h" -GIT__USE_OIDMAP; +GIT__USE_OIDMAP extern git_mutex git__mwindow_mutex; diff --git a/src/pack-objects.c b/src/pack-objects.c index e287e3306..c4c061a3a 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -41,7 +41,7 @@ struct pack_write_context { git_transfer_progress *stats; }; -GIT__USE_OIDMAP; +GIT__USE_OIDMAP #ifdef GIT_THREADS diff --git a/src/pack.c b/src/pack.c index cd6526721..45dd4d5be 100644 --- a/src/pack.c +++ b/src/pack.c @@ -16,8 +16,8 @@ #include -GIT__USE_OFFMAP; -GIT__USE_OIDMAP; +GIT__USE_OFFMAP +GIT__USE_OIDMAP static int packfile_open(struct git_pack_file *p); static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n); diff --git a/src/revwalk.c b/src/revwalk.c index 6acc5d034..dcdd97915 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -14,7 +14,7 @@ #include "git2/revparse.h" #include "merge.h" -GIT__USE_OIDMAP; +GIT__USE_OIDMAP git_commit_list_node *git_revwalk__commit_lookup( git_revwalk *walk, const git_oid *oid) From 7483e08f1a2897ad85e8ed6f17ec5b34982e40dc Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 3 Aug 2015 07:38:07 +0100 Subject: [PATCH 24/29] Handle ssh:// and git:// urls containing a '~' character. For such a path '/~/...' the leading '/' is stripped so the server will get a path starting with '~' and correctly handle it. --- src/transports/git.c | 2 ++ src/transports/ssh.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/transports/git.c b/src/transports/git.c index 7e0a47414..52de92d09 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -50,6 +50,8 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) } repo = delim; + if (repo[1] == '~') + ++repo; delim = strchr(url, ':'); if (delim == NULL) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 83af137f8..e3792ebb3 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -66,6 +66,8 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) if (!git__prefixcmp(url, prefix_ssh)) { url = url + strlen(prefix_ssh); repo = strchr(url, '/'); + if (repo && repo[1] == '~') + ++repo; } else { repo = strchr(url, ':'); if (repo) repo++; From e874f3c1c0b64f6c88988305f889cbc97209a817 Mon Sep 17 00:00:00 2001 From: Tony Kelman Date: Sun, 5 Jul 2015 10:07:48 -0400 Subject: [PATCH 25/29] Increase required version of cmake to 2.8 --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fc91dabfd..4747818fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ # > cmake --build . --target install PROJECT(libgit2 C) -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) CMAKE_POLICY(SET CMP0015 NEW) # Add find modules to the path diff --git a/README.md b/README.md index 4ee1fdc2a..3191aeee2 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthrea they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API for threading. -The `libgit2` library is built using [CMake]() (version 2.6 or newer) on all platforms. +The `libgit2` library is built using [CMake]() (version 2.8 or newer) on all platforms. On most systems you can build the library using the following commands From adb8f8d0bc4ce505d72d1194c779fb7fa4ae23ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 24 Jul 2015 18:44:29 +0200 Subject: [PATCH 26/29] filebuf: failing test for leaving the lockfile when failing to rename When we fail to rename, we currently leave the lockfile laying around. This shows that behaviour. --- tests/core/filebuf.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/core/filebuf.c b/tests/core/filebuf.c index 5a3e7510f..9fd52b179 100644 --- a/tests/core/filebuf.c +++ b/tests/core/filebuf.c @@ -124,3 +124,30 @@ void test_core_filebuf__umask(void) cl_must_pass(p_unlink(test)); } +void test_core_filebuf__rename_error(void) +{ + git_filebuf file = GIT_FILEBUF_INIT; + char *dir = "subdir", *test = "subdir/test", *test_lock = "subdir/test.lock"; + int fd; + +#ifndef GIT_WIN32 + cl_skip(); +#endif + + cl_git_pass(p_mkdir(dir, 0666)); + cl_git_mkfile(test, "dummy content"); + fd = p_open(test, O_RDONLY); + cl_assert(fd > 0); + cl_git_pass(git_filebuf_open(&file, test, 0, 0666)); + + cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks")); + + cl_assert_equal_i(true, git_path_exists(test_lock)); + + cl_git_fail(git_filebuf_commit(&file)); + p_close(fd); + + git_filebuf_cleanup(&file); + cl_assert_equal_i(false, git_path_exists(test_lock)); + +} From 62a273ccbb40477a783410950be65aa18f147447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 24 Jul 2015 19:22:41 +0200 Subject: [PATCH 27/29] filebuf: remove lockfile upon rename errors When we have an error renaming the lockfile, we need to make sure that we remove it upon cleanup. For this, we need to keep track of whether we opened the file and whether the rename succeeded. If we did create the lockfile but the rename did not succeed, we remove the lockfile. This won't protect against all errors, but the most common ones (target file is open) does get handled. --- src/filebuf.c | 7 ++++++- src/filebuf.h | 2 ++ tests/core/filebuf.c | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/filebuf.c b/src/filebuf.c index 848ac343b..838f4b4d2 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -101,7 +101,7 @@ void git_filebuf_cleanup(git_filebuf *file) if (file->fd_is_open && file->fd >= 0) p_close(file->fd); - if (file->fd_is_open && file->path_lock && git_path_exists(file->path_lock)) + if (file->created_lock && !file->did_rename && file->path_lock && git_path_exists(file->path_lock)) p_unlink(file->path_lock); if (file->compute_digest) { @@ -258,6 +258,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode goto cleanup; } file->fd_is_open = true; + file->created_lock = true; /* No original path */ file->path_original = NULL; @@ -281,6 +282,8 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode /* open the file for locking */ if ((error = lock_file(file, flags, mode)) < 0) goto cleanup; + + file->created_lock = true; } return 0; @@ -340,6 +343,8 @@ int git_filebuf_commit(git_filebuf *file) goto on_error; } + file->did_rename = true; + git_filebuf_cleanup(file); return 0; diff --git a/src/filebuf.h b/src/filebuf.h index 2bd18dc35..f4d255b0a 100644 --- a/src/filebuf.h +++ b/src/filebuf.h @@ -44,6 +44,8 @@ struct git_filebuf { size_t buf_size, buf_pos; git_file fd; bool fd_is_open; + bool created_lock; + bool did_rename; bool do_not_buffer; int last_error; }; diff --git a/tests/core/filebuf.c b/tests/core/filebuf.c index 9fd52b179..3f7dc8569 100644 --- a/tests/core/filebuf.c +++ b/tests/core/filebuf.c @@ -148,6 +148,6 @@ void test_core_filebuf__rename_error(void) p_close(fd); git_filebuf_cleanup(&file); - cl_assert_equal_i(false, git_path_exists(test_lock)); + cl_assert_equal_i(false, git_path_exists(test_lock)); } From 16cee5d6350d5f64f6fdecc0e7562ec95f739a53 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 3 Aug 2015 08:17:47 -0500 Subject: [PATCH 28/29] Stage an unregistered submodule in _add_bypath() --- src/index.c | 63 ++++++++++++++++++++++++++++++++++++++++---- tests/index/bypath.c | 13 +++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/index.c b/src/index.c index 501498e9e..73f0b3d26 100644 --- a/src/index.c +++ b/src/index.c @@ -1228,6 +1228,45 @@ int git_index_add_frombuffer( return 0; } +static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path) +{ + git_repository *sub; + git_buf abspath = GIT_BUF_INIT; + git_repository *repo = INDEX_OWNER(index); + git_reference *head; + git_index_entry *entry; + struct stat st; + int error; + + if (index_entry_create(&entry, INDEX_OWNER(index), path) < 0) + return -1; + + if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0) + return error; + + if ((error = p_stat(abspath.ptr, &st)) < 0) { + giterr_set(GITERR_OS, "failed to stat repository dir"); + return -1; + } + + git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode); + + if ((error = git_repository_open(&sub, abspath.ptr)) < 0) + return error; + + if ((error = git_repository_head(&head, sub)) < 0) + return error; + + git_oid_cpy(&entry->id, git_reference_target(head)); + entry->mode = GIT_FILEMODE_COMMIT; + + git_reference_free(head); + git_repository_free(sub); + git_buf_free(&abspath); + + *out = entry; + return 0; +} int git_index_add_bypath(git_index *index, const char *path) { @@ -1252,12 +1291,26 @@ int git_index_add_bypath(git_index *index, const char *path) ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path); if (ret == GIT_ENOTFOUND) return giterr_restore(&err); - else - git__free(err.error_msg.message); - ret = git_submodule_add_to_index(sm, false); - git_submodule_free(sm); - return ret; + git__free(err.error_msg.message); + + /* + * EEXISTS means that there is a repository at that path, but it's not known + * as a submodule. We add its HEAD as an entry and don't register it. + */ + if (ret == GIT_EEXISTS) { + if ((ret = add_repo_as_submodule(&entry, index, path)) < 0) + return ret; + + if ((ret = index_insert(index, &entry, 1, false)) < 0) + return ret; + } else if (ret < 0) { + return ret; + } else { + ret = git_submodule_add_to_index(sm, false); + git_submodule_free(sm); + return ret; + } } /* Adding implies conflict was resolved, move conflict entries to REUC */ diff --git a/tests/index/bypath.c b/tests/index/bypath.c index ddb766a22..9706a8833 100644 --- a/tests/index/bypath.c +++ b/tests/index/bypath.c @@ -33,3 +33,16 @@ void test_index_bypath__add_submodule(void) cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0)); cl_assert_equal_i(0, status & GIT_SUBMODULE_STATUS_WD_MODIFIED); } + +void test_index_bypath__add_submodule_unregistered(void) +{ + const char *sm_name = "not-submodule"; + const char *sm_head = "68e92c611b80ee1ed8f38314ff9577f0d15b2444"; + const git_index_entry *entry; + + cl_git_pass(git_index_add_bypath(g_idx, sm_name)); + + cl_assert(entry = git_index_get_bypath(g_idx, sm_name, 0)); + cl_assert_equal_s(sm_head, git_oid_tostr_s(&entry->id)); + cl_assert_equal_s(sm_name, entry->path); +} From f6dedf2c2eb806e2a6fdd4cf31f68386efc2ee0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 3 Aug 2015 20:07:35 +0200 Subject: [PATCH 29/29] Bump version to v0.23.1 --- include/git2/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/version.h b/include/git2/version.h index 6837e90ef..3a091e788 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,10 +7,10 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.23.0" +#define LIBGIT2_VERSION "0.23.1" #define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MINOR 23 -#define LIBGIT2_VER_REVISION 0 +#define LIBGIT2_VER_REVISION 1 #define LIBGIT2_VER_PATCH 0 #define LIBGIT2_SOVERSION 23