commit 6691714a6b757c9e0e6db70e34205fbc69306af6 from: Stefan Sperling date: Tue Jan 23 22:44:49 2018 UTC prepare application of deltas commit - 4ee4114f42bfb2db8acaf987154009165f43ec59 commit + 6691714a6b757c9e0e6db70e34205fbc69306af6 blob - e3a0f891cc456e23b9a1b1a45535bce0d61a5387 blob + 70c6704d0313d8059c362e51ff46094f89488561 --- lib/delta.c +++ lib/delta.c @@ -61,28 +61,22 @@ const struct got_error * 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 @@ -30,7 +30,6 @@ struct got_delta_chain { 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 @@ -647,7 +647,7 @@ resolve_delta_chain(struct got_delta_chain *deltas, st 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) { @@ -822,31 +822,62 @@ dump_plain_object(FILE *infile, uint8_t type, size_t s } 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; } @@ -866,33 +897,21 @@ got_packfile_extract_object(FILE **f, struct got_objec 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);