commit - 1cc8e7f9595db4aa8d3e79361376d1a0e7064635
commit + 8628c62d73b92bfe39c6a8ec4d5a85f8a6fb662d
blob - 8b8243244f2258d9a028e56b322c67023310b69e
blob + c187dc31fb4d77d7908a8334c2dc1a939230168d
--- lib/delta.c
+++ lib/delta.c
p = delta_buf;
remain = delta_len;
return parse_delta_sizes(base_size, result_size, &p, &remain);
+}
+
+const struct got_error *
+got_delta_apply_in_mem(uint8_t *base_buf, const uint8_t *delta_buf,
+ size_t delta_len, uint8_t *outbuf, size_t *outsize)
+{
+ const struct got_error *err = NULL;
+ uint64_t base_size, result_size;
+ size_t remain;
+ const uint8_t *p;
+
+ *outsize= 0;
+
+ if (delta_len < GOT_DELTA_STREAM_LENGTH_MIN)
+ return got_error(GOT_ERR_BAD_DELTA);
+
+ p = delta_buf;
+ remain = delta_len;
+ err = parse_delta_sizes(&base_size, &result_size, &p, &remain);
+ if (err)
+ return err;
+
+ /* Decode and execute copy instructions from the delta stream. */
+ err = next_delta_byte(&p, &remain);
+ while (err == NULL && remain > 0) {
+ if (*p & GOT_DELTA_BASE_COPY) {
+ off_t offset = 0;
+ size_t len = 0;
+ err = parse_opcode(&offset, &len, &p, &remain);
+ if (err)
+ break;
+ memcpy(outbuf + *outsize, base_buf + offset, len);
+ if (err == NULL) {
+ *outsize += len;
+ if (remain > 0) {
+ p++;
+ remain--;
+ }
+ }
+ } else {
+ size_t len = (size_t)*p;
+ if (len == 0) {
+ err = got_error(GOT_ERR_BAD_DELTA);
+ break;
+ }
+ err = next_delta_byte(&p, &remain);
+ if (err)
+ break;
+ if (remain < len)
+ return got_error(GOT_ERR_BAD_DELTA);
+ memcpy(outbuf + *outsize, p, len);
+ p += len;
+ remain -= len;
+ *outsize += len;
+ }
+ }
+
+ if (*outsize != result_size)
+ err = got_error(GOT_ERR_BAD_DELTA);
+ return err;
}
const struct got_error *
blob - 3c7bb235cb37bcd85135050f703b4191e33fc84c
blob + 27f892a1d1f51a54cd4519bf471c326285fd47ae
--- lib/got_delta_lib.h
+++ lib/got_delta_lib.h
struct got_delta_chain *);
const struct got_error *got_delta_get_sizes(uint64_t *, uint64_t *,
const uint8_t *, size_t);
+const struct got_error *got_delta_apply_in_mem(uint8_t *, const uint8_t *,
+ size_t, uint8_t *, size_t *);
const struct got_error *got_delta_apply(FILE *, const uint8_t *, size_t,
FILE *);
blob - 06e97009123ad8a83250cae46a1f7e0e4bde4d00
blob + 569429d80e967730cfa186780dfdf22d2ed164f6
--- lib/pack.c
+++ lib/pack.c
const struct got_error *err = NULL;
struct got_delta *delta;
FILE *base_file = NULL, *accum_file = NULL;
+ uint8_t *base_buf = NULL, *accum_buf = NULL;
+ size_t accum_size;
uint64_t max_size;
int n = 0;
if (SIMPLEQ_EMPTY(&deltas->entries))
return got_error(GOT_ERR_BAD_DELTA_CHAIN);
+ /* We process small enough files entirely in memory for speed. */
err = get_delta_chain_max_size(&max_size, deltas);
if (err)
return err;
-
- if (max_size < GOT_DELTA_RESULT_SIZE_CACHED_MAX)
- base_file = fmemopen(NULL, max_size, "w+");
- else
+ if (max_size < GOT_DELTA_RESULT_SIZE_CACHED_MAX) {
+ accum_buf = malloc(max_size);
+ if (accum_buf == NULL)
+ return got_error(GOT_ERR_NO_MEM);
+ } else {
base_file = got_opentemp();
- if (base_file == NULL)
- return got_error_from_errno();
+ if (base_file == NULL)
+ return got_error_from_errno();
- if (max_size < GOT_DELTA_RESULT_SIZE_CACHED_MAX)
- accum_file = fmemopen(NULL, max_size, "w+");
- else
accum_file = got_opentemp();
- if (accum_file == NULL) {
- err = got_error_from_errno();
- fclose(base_file);
- return err;
+ if (accum_file == NULL) {
+ err = got_error_from_errno();
+ fclose(base_file);
+ return err;
+ }
}
/* Deltas are ordered in ascending order. */
if (n == 0) {
FILE *delta_file;
+ size_t base_len;
/* Plain object types are the delta base. */
if (delta->type != GOT_OBJ_TYPE_COMMIT &&
err = got_error_from_errno();
goto done;
}
- err = got_inflate_to_file(&delta_len, delta_file,
- base_file);
+ if (base_file)
+ err = got_inflate_to_file(&delta_len,
+ delta_file, base_file);
+ else {
+ err = got_inflate_to_mem(&base_buf, &base_len,
+ delta_file);
+ if (base_len < max_size) {
+ uint8_t *p;
+ p = reallocarray(base_buf, 1, max_size);
+ if (p == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+ base_buf = p;
+ }
+ }
fclose(delta_file);
if (err)
goto done;
n++;
- rewind(base_file);
+ if (base_file)
+ rewind(base_file);
continue;
}
}
/* delta_buf is now cached */
- err = got_delta_apply(base_file, delta_buf, delta_len,
- /* Final delta application writes to the output file. */
- ++n < deltas->nentries ? accum_file : outfile);
+ if (base_buf) {
+ err = got_delta_apply_in_mem(base_buf, delta_buf,
+ delta_len, accum_buf, &accum_size);
+ n++;
+ } else {
+ err = got_delta_apply(base_file, delta_buf, delta_len,
+ /* Final delta application writes to output file. */
+ ++n < deltas->nentries ? accum_file : outfile);
+ }
if (err)
goto done;
if (n < deltas->nentries) {
/* Accumulated delta becomes the new base. */
- FILE *tmp = accum_file;
- accum_file = base_file;
- base_file = tmp;
- rewind(base_file);
- rewind(accum_file);
+ if (base_buf) {
+ uint8_t *tmp = accum_buf;
+ accum_buf = base_buf;
+ base_buf = tmp;
+ } else {
+ FILE *tmp = accum_file;
+ accum_file = base_file;
+ base_file = tmp;
+ rewind(base_file);
+ rewind(accum_file);
+ }
}
}
done:
- fclose(base_file);
- fclose(accum_file);
+ free(base_buf);
+ if (accum_buf) {
+ size_t len = fwrite(accum_buf, 1, accum_size, outfile);
+ free(accum_buf);
+ if (len != accum_size)
+ return got_ferror(outfile, GOT_ERR_IO);
+ }
+ if (base_file)
+ fclose(base_file);
+ if (accum_file)
+ fclose(accum_file);
rewind(outfile);
return err;
}