diff options
author | Russell Belfer <rb@github.com> | 2014-04-18 09:26:38 -0700 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2014-04-18 09:26:38 -0700 |
commit | 386777fd0dd7665a0aad65bf3589d7bf71024c0e (patch) | |
tree | b7a300d76463cd7a4310d25f4179bc68729fcfcb | |
parent | 3c69bebc1c18444e9358c33f56c7cfefea4d1a8f (diff) | |
parent | 7be1caf7f54bff938c71a616f38e9ac375a0b137 (diff) | |
download | libgit2-386777fd0dd7665a0aad65bf3589d7bf71024c0e.tar.gz |
Merge pull request #2213 from ethomson/safecrlf
Introduce core.safecrlf handling
-rw-r--r-- | src/config_cache.c | 1 | ||||
-rw-r--r-- | src/crlf.c | 15 | ||||
-rw-r--r-- | src/repository.h | 4 | ||||
-rw-r--r-- | tests/filter/crlf.c | 80 |
4 files changed, 99 insertions, 1 deletions
diff --git a/src/config_cache.c b/src/config_cache.c index ec75d1501..4bcbf02bf 100644 --- a/src/config_cache.c +++ b/src/config_cache.c @@ -68,6 +68,7 @@ static struct map_data _cvar_maps[] = { {"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT }, {"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT }, {"core.precomposeunicode", NULL, 0, GIT_PRECOMPOSE_DEFAULT }, + {"core.safecrlf", NULL, 0, GIT_SAFE_CRLF_DEFAULT}, }; int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) diff --git a/src/crlf.c b/src/crlf.c index 2480cc918..8be1b9a05 100644 --- a/src/crlf.c +++ b/src/crlf.c @@ -21,6 +21,7 @@ struct crlf_attrs { int crlf_action; int eol; int auto_crlf; + int safe_crlf; }; struct crlf_filter { @@ -137,6 +138,13 @@ static int crlf_apply_to_odb( if (git_buf_text_gather_stats(&stats, from, false)) return GIT_PASSTHROUGH; + /* If safecrlf is enabled, sanity-check the result. */ + if (ca->safe_crlf && (stats.cr != stats.crlf || stats.lf != stats.crlf)) { + giterr_set(GITERR_FILTER, "LF would be replaced by CRLF in '%s'", + git_filter_source_path(src)); + return -1; + } + /* * We're currently not going to even try to convert stuff * that has bare CR characters. Does anybody do that crazy @@ -272,6 +280,13 @@ static int crlf_check( return GIT_PASSTHROUGH; } + if (git_filter_source_mode(src) == GIT_FILTER_CLEAN) { + error = git_repository__cvar( + &ca.safe_crlf, git_filter_source_repo(src), GIT_CVAR_SAFE_CRLF); + if (error < 0) + return error; + } + *payload = git__malloc(sizeof(ca)); GITERR_CHECK_ALLOC(*payload); memcpy(*payload, &ca, sizeof(ca)); diff --git a/src/repository.h b/src/repository.h index 86db488fd..27eec9dd8 100644 --- a/src/repository.h +++ b/src/repository.h @@ -38,6 +38,7 @@ typedef enum { GIT_CVAR_TRUSTCTIME, /* core.trustctime */ GIT_CVAR_ABBREV, /* core.abbrev */ GIT_CVAR_PRECOMPOSE, /* core.precomposeunicode */ + GIT_CVAR_SAFE_CRLF, /* core.safecrlf */ GIT_CVAR_CACHE_MAX } git_cvar_cached; @@ -89,7 +90,8 @@ typedef enum { GIT_ABBREV_DEFAULT = 7, /* core.precomposeunicode */ GIT_PRECOMPOSE_DEFAULT = GIT_CVAR_FALSE, - + /* core.safecrlf */ + GIT_SAFE_CRLF_DEFAULT = GIT_CVAR_FALSE, } git_cvar_value; /* internal repository init flags */ diff --git a/tests/filter/crlf.c b/tests/filter/crlf.c index c9fb9cd7f..75320efee 100644 --- a/tests/filter/crlf.c +++ b/tests/filter/crlf.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "git2/sys/filter.h" +#include "buffer.h" static git_repository *g_repo = NULL; @@ -69,3 +70,82 @@ void test_filter_crlf__to_odb(void) git_filter_list_free(fl); git_buf_free(&out); } + +void test_filter_crlf__with_safecrlf(void) +{ + git_filter_list *fl; + git_filter *crlf; + git_buf in = {0}, out = GIT_BUF_INIT; + + cl_repo_set_bool(g_repo, "core.safecrlf", true); + + cl_git_pass(git_filter_list_new(&fl, g_repo, GIT_FILTER_TO_ODB)); + + crlf = git_filter_lookup(GIT_FILTER_CRLF); + cl_assert(crlf != NULL); + + cl_git_pass(git_filter_list_push(fl, crlf, NULL)); + + /* Normalized \r\n succeeds with safecrlf */ + in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n"; + in.size = strlen(in.ptr); + + cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); + cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr); + + /* Mix of line endings fails with safecrlf */ + in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n"; + in.size = strlen(in.ptr); + + cl_git_fail(git_filter_list_apply_to_data(&out, fl, &in)); + cl_assert_equal_i(giterr_last()->klass, GITERR_FILTER); + + /* Normalized \n fails with safecrlf */ + in.ptr = "Normal\nLF\nonly\nline-endings.\n"; + in.size = strlen(in.ptr); + + cl_git_fail(git_filter_list_apply_to_data(&out, fl, &in)); + cl_assert_equal_i(giterr_last()->klass, GITERR_FILTER); + + git_filter_list_free(fl); + git_buf_free(&out); +} + +void test_filter_crlf__no_safecrlf(void) +{ + git_filter_list *fl; + git_filter *crlf; + git_buf in = {0}, out = GIT_BUF_INIT; + + cl_git_pass(git_filter_list_new(&fl, g_repo, GIT_FILTER_TO_ODB)); + + crlf = git_filter_lookup(GIT_FILTER_CRLF); + cl_assert(crlf != NULL); + + cl_git_pass(git_filter_list_push(fl, crlf, NULL)); + + /* Normalized \r\n succeeds with safecrlf */ + in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n"; + in.size = strlen(in.ptr); + + cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); + cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr); + + /* Mix of line endings fails with safecrlf */ + in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n"; + in.size = strlen(in.ptr); + + cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); + cl_assert_equal_s("Mixed\nup\nLF\nand\nCRLF\nline-endings.\n", out.ptr); + + /* Normalized \n fails with safecrlf */ + in.ptr = "Normal\nLF\nonly\nline-endings.\n"; + in.size = strlen(in.ptr); + + cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); + cl_assert_equal_s("Normal\nLF\nonly\nline-endings.\n", out.ptr); + + git_filter_list_free(fl); + git_buf_free(&out); +} + |