From 6424c2ad12cf6c3feb533fab9c4dded7514d0f4c Mon Sep 17 00:00:00 2001 From: Jehan Bing Date: Mon, 20 Feb 2012 12:53:37 -0800 Subject: Ignore SIGPIPE when running a filter driver If a filter is not defined or if it fails, git should behave as if the filter is a no-op passthru. However, if the filter exits before reading all the content, depending on the timing, git could be killed with SIGPIPE when it tries to write to the pipe connected to the filter. Ignore SIGPIPE while processing the filter to give us a chance to check the return value from a failed write, in order to detect and act on this mode of failure in a more controlled way. Signed-off-by: Jehan Bing Signed-off-by: Junio C Hamano --- convert.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'convert.c') diff --git a/convert.c b/convert.c index 12868ed7bd..33373b3ac0 100644 --- a/convert.c +++ b/convert.c @@ -2,6 +2,7 @@ #include "attr.h" #include "run-command.h" #include "quote.h" +#include "sigchain.h" /* * convert.c - convert a file when checking it out and checking it in. @@ -360,12 +361,16 @@ static int filter_buffer(int in, int out, void *data) if (start_command(&child_process)) return error("cannot fork to run external filter %s", params->cmd); + sigchain_push(SIGPIPE, SIG_IGN); + write_err = (write_in_full(child_process.in, params->src, params->size) < 0); if (close(child_process.in)) write_err = 1; if (write_err) error("cannot feed the input to external filter %s", params->cmd); + sigchain_pop(SIGPIPE); + status = finish_command(&child_process); if (status) error("external filter %s failed %d", params->cmd, status); -- cgit v1.2.3 From 92ac3197e4859ba8c19e3e7f7b8cf5dc38e4669d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 24 Feb 2012 17:02:37 -0500 Subject: teach convert_to_git a "dry run" mode Some callers may want to know whether convert_to_git will actually do anything before performing the conversion itself (e.g., to decide whether to stream or handle blobs in-core). This patch lets callers specify the dry run mode by passing a NULL destination buffer. The return value, instead of indicating whether conversion happened, will indicate whether conversion would occur. For readability, we also include a wrapper function which makes it more obvious we are not actually performing the conversion. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- convert.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'convert.c') diff --git a/convert.c b/convert.c index 12868ed7bd..65fa9d5eda 100644 --- a/convert.c +++ b/convert.c @@ -231,6 +231,13 @@ static int crlf_to_git(const char *path, const char *src, size_t len, if (!stats.cr) return 0; + /* + * At this point all of our source analysis is done, and we are sure we + * would convert. If we are in dry-run mode, we can give an answer. + */ + if (!buf) + return 1; + /* only grow if not in place */ if (strbuf_avail(buf) + buf->len < len) strbuf_grow(buf, len - buf->len); @@ -391,6 +398,9 @@ static int apply_filter(const char *path, const char *src, size_t len, if (!cmd) return 0; + if (!dst) + return 1; + memset(&async, 0, sizeof(async)); async.proc = filter_buffer; async.data = ¶ms; @@ -525,6 +535,9 @@ static int ident_to_git(const char *path, const char *src, size_t len, if (!ident || !count_ident(src, len)) return 0; + if (!buf) + return 1; + /* only grow if not in place */ if (strbuf_avail(buf) + buf->len < len) strbuf_grow(buf, len - buf->len); @@ -754,13 +767,13 @@ int convert_to_git(const char *path, const char *src, size_t len, filter = ca.drv->clean; ret |= apply_filter(path, src, len, dst, filter); - if (ret) { + if (ret && dst) { src = dst->buf; len = dst->len; } ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr); ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe); - if (ret) { + if (ret && dst) { src = dst->buf; len = dst->len; } -- cgit v1.2.3 From 4c3b57b98bccfdb740b8f1d0ca574dd51deacfad Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 24 Feb 2012 17:05:03 -0500 Subject: teach dry-run convert_to_git not to require a src buffer When we call convert_to_git in dry-run mode, it may still want to look at the source buffer, because some CRLF conversion modes depend on analyzing the source to determine whether it is in fact convertible CRLF text. However, the main motivation for convert_to_git's dry-run mode is that we would decide which method to use to acquire the blob's data (streaming versus in-core). Requiring this source analysis creates a chicken-and-egg problem. We are better off simply guessing that anything we can't analyze will end up needing conversion. This patch lets a caller specify a NULL src buffer when using dry-run mode (and only dry-run mode). A non-zero return value goes from "we would convert" to "we might convert"; a zero return value remains "we would definitely not convert". Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- convert.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'convert.c') diff --git a/convert.c b/convert.c index 65fa9d5eda..aa7f72d8a0 100644 --- a/convert.c +++ b/convert.c @@ -195,9 +195,17 @@ static int crlf_to_git(const char *path, const char *src, size_t len, char *dst; if (crlf_action == CRLF_BINARY || - (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || !len) + (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || + (src && !len)) return 0; + /* + * If we are doing a dry-run and have no source buffer, there is + * nothing to analyze; we must assume we would convert. + */ + if (!buf && !src) + return 1; + gather_stats(src, len, &stats); if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) { @@ -532,7 +540,7 @@ static int ident_to_git(const char *path, const char *src, size_t len, { char *dst, *dollar; - if (!ident || !count_ident(src, len)) + if (!ident || (src && !count_ident(src, len))) return 0; if (!buf) -- cgit v1.2.3