commit - 4ee4114f42bfb2db8acaf987154009165f43ec59
commit + 6691714a6b757c9e0e6db70e34205fbc69306af6
blob - e3a0f891cc456e23b9a1b1a45535bce0d61a5387
blob + 70c6704d0313d8059c362e51ff46094f89488561
--- lib/delta.c
+++ lib/delta.c
got_delta_chain_get_base_type(int *type, struct got_delta_chain *deltas)
{
struct got_delta *delta;
- int n = 0;
- /* Find the last delta in the chain. It should be a plain object. */
- SIMPLEQ_FOREACH(delta, &deltas->entries, entry) {
- n++;
- if (delta->type == GOT_OBJ_TYPE_COMMIT ||
- delta->type == GOT_OBJ_TYPE_TREE ||
- delta->type == GOT_OBJ_TYPE_BLOB ||
- delta->type == GOT_OBJ_TYPE_TAG) {
- if (n != deltas->nentries)
- return got_error(GOT_ERR_BAD_DELTA_CHAIN);
- *type = delta->type;
- return NULL;
- }
+ /* The first delta in the chain should represent the base object. */
+ delta = SIMPLEQ_FIRST(&deltas->entries);
+ if (delta->type == GOT_OBJ_TYPE_COMMIT ||
+ delta->type == GOT_OBJ_TYPE_TREE ||
+ delta->type == GOT_OBJ_TYPE_BLOB ||
+ delta->type == GOT_OBJ_TYPE_TAG) {
+ *type = delta->type;
+ return NULL;
}
return got_error(GOT_ERR_BAD_DELTA_CHAIN);
}
-const struct got_error *
-got_delta_apply(struct got_repository *repo, FILE *infile, size_t size,
- struct got_object *base_obj, FILE *outfile)
+const struct got_error *got_delta_apply(struct got_delta *delta,
+ FILE *base_file, FILE *delta_file, FILE *outfile)
{
return got_error(GOT_ERR_NOT_IMPL);
}
blob - 1410200d3d473b20e4826c4517191df7013a47ae
blob + 3c6a6e724069a232e85775d3c107fa419a473769
--- lib/delta.h
+++ lib/delta.h
struct got_delta *got_delta_open(const char *, int, off_t, size_t);
void got_delta_close(struct got_delta *);
const struct got_error *got_delta_chain_get_base_type(int *,
- struct got_delta_chain *) ;
-const struct got_error *
-got_delta_apply(struct got_repository *, FILE *, size_t, struct got_object *,
+ struct got_delta_chain *);
+const struct got_error *got_delta_apply(struct got_delta *, FILE *, FILE *,
FILE *);
blob - e3805da4fc0947161060aea34cc710882f1f3c4e
blob + 670aff4833f47236b21b0bebeb80d83ca67ad7ab
--- lib/pack.c
+++ lib/pack.c
if (delta == NULL)
return got_error(GOT_ERR_NO_MEM);
deltas->nentries++;
- SIMPLEQ_INSERT_TAIL(&deltas->entries, delta, entry);
+ SIMPLEQ_INSERT_HEAD(&deltas->entries, delta, entry);
/* In case of error below, delta is freed in got_object_close(). */
switch (delta_type) {
}
static const struct got_error *
-dump_ref_delta_object(struct got_repository *repo, FILE *infile, uint8_t type,
- size_t size, FILE *outfile)
+dump_delta_object(struct got_object *obj, FILE *outfile)
{
const struct got_error *err = NULL;
- struct got_object_id base_id;
- struct got_object *base_obj;
- size_t n;
+ struct got_delta *delta;
+ FILE *base_file, *accum_file;
+ int n = 0;
- if (size < sizeof(base_id))
- return got_ferror(infile, GOT_ERR_BAD_PACKFILE);
+ if (SIMPLEQ_EMPTY(&obj->deltas.entries))
+ return got_error(GOT_ERR_BAD_DELTA_CHAIN);
- n = fread(&base_id, sizeof(base_id), 1, infile);
- if (n != 1)
- return got_ferror(infile, GOT_ERR_BAD_PACKFILE);
+ base_file = got_opentemp();
+ if (base_file == NULL)
+ return got_error_from_errno();
- size -= sizeof(base_id);
- if (size <= 0)
- return got_ferror(infile, GOT_ERR_BAD_PACKFILE);
-
- err = got_object_open(&base_obj, repo, &base_id);
- if (err)
+ accum_file = got_opentemp();
+ if (accum_file == NULL) {
+ err = got_error_from_errno();
+ fclose(base_file);
return err;
+ }
- err = got_delta_apply(repo, infile, size, base_obj, outfile);
- got_object_close(base_obj);
+ /* Deltas are ordered in ascending order. */
+ SIMPLEQ_FOREACH(delta, &obj->deltas.entries, entry) {
+ FILE *delta_file = fopen(delta->path_packfile, "rb");
+ if (delta_file == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ if (fseeko(delta_file, delta->offset, SEEK_SET) != 0) {
+ fclose(delta_file);
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ err = got_delta_apply(delta, base_file, delta_file,
+ /* Final delta application writes to the output file. */
+ ++n < obj->deltas.nentries ? accum_file : outfile);
+ fclose(delta_file);
+ if (err)
+ goto done;
+
+ if (n < obj->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);
+ }
+ }
+
+done:
+ fclose(base_file);
+ fclose(accum_file);
+ rewind(outfile);
return err;
}
goto done;
}
- packfile = fopen(obj->path_packfile, "rb");
- if (packfile == NULL) {
- err = got_error_from_errno();
- goto done;
- }
+ if ((obj->flags & GOT_OBJ_FLAG_DELTIFIED) == 0) {
+ packfile = fopen(obj->path_packfile, "rb");
+ if (packfile == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
- if (fseeko(packfile, obj->pack_offset, SEEK_SET) != 0) {
- err = got_error_from_errno();
- goto done;
- }
+ if (fseeko(packfile, obj->pack_offset, SEEK_SET) != 0) {
+ err = got_error_from_errno();
+ goto done;
+ }
- switch (obj->type) {
- case GOT_OBJ_TYPE_COMMIT:
- case GOT_OBJ_TYPE_TREE:
- case GOT_OBJ_TYPE_BLOB:
- case GOT_OBJ_TYPE_TAG:
err = dump_plain_object(packfile, obj->type, obj->size, *f);
- break;
- case GOT_OBJ_TYPE_REF_DELTA:
- err = dump_ref_delta_object(repo, packfile, obj->type,
- obj->size, *f);
- break;
- case GOT_OBJ_TYPE_OFFSET_DELTA:
- default:
- err = got_error(GOT_ERR_NOT_IMPL);
- goto done;
- }
+ } else
+ err = dump_delta_object(obj, *f);
done:
if (packfile)
fclose(packfile);