add support for extracting non-deltified packed objects
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
diff --git a/include/got_error.h b/include/got_error.h
index ebe18b5..b85bd54 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -34,6 +34,7 @@
#define GOT_ERR_BAD_PACKFILE 16
#define GOT_ERR_NO_OBJ 17
#define GOT_ERR_NOT_IMPL 18
+#define GOT_ERR_OBJ_NOT_PACKED 19
static const struct got_error {
int code;
@@ -58,6 +59,7 @@ static const struct got_error {
{ GOT_ERR_BAD_PACKFILE, "bad pack file" },
{ GOT_ERR_NO_OBJ, "object not found" },
{ GOT_ERR_NOT_IMPL, "feature not implemented" },
+ { GOT_ERR_OBJ_NOT_PACKED,"object is not packed" },
};
const struct got_error * got_error(int code);
diff --git a/lib/object.c b/lib/object.c
index f3581b6..96d336a 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -274,9 +274,8 @@ open_object(FILE **f, struct got_object *obj, struct got_repository *repo)
const struct got_error *err = NULL;
char *path;
- if (obj->flags & GOT_OBJ_FLAG_PACKED) {
- return got_error(GOT_ERR_NOT_IMPL);
- }
+ if (obj->flags & GOT_OBJ_FLAG_PACKED)
+ return got_packfile_extract_object(f, obj, repo);
err = object_path(&path, &obj->id, repo);
if (err)
diff --git a/lib/pack.c b/lib/pack.c
index 7e7325a..32b5af0 100644
--- a/lib/pack.c
+++ b/lib/pack.c
@@ -327,7 +327,7 @@ read_packfile_hdr(FILE *f, struct got_packidx_v2_hdr *packidx)
}
static const struct got_error *
-decode_type_and_size(uint8_t *type, uint64_t *size, FILE *packfile)
+decode_type_and_size(uint8_t *type, uint64_t *size, size_t *len, FILE *packfile)
{
uint8_t t = 0;
uint64_t s = 0;
@@ -357,6 +357,7 @@ decode_type_and_size(uint8_t *type, uint64_t *size, FILE *packfile)
*type = t;
*size = s;
+ *len = i * sizeof(sizeN);
return NULL;
}
@@ -374,6 +375,7 @@ open_packed_object(struct got_object **obj, struct got_repository *repo,
FILE *packfile;
uint8_t type;
uint64_t size;
+ size_t tslen;
*obj = NULL;
if (idx == -1) /* object not found in pack index */
@@ -407,7 +409,7 @@ open_packed_object(struct got_object **obj, struct got_repository *repo,
goto done;
}
- err = decode_type_and_size(&type, &size, packfile);
+ err = decode_type_and_size(&type, &size, &tslen, packfile);
if (err)
goto done;
@@ -431,7 +433,7 @@ open_packed_object(struct got_object **obj, struct got_repository *repo,
(*obj)->hdrlen = 0;
(*obj)->size = size;
memcpy(&(*obj)->id, id, sizeof((*obj)->id));
- (*obj)->pack_offset = offset;
+ (*obj)->pack_offset = offset + tslen;
break;
case GOT_OBJ_TYPE_REF_DELTA:
case GOT_OBJ_TYPE_TAG:
@@ -500,3 +502,75 @@ done:
err = got_error_from_errno();
return err;
}
+
+static const struct got_error *
+dump_plain_object(FILE *infile, uint8_t type, size_t size, FILE *outfile)
+{
+ size_t n;
+
+ while (size > 0) {
+ uint8_t data[2048];
+ size_t len = MIN(size, sizeof(data));
+
+ n = fread(data, len, 1, infile);
+ if (n != 1)
+ return got_ferror(infile, GOT_ERR_BAD_PACKIDX);
+
+ n = fwrite(data, len, 1, outfile);
+ if (n != 1)
+ return got_ferror(outfile, GOT_ERR_BAD_PACKIDX);
+
+ size -= len;
+ }
+
+ rewind(outfile);
+ return NULL;
+}
+
+const struct got_error *
+got_packfile_extract_object(FILE **f, struct got_object *obj,
+ struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ FILE *packfile = NULL;
+
+ if ((obj->flags & GOT_OBJ_FLAG_PACKED) == 0)
+ return got_error(GOT_ERR_OBJ_NOT_PACKED);
+
+ *f = got_opentemp();
+ if (*f == NULL) {
+ err = got_error(GOT_ERR_FILE_OPEN);
+ goto done;
+ }
+
+ 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;
+ }
+
+ switch (obj->type) {
+ case GOT_OBJ_TYPE_COMMIT:
+ case GOT_OBJ_TYPE_TREE:
+ case GOT_OBJ_TYPE_BLOB:
+ err = dump_plain_object(packfile, obj->type, obj->size, *f);
+ break;
+ case GOT_OBJ_TYPE_REF_DELTA:
+ case GOT_OBJ_TYPE_TAG:
+ case GOT_OBJ_TYPE_OFFSET_DELTA:
+ default:
+ err = got_error(GOT_ERR_NOT_IMPL);
+ goto done;
+ }
+done:
+ if (packfile)
+ fclose(packfile);
+ if (err && *f)
+ fclose(*f);
+ return err;
+}
diff --git a/lib/pack.h b/lib/pack.h
index e26be48..18a6071 100644
--- a/lib/pack.h
+++ b/lib/pack.h
@@ -123,3 +123,5 @@ void got_packidx_close(struct got_packidx_v2_hdr *);
const struct got_error *got_packfile_open_object(struct got_object **,
struct got_object_id *, struct got_repository *);
+const struct got_error *got_packfile_extract_object(FILE **,
+ struct got_object *, struct got_repository *);