summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2014-04-18 09:26:38 -0700
committerRussell Belfer <rb@github.com>2014-04-18 09:26:38 -0700
commit386777fd0dd7665a0aad65bf3589d7bf71024c0e (patch)
treeb7a300d76463cd7a4310d25f4179bc68729fcfcb
parent3c69bebc1c18444e9358c33f56c7cfefea4d1a8f (diff)
parent7be1caf7f54bff938c71a616f38e9ac375a0b137 (diff)
downloadlibgit2-386777fd0dd7665a0aad65bf3589d7bf71024c0e.tar.gz
Merge pull request #2213 from ethomson/safecrlf
Introduce core.safecrlf handling
-rw-r--r--src/config_cache.c1
-rw-r--r--src/crlf.c15
-rw-r--r--src/repository.h4
-rw-r--r--tests/filter/crlf.c80
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);
+}
+