commit - ce2bf7b7c9058374563c6db8608dbab9df2bba7d
commit + 6395114c60289f3ac0f28c0fc4b5dfcef8690cdf
blob - 4bac59b80e15c0c64099a61c98b1dd60cd3e01a4
blob + 280287ef843efeb4547446a984e2d924c66f9374
--- lib/pack.c
+++ lib/pack.c
const struct got_error *err = NULL;
struct got_delta *delta;
uint8_t *base_buf = NULL, *accum_buf = NULL, *delta_buf;
- size_t base_bufsz = 0, accum_size = 0, delta_len;
- uint64_t max_size;
+ size_t base_bufsz = 0, accum_bufsz = 0, accum_size = 0, delta_len;
+ /* We process small enough files entirely in memory for speed. */
+ const size_t max_bufsize = GOT_DELTA_RESULT_SIZE_CACHED_MAX;
+ uint64_t max_size = 0;
int n = 0;
*result_size = 0;
if (STAILQ_EMPTY(&deltas->entries))
return got_error(GOT_ERR_BAD_DELTA_CHAIN);
- /* We process small enough files entirely in memory for speed. */
- err = got_pack_get_delta_chain_max_size(&max_size, deltas, pack);
- if (err)
- return err;
- if (max_size < GOT_DELTA_RESULT_SIZE_CACHED_MAX) {
- accum_buf = malloc(max_size);
- if (accum_buf == NULL)
- return got_error_from_errno("malloc");
- base_file = NULL;
- accum_file = NULL;
- } else {
- if (fseeko(base_file, 0L, SEEK_SET) == -1)
- return got_error_from_errno("fseeko");
- if (fseeko(accum_file, 0L, SEEK_SET) == -1)
- return got_error_from_errno("fseeko");
- }
+ if (fseeko(base_file, 0L, SEEK_SET) == -1)
+ return got_error_from_errno("fseeko");
+ if (fseeko(accum_file, 0L, SEEK_SET) == -1)
+ return got_error_from_errno("fseeko");
/* Deltas are ordered in ascending order. */
STAILQ_FOREACH(delta, &deltas->entries, entry) {
+ uint64_t base_size, result_size = 0;
int cached = 1;
if (n == 0) {
size_t mapoff;
goto done;
}
}
- if (base_file) {
+ if (delta->size > max_size)
+ max_size = delta->size;
+ if (max_size > max_bufsize) {
if (pack->map) {
mapoff = (size_t)delta_data_offset;
err = got_inflate_to_file_mmap(
&base_bufsz, NULL, NULL, pack->fd,
base_file);
} else {
+ accum_buf = malloc(max_size);
+ if (accum_buf == NULL) {
+ err = got_error_from_errno("malloc");
+ goto done;
+ }
+ accum_bufsz = max_size;
if (pack->map) {
mapoff = (size_t)delta_data_offset;
err = got_inflate_to_mem_mmap(&base_buf,
if (err)
goto done;
n++;
- if (base_file)
+ if (base_buf == NULL)
rewind(base_file);
continue;
}
goto done;
}
}
+
+ err = got_delta_get_sizes(&base_size, &result_size,
+ delta_buf, delta_len);
+ if (err)
+ goto done;
+ if (base_size > max_size)
+ max_size = base_size;
+ if (result_size > max_size)
+ max_size = result_size;
+
+ if (base_buf && max_size > max_bufsize) {
+ /* Switch from buffers to temporary files. */
+ size_t w = fwrite(base_buf, 1, base_bufsz,
+ base_file);
+ if (w != base_bufsz) {
+ err = got_ferror(outfile, GOT_ERR_IO);
+ goto done;
+ }
+ free(base_buf);
+ base_buf = NULL;
+ free(accum_buf);
+ accum_buf = NULL;
+ }
+
+ if (base_buf && max_size > base_bufsz) {
+ uint8_t *p = realloc(base_buf, max_size);
+ if (p == NULL) {
+ err = got_error_from_errno("realloc");
+ goto done;
+ }
+ base_buf = p;
+ base_bufsz = max_size;
+ }
+
+ if (accum_buf && max_size > accum_bufsz) {
+ uint8_t *p = realloc(accum_buf, max_size);
+ if (p == NULL) {
+ err = got_error_from_errno("realloc");
+ goto done;
+ }
+ accum_buf = p;
+ accum_bufsz = max_size;
+ }
+
if (base_buf) {
err = got_delta_apply_in_mem(base_buf, base_bufsz,
delta_buf, delta_len, accum_buf,
/* Accumulated delta becomes the new base. */
if (base_buf) {
uint8_t *tmp = accum_buf;
- /*
- * Base buffer switches roles with accumulation
- * buffer. Ensure it can hold the largest
- * result in the delta chain. The initial
- * allocation might have been smaller.
- */
- if (base_bufsz < max_size) {
- uint8_t *p;
- p = reallocarray(base_buf, 1, max_size);
- if (p == NULL) {
- err = got_error_from_errno(
- "reallocarray");
- goto done;
- }
- base_buf = p;
- base_bufsz = max_size;
- }
+ size_t tmp_size = accum_bufsz;
accum_buf = base_buf;
+ accum_bufsz = base_bufsz;
base_buf = tmp;
+ base_bufsz = tmp_size;
} else {
FILE *tmp = accum_file;
accum_file = base_file;