commit b107e67fba94d3a78c6b93b0d9a0f3482c9e5dd9 from: Stefan Sperling date: Fri Jan 19 17:03:07 2018 UTC Implement open() support for offset delta objects commit - 9710aac2fcc11960009a5aad05cda68a89e85b7a commit + b107e67fba94d3a78c6b93b0d9a0f3482c9e5dd9 blob - 204947b421455ff730a46fe0ff59b72331ec8a6a blob + 54b890a4cdf611d89cafac33844289083e0fc554 --- include/got_object.h +++ include/got_object.h @@ -80,15 +80,20 @@ struct got_object { size_t size; struct got_object_id id; - char *path_packfile; - off_t pack_offset; + char *path_packfile; /* if packed */ + off_t pack_offset; /* if packed */ + + /* If type is OFFSET_DELTA: */ + int base_type; + uint64_t base_size; + off_t base_obj_offset; }; struct got_repository; char *got_object_id_str(struct got_object_id *, char *, size_t); int got_object_id_cmp(struct got_object_id *, struct got_object_id *); -const char *got_object_get_type_tag(int); +int got_object_get_type(struct got_object *); const struct got_error *got_object_open(struct got_object **, struct got_repository *, struct got_object_id *); void got_object_close(struct got_object *); blob - d99ed9f7c19a52512573c812b0f54ccfe0218861 blob + 3bf0c3c7eaa09b84e6b176a6d650cd3e57ef42ae --- lib/diff.c +++ lib/diff.c @@ -232,7 +232,7 @@ diff_added_tree(struct got_object_id *id, struct got_r if (err) goto done; - if (treeobj->type != GOT_OBJ_TYPE_TREE) { + if (got_object_get_type(treeobj) != GOT_OBJ_TYPE_TREE) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } @@ -312,7 +312,7 @@ diff_deleted_tree(struct got_object_id *id, struct got if (err) goto done; - if (treeobj->type != GOT_OBJ_TYPE_TREE) { + if (got_object_get_type(treeobj) != GOT_OBJ_TYPE_TREE) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } blob - 96d336a171264be9c2e02e38fbaa135a7859c3aa blob + 9f2bc6f19f925498fcf0679ec4e0b0a4deeee9d8 --- lib/object.c +++ lib/object.c @@ -61,19 +61,21 @@ got_object_id_cmp(struct got_object_id *id1, struct go return memcmp(id1->sha1, id2->sha1, SHA1_DIGEST_LENGTH); } -const char * -got_object_get_type_tag(int type) +int +got_object_get_type(struct got_object *obj) { - switch (type) { + switch (obj->type) { case GOT_OBJ_TYPE_COMMIT: - return GOT_OBJ_TAG_COMMIT; case GOT_OBJ_TYPE_TREE: - return GOT_OBJ_TAG_TREE; case GOT_OBJ_TYPE_BLOB: - return GOT_OBJ_TAG_BLOB; + case GOT_OBJ_TYPE_TAG: + return obj->type; + case GOT_OBJ_TYPE_REF_DELTA: + case GOT_OBJ_TYPE_OFFSET_DELTA: + return obj->base_type; } - return NULL; + abort(); } static void blob - 3ec264fcdf777cbd3e6b7dabb936c418472ef058 blob + a91b59411f042723dc0f4b7c23bb54b076ea2bd1 --- lib/pack.c +++ lib/pack.c @@ -383,11 +383,103 @@ open_plain_object(struct got_object **obj, const char (*obj)->size = size; memcpy(&(*obj)->id, id, sizeof((*obj)->id)); (*obj)->pack_offset = offset; + + return NULL; +} + +static const struct got_error * +decode_negative_offset(int64_t *offset, size_t *len, FILE *packfile) +{ + int64_t o = 0; + uint8_t offN; + size_t n; + int i = 0; + + do { + /* We do not support offset values which don't fit in 64 bit. */ + if (i > 8) + return got_error(GOT_ERR_NO_SPACE); + + n = fread(&offN, sizeof(offN), 1, packfile); + if (n != 1) + return got_ferror(packfile, GOT_ERR_BAD_PACKIDX); + + if (i == 0) + o = (offN & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK); + else { + int j; + int64_t v = 128; + o <<= 7; + o |= (offN & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK); + o += v; + for (j = 0; j < i; j++) { + v <<= 7; + o += v; + } + } + i++; + } while (offN & GOT_PACK_OBJ_DELTA_OFF_MORE); + *offset = o; + *len = i * sizeof(offN); return NULL; } static const struct got_error * +open_offset_delta_object(struct got_object **obj, struct got_repository *repo, + const char *path_packfile, FILE *packfile, struct got_object_id *id, + off_t offset, size_t size) +{ + const struct got_error *err = NULL; + int64_t negoffset; + size_t negofflen; + off_t base_obj_offset; + struct got_object *base_obj; + struct got_object_id base_id; + uint8_t base_type; + uint64_t base_size; + size_t base_tslen; + + err = decode_negative_offset(&negoffset, &negofflen, packfile); + if (err) + return err; + + /* Compute the base object's offset (must be in the same pack file). */ + base_obj_offset = (offset - negoffset); + if (base_obj_offset <= 0) + return got_error(GOT_ERR_BAD_PACKFILE); + + if (fseeko(packfile, base_obj_offset, SEEK_SET) != 0) + return got_error_from_errno(); + + err = decode_type_and_size(&base_type, &base_size, &base_tslen, + packfile); + if (err) + return err; + + *obj = calloc(1, sizeof(**obj)); + if (*obj == NULL) + return got_error(GOT_ERR_NO_MEM); + + (*obj)->path_packfile = strdup(path_packfile); + if ((*obj)->path_packfile == NULL) { + free(*obj); + return got_error(GOT_ERR_NO_MEM); + } + (*obj)->type = GOT_OBJ_TYPE_OFFSET_DELTA; + (*obj)->flags = GOT_OBJ_FLAG_PACKED; + (*obj)->hdrlen = 0; + (*obj)->size = size; + memcpy(&(*obj)->id, id, sizeof((*obj)->id)); + (*obj)->pack_offset = offset; + (*obj)->base_type = base_type; + (*obj)->base_size = base_size; + (*obj)->base_obj_offset = base_obj_offset; + + return NULL; +} + +static const struct got_error * open_packed_object(struct got_object **obj, struct got_repository *repo, const char *path_packdir, struct got_packidx_v2_hdr *packidx, struct got_object_id *id) @@ -447,9 +539,14 @@ open_packed_object(struct got_object **obj, struct got offset + tslen, size); break; + case GOT_OBJ_TYPE_OFFSET_DELTA: + err = open_offset_delta_object(obj, repo, path_packfile, + packfile, id, offset + tslen, size); + break; + case GOT_OBJ_TYPE_REF_DELTA: case GOT_OBJ_TYPE_TAG: - case GOT_OBJ_TYPE_OFFSET_DELTA: + break; default: err = got_error(GOT_ERR_NOT_IMPL); goto done; @@ -547,7 +644,7 @@ dump_ref_delta_object(struct got_repository *repo, FIL const struct got_error *err = NULL; struct got_object_id base_id; struct got_object *base_obj; - int n; + size_t n; if (size < sizeof(base_id)) return got_ferror(infile, GOT_ERR_BAD_PACKFILE); blob - 18a6071e88706cf03a4eb280c3b30f5cd73fc425 blob + 189b5641714068ed3ea3bc6d13b1f765956a582d --- lib/pack.h +++ lib/pack.h @@ -107,6 +107,9 @@ struct got_packfile_object_data_offset_delta { * 2^14 + ... + 2^(7 * (n-1)) is added to the result. */ uint8_t *offset; /* variable length */ +#define GOT_PACK_OBJ_DELTA_OFF_MORE 0x80 +#define GOT_PACK_OBJ_DELTA_OFF_VAL_MASK 0x7f + uint8_t *delta_data; /* compressed */ }; struct got_packfile_obj_data { blob - 8fd30992c9434f52ee5debdc68bdf0bbf2a550c3 blob + 6495ec45fdd21d9b0882c3766a0ff40302a76137 --- regress/repository/repository_test.c +++ regress/repository/repository_test.c @@ -49,7 +49,7 @@ print_parent_commits(struct got_commit_object *commit, err = got_object_open(&obj, repo, &pid->id); if (err != NULL) return err; - if (obj->type != GOT_OBJ_TYPE_COMMIT) + if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) return got_error(GOT_ERR_OBJ_TYPE); print_commit_object(obj, repo); got_object_close(obj); @@ -89,7 +89,7 @@ print_tree_object(struct got_object *obj, char *parent if (err != NULL) break; - if (treeobj->type != GOT_OBJ_TYPE_TREE) { + if (got_object_get_type(treeobj) != GOT_OBJ_TYPE_TREE) { err = got_error(GOT_ERR_OBJ_TYPE); got_object_close(treeobj); break; @@ -142,7 +142,7 @@ print_commit_object(struct got_object *obj, struct got err = got_object_open(&treeobj, repo, &commit->tree_id); if (err != NULL) return err; - if (treeobj->type == GOT_OBJ_TYPE_TREE) { + if (got_object_get_type(treeobj) == GOT_OBJ_TYPE_TREE) { print_tree_object(treeobj, "", repo); printf("\n"); } @@ -178,7 +178,7 @@ repo_read_log(const char *repo_path) err = got_object_open(&obj, repo, id); if (err != NULL || obj == NULL) return 0; - if (obj->type == GOT_OBJ_TYPE_COMMIT) + if (got_object_get_type(obj) == GOT_OBJ_TYPE_COMMIT) print_commit_object(obj, repo); got_object_close(obj); free(id); @@ -209,7 +209,7 @@ repo_read_blob(const char *repo_path) err = got_object_open(&obj, repo, &id); if (err != NULL || obj == NULL) return 0; - if (obj->type != GOT_OBJ_TYPE_BLOB) + if (got_object_get_type(obj) != GOT_OBJ_TYPE_BLOB) return 0; err = got_object_blob_open(&blob, repo, obj, 64);