Commit 5a76ad35 by Carlos Martín Nieto

crlf: pass-through mixed EOL buffers from LF->CRLF

When checking out files, we're performing conversion into the user's
native line endings, but we only want to do it for files which have
consistent line endings. Refuse to perform the conversion for mixed-EOL
files.

The CRLF->LF filter is left as-is, as that conversion is considered to be
normalization by git and should force a conversion of the line endings.
parent 1589aa0c
...@@ -123,9 +123,13 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) ...@@ -123,9 +123,13 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) { for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) {
size_t copylen = next - scan; size_t copylen = next - scan;
/* don't convert existing \r\n to \r\r\n */ size_t needsize = tgt->size + copylen + 2 + 1;
size_t extralen = (next > start && next[-1] == '\r') ? 1 : 2;
size_t needsize = tgt->size + copylen + extralen + 1; /* if we find mixed line endings, bail */
if (next > start && next[-1] == '\r') {
git_buf_free(tgt);
return GIT_PASSTHROUGH;
}
if (tgt->asize < needsize && git_buf_grow(tgt, needsize) < 0) if (tgt->asize < needsize && git_buf_grow(tgt, needsize) < 0)
return -1; return -1;
...@@ -134,8 +138,8 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src) ...@@ -134,8 +138,8 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
memcpy(tgt->ptr + tgt->size, scan, copylen); memcpy(tgt->ptr + tgt->size, scan, copylen);
tgt->size += copylen; tgt->size += copylen;
} }
if (extralen == 2)
tgt->ptr[tgt->size++] = '\r'; tgt->ptr[tgt->size++] = '\r';
tgt->ptr[tgt->size++] = '\n'; tgt->ptr[tgt->size++] = '\n';
} }
......
...@@ -56,9 +56,10 @@ GIT_INLINE(int) git_buf_text_puts_escape_regex(git_buf *buf, const char *string) ...@@ -56,9 +56,10 @@ GIT_INLINE(int) git_buf_text_puts_escape_regex(git_buf *buf, const char *string)
extern void git_buf_text_unescape(git_buf *buf); extern void git_buf_text_unescape(git_buf *buf);
/** /**
* Replace all \r\n with \n. Does not modify \r without trailing \n. * Replace all \r\n with \n.
* *
* @return 0 on success, -1 on memory error * @return 0 on success, -1 on memory error, GIT_PASSTHROUGH if the
* source buffer has mixed line endings.
*/ */
extern int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src); extern int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src);
......
...@@ -79,10 +79,7 @@ void test_checkout_crlf__more_lf_autocrlf_true(void) ...@@ -79,10 +79,7 @@ void test_checkout_crlf__more_lf_autocrlf_true(void)
git_checkout_head(g_repo, &opts); git_checkout_head(g_repo, &opts);
if (GIT_EOL_NATIVE == GIT_EOL_LF) check_file_contents("./crlf/more-lf", MORE_LF_TEXT_RAW);
check_file_contents("./crlf/more-lf", MORE_LF_TEXT_RAW);
else
check_file_contents("./crlf/more-lf", MORE_LF_TEXT_AS_CRLF);
} }
void test_checkout_crlf__more_crlf_autocrlf_true(void) void test_checkout_crlf__more_crlf_autocrlf_true(void)
...@@ -94,10 +91,7 @@ void test_checkout_crlf__more_crlf_autocrlf_true(void) ...@@ -94,10 +91,7 @@ void test_checkout_crlf__more_crlf_autocrlf_true(void)
git_checkout_head(g_repo, &opts); git_checkout_head(g_repo, &opts);
if (GIT_EOL_NATIVE == GIT_EOL_LF) check_file_contents("./crlf/more-crlf", MORE_CRLF_TEXT_RAW);
check_file_contents("./crlf/more-crlf", MORE_CRLF_TEXT_RAW);
else
check_file_contents("./crlf/more-crlf", MORE_CRLF_TEXT_AS_CRLF);
} }
void test_checkout_crlf__all_crlf_autocrlf_true(void) void test_checkout_crlf__all_crlf_autocrlf_true(void)
......
...@@ -1034,18 +1034,14 @@ void test_core_buffer__lf_and_crlf_conversions(void) ...@@ -1034,18 +1034,14 @@ void test_core_buffer__lf_and_crlf_conversions(void)
git_buf_sets(&src, "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n"); git_buf_sets(&src, "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n");
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_fail_with(GIT_PASSTHROUGH, git_buf_text_lf_to_crlf(&tgt, &src));
check_buf("crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n", tgt);
check_buf(src.ptr, tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf("crlf\ncrlf\ncrlf\ncrlf\n", tgt); check_buf("crlf\ncrlf\ncrlf\ncrlf\n", tgt);
git_buf_sets(&src, "\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf"); git_buf_sets(&src, "\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf");
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_fail_with(GIT_PASSTHROUGH, git_buf_text_lf_to_crlf(&tgt, &src));
check_buf("\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf", tgt);
check_buf(src.ptr, tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf("\ncrlf\ncrlf\ncrlf\ncrlf\ncrlf", tgt); check_buf("\ncrlf\ncrlf\ncrlf\ncrlf\ncrlf", tgt);
...@@ -1054,8 +1050,7 @@ void test_core_buffer__lf_and_crlf_conversions(void) ...@@ -1054,8 +1050,7 @@ void test_core_buffer__lf_and_crlf_conversions(void)
git_buf_sets(&src, "\nlf\nlf\ncrlf\r\nlf\nlf\ncrlf\r\n"); git_buf_sets(&src, "\nlf\nlf\ncrlf\r\nlf\nlf\ncrlf\r\n");
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_fail_with(GIT_PASSTHROUGH, git_buf_text_lf_to_crlf(&tgt, &src));
check_buf("\r\nlf\r\nlf\r\ncrlf\r\nlf\r\nlf\r\ncrlf\r\n", tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf("\nlf\nlf\ncrlf\nlf\nlf\ncrlf\n", tgt); check_buf("\nlf\nlf\ncrlf\nlf\nlf\ncrlf\n", tgt);
...@@ -1063,8 +1058,7 @@ void test_core_buffer__lf_and_crlf_conversions(void) ...@@ -1063,8 +1058,7 @@ void test_core_buffer__lf_and_crlf_conversions(void)
git_buf_sets(&src, "\ncrlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf"); git_buf_sets(&src, "\ncrlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf");
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_fail_with(GIT_PASSTHROUGH, git_buf_text_lf_to_crlf(&tgt, &src));
check_buf("\r\ncrlf\r\ncrlf\r\nlf\r\ncrlf\r\ncrlf", tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf("\ncrlf\ncrlf\nlf\ncrlf\ncrlf", tgt); check_buf("\ncrlf\ncrlf\nlf\ncrlf\ncrlf", tgt);
...@@ -1072,8 +1066,7 @@ void test_core_buffer__lf_and_crlf_conversions(void) ...@@ -1072,8 +1066,7 @@ void test_core_buffer__lf_and_crlf_conversions(void)
git_buf_sets(&src, "\rcrlf\r\nlf\nlf\ncr\rcrlf\r\nlf\ncr\r"); git_buf_sets(&src, "\rcrlf\r\nlf\nlf\ncr\rcrlf\r\nlf\ncr\r");
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_fail_with(GIT_PASSTHROUGH, git_buf_text_lf_to_crlf(&tgt, &src));
check_buf("\rcrlf\r\nlf\r\nlf\r\ncr\rcrlf\r\nlf\r\ncr\r", tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf("\rcrlf\nlf\nlf\ncr\rcrlf\nlf\ncr\r", tgt); check_buf("\rcrlf\nlf\nlf\ncr\rcrlf\nlf\ncr\r", tgt);
...@@ -1089,8 +1082,7 @@ void test_core_buffer__lf_and_crlf_conversions(void) ...@@ -1089,8 +1082,7 @@ void test_core_buffer__lf_and_crlf_conversions(void)
/* blob correspondence tests */ /* blob correspondence tests */
git_buf_sets(&src, ALL_CRLF_TEXT_RAW); git_buf_sets(&src, ALL_CRLF_TEXT_RAW);
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_fail_with(GIT_PASSTHROUGH, git_buf_text_lf_to_crlf(&tgt, &src));
check_buf(ALL_CRLF_TEXT_AS_CRLF, tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf(ALL_CRLF_TEXT_AS_LF, tgt); check_buf(ALL_CRLF_TEXT_AS_LF, tgt);
git_buf_free(&src); git_buf_free(&src);
...@@ -1105,16 +1097,14 @@ void test_core_buffer__lf_and_crlf_conversions(void) ...@@ -1105,16 +1097,14 @@ void test_core_buffer__lf_and_crlf_conversions(void)
git_buf_free(&tgt); git_buf_free(&tgt);
git_buf_sets(&src, MORE_CRLF_TEXT_RAW); git_buf_sets(&src, MORE_CRLF_TEXT_RAW);
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_fail_with(GIT_PASSTHROUGH, git_buf_text_lf_to_crlf(&tgt, &src));
check_buf(MORE_CRLF_TEXT_AS_CRLF, tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf(MORE_CRLF_TEXT_AS_LF, tgt); check_buf(MORE_CRLF_TEXT_AS_LF, tgt);
git_buf_free(&src); git_buf_free(&src);
git_buf_free(&tgt); git_buf_free(&tgt);
git_buf_sets(&src, MORE_LF_TEXT_RAW); git_buf_sets(&src, MORE_LF_TEXT_RAW);
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src)); cl_git_fail_with(GIT_PASSTHROUGH, git_buf_text_lf_to_crlf(&tgt, &src));
check_buf(MORE_LF_TEXT_AS_CRLF, tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src)); cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf(MORE_LF_TEXT_AS_LF, tgt); check_buf(MORE_LF_TEXT_AS_LF, tgt);
git_buf_free(&src); git_buf_free(&src);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment