Skip to content

Commit ddaf4e2

Browse files
committed
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
2 parents 5bf6668 + 0c4dd67 commit ddaf4e2

File tree

5 files changed

+32
-8
lines changed

5 files changed

+32
-8
lines changed

cache.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,9 +1541,13 @@ extern const char *git_mailmap_blob;
15411541
extern void maybe_flush_or_die(FILE *, const char *);
15421542
__attribute__((format (printf, 2, 3)))
15431543
extern void fprintf_or_die(FILE *, const char *fmt, ...);
1544+
1545+
#define COPY_READ_ERROR (-2)
1546+
#define COPY_WRITE_ERROR (-3)
15441547
extern int copy_fd(int ifd, int ofd);
15451548
extern int copy_file(const char *dst, const char *src, int mode);
15461549
extern int copy_file_with_time(const char *dst, const char *src, int mode);
1550+
15471551
extern void write_or_die(int fd, const void *buf, size_t count);
15481552
extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
15491553
extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);

convert.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,14 @@ static int filter_buffer_or_fd(int in, int out, void *data)
356356
sigchain_push(SIGPIPE, SIG_IGN);
357357

358358
if (params->src) {
359-
write_err = (write_in_full(child_process.in, params->src, params->size) < 0);
359+
write_err = (write_in_full(child_process.in,
360+
params->src, params->size) < 0);
361+
if (errno == EPIPE)
362+
write_err = 0;
360363
} else {
361364
write_err = copy_fd(params->fd, child_process.in);
365+
if (write_err == COPY_WRITE_ERROR && errno == EPIPE)
366+
write_err = 0;
362367
}
363368

364369
if (close(child_process.in))

copy.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,10 @@ int copy_fd(int ifd, int ofd)
77
ssize_t len = xread(ifd, buffer, sizeof(buffer));
88
if (!len)
99
break;
10-
if (len < 0) {
11-
return error("copy-fd: read returned %s",
12-
strerror(errno));
13-
}
10+
if (len < 0)
11+
return COPY_READ_ERROR;
1412
if (write_in_full(ofd, buffer, len) < 0)
15-
return error("copy-fd: write returned %s",
16-
strerror(errno));
13+
return COPY_WRITE_ERROR;
1714
}
1815
return 0;
1916
}
@@ -43,6 +40,14 @@ int copy_file(const char *dst, const char *src, int mode)
4340
return fdo;
4441
}
4542
status = copy_fd(fdi, fdo);
43+
switch (status) {
44+
case COPY_READ_ERROR:
45+
error("copy-fd: read returned %s", strerror(errno));
46+
break;
47+
case COPY_WRITE_ERROR:
48+
error("copy-fd: write returned %s", strerror(errno));
49+
break;
50+
}
4651
close(fdi);
4752
if (close(fdo) != 0)
4853
return error("%s: close error: %s", dst, strerror(errno));

lockfile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
289289
int save_errno = errno;
290290

291291
if (flags & LOCK_DIE_ON_ERROR)
292-
exit(128);
292+
die("failed to prepare '%s' for appending", path);
293293
close(orig_fd);
294294
rollback_lock_file(lk);
295295
errno = save_errno;

t/t0021-conversion.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,16 @@ test_expect_success 'filtering large input to small output should use little mem
204204
GIT_MMAP_LIMIT=1m GIT_ALLOC_LIMIT=1m git add 30MB
205205
'
206206

207+
test_expect_success 'filter that does not read is fine' '
208+
test-genrandom foo $((128 * 1024 + 1)) >big &&
209+
echo "big filter=epipe" >.gitattributes &&
210+
git config filter.epipe.clean "echo xyzzy" &&
211+
git add big &&
212+
git cat-file blob :big >actual &&
213+
echo xyzzy >expect &&
214+
test_cmp expect actual
215+
'
216+
207217
test_expect_success EXPENSIVE 'filter large file' '
208218
git config filter.largefile.smudge cat &&
209219
git config filter.largefile.clean cat &&

0 commit comments

Comments
 (0)