diff options
author | Junio C Hamano <gitster@pobox.com> | 2015-05-22 12:41:57 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-05-22 12:41:57 -0700 |
commit | ddaf4e2e9a8b38185405205ddead638cf052728e (patch) | |
tree | 67c406d62df91a583c2a7a34af92c1317e6b966f | |
parent | Merge branch 'mh/clone-verbosity-fix' (diff) | |
parent | filter_buffer_or_fd(): ignore EPIPE (diff) | |
download | tgif-ddaf4e2e9a8b38185405205ddead638cf052728e.tar.xz |
Merge branch 'jc/ignore-epipe-in-filter'
Filter scripts were run with SIGPIPE disabled on the Git side,
expecting that they may not read what Git feeds them to filter.
We however treated a filter that does not read its input fully
before exiting as an error.
This changes semantics, but arguably in a good way. If a filter
can produce its output without consuming its input using whatever
magic, we now let it do so, instead of diagnosing it as a
programming error.
* jc/ignore-epipe-in-filter:
filter_buffer_or_fd(): ignore EPIPE
copy.c: make copy_fd() report its status silently
-rw-r--r-- | cache.h | 4 | ||||
-rw-r--r-- | convert.c | 7 | ||||
-rw-r--r-- | copy.c | 17 | ||||
-rw-r--r-- | lockfile.c | 2 | ||||
-rwxr-xr-x | t/t0021-conversion.sh | 10 |
5 files changed, 32 insertions, 8 deletions
@@ -1541,9 +1541,13 @@ extern const char *git_mailmap_blob; extern void maybe_flush_or_die(FILE *, const char *); __attribute__((format (printf, 2, 3))) extern void fprintf_or_die(FILE *, const char *fmt, ...); + +#define COPY_READ_ERROR (-2) +#define COPY_WRITE_ERROR (-3) extern int copy_fd(int ifd, int ofd); extern int copy_file(const char *dst, const char *src, int mode); extern int copy_file_with_time(const char *dst, const char *src, int mode); + extern void write_or_die(int fd, const void *buf, size_t count); extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg); extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg); @@ -356,9 +356,14 @@ static int filter_buffer_or_fd(int in, int out, void *data) sigchain_push(SIGPIPE, SIG_IGN); if (params->src) { - write_err = (write_in_full(child_process.in, params->src, params->size) < 0); + write_err = (write_in_full(child_process.in, + params->src, params->size) < 0); + if (errno == EPIPE) + write_err = 0; } else { write_err = copy_fd(params->fd, child_process.in); + if (write_err == COPY_WRITE_ERROR && errno == EPIPE) + write_err = 0; } if (close(child_process.in)) @@ -7,13 +7,10 @@ int copy_fd(int ifd, int ofd) ssize_t len = xread(ifd, buffer, sizeof(buffer)); if (!len) break; - if (len < 0) { - return error("copy-fd: read returned %s", - strerror(errno)); - } + if (len < 0) + return COPY_READ_ERROR; if (write_in_full(ofd, buffer, len) < 0) - return error("copy-fd: write returned %s", - strerror(errno)); + return COPY_WRITE_ERROR; } return 0; } @@ -43,6 +40,14 @@ int copy_file(const char *dst, const char *src, int mode) return fdo; } status = copy_fd(fdi, fdo); + switch (status) { + case COPY_READ_ERROR: + error("copy-fd: read returned %s", strerror(errno)); + break; + case COPY_WRITE_ERROR: + error("copy-fd: write returned %s", strerror(errno)); + break; + } close(fdi); if (close(fdo) != 0) return error("%s: close error: %s", dst, strerror(errno)); diff --git a/lockfile.c b/lockfile.c index 30e65e9d22..5a93bc7bc2 100644 --- a/lockfile.c +++ b/lockfile.c @@ -289,7 +289,7 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags) int save_errno = errno; if (flags & LOCK_DIE_ON_ERROR) - exit(128); + die("failed to prepare '%s' for appending", path); close(orig_fd); rollback_lock_file(lk); errno = save_errno; diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index ca7d2a630a..e0200b9f33 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -204,6 +204,16 @@ test_expect_success 'filtering large input to small output should use little mem GIT_MMAP_LIMIT=1m GIT_ALLOC_LIMIT=1m git add 30MB ' +test_expect_success 'filter that does not read is fine' ' + test-genrandom foo $((128 * 1024 + 1)) >big && + echo "big filter=epipe" >.gitattributes && + git config filter.epipe.clean "echo xyzzy" && + git add big && + git cat-file blob :big >actual && + echo xyzzy >expect && + test_cmp expect actual +' + test_expect_success EXPENSIVE 'filter large file' ' git config filter.largefile.smudge cat && git config filter.largefile.clean cat && |