commit - 9710aac2fcc11960009a5aad05cda68a89e85b7a
commit + b107e67fba94d3a78c6b93b0d9a0f3482c9e5dd9
blob - 204947b421455ff730a46fe0ff59b72331ec8a6a
blob + 54b890a4cdf611d89cafac33844289083e0fc554
--- include/got_object.h
+++ include/got_object.h
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
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;
}
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
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
(*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)
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;
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
* 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
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);
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;
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");
}
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);
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);