summaryrefslogtreecommitdiff
path: root/entry.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2011-05-13 15:55:00 -0700
committerJunio C Hamano <gitster@pobox.com>2011-05-20 23:16:53 -0700
commitde6182db67d0f53fdc13256042014f2ddf5f8df3 (patch)
tree177d871672cea8c07f3cc2b6ef30fb8c36b09f08 /entry.c
parentb0d9c69f5ee4a626a779d27a33f5565efccd5802 (diff)
downloadgit-de6182db67d0f53fdc13256042014f2ddf5f8df3.tar.gz
streaming_write_entry(): support files with holes
One typical use of a large binary file is to hold a sparse on-disk hash table with a lot of holes. Help preserving the holes with lseek(). Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'entry.c')
-rw-r--r--entry.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/entry.c b/entry.c
index da37d01514..e2dc16c131 100644
--- a/entry.c
+++ b/entry.c
@@ -123,6 +123,7 @@ static int streaming_write_entry(struct cache_entry *ce, char *path,
enum object_type type;
unsigned long sz;
int result = -1;
+ ssize_t kept = 0;
int fd = -1;
st = open_istream(ce->sha1, &type, &sz);
@@ -136,18 +137,34 @@ static int streaming_write_entry(struct cache_entry *ce, char *path,
goto close_and_exit;
for (;;) {
- char buf[10240];
- ssize_t wrote;
+ char buf[1024 * 16];
+ ssize_t wrote, holeto;
ssize_t readlen = read_istream(st, buf, sizeof(buf));
if (!readlen)
break;
+ if (sizeof(buf) == readlen) {
+ for (holeto = 0; holeto < readlen; holeto++)
+ if (buf[holeto])
+ break;
+ if (readlen == holeto) {
+ kept += holeto;
+ continue;
+ }
+ }
+ if (kept && lseek(fd, kept, SEEK_CUR) == (off_t) -1)
+ goto close_and_exit;
+ else
+ kept = 0;
wrote = write_in_full(fd, buf, readlen);
if (wrote != readlen)
goto close_and_exit;
}
+ if (kept && (lseek(fd, kept - 1, SEEK_CUR) == (off_t) -1 ||
+ write(fd, "", 1) != 1))
+ goto close_and_exit;
*fstat_done = fstat_output(fd, state, statbuf);
close_and_exit: