commit - d71d75ad16058715e286e90bf48ab4f3d76e2127
commit + ab9a70b228c50aa8f3066780a9472f5fe8453d85
blob - b621824f64024b17e410ee7d940177183af49938
blob + 325073050fc88a4c277d9fab2d2a72433701503f
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_NOT_ABSPATH 0x0003
#define GOT_ERR_BAD_PATH 0x0004
#define GOT_ERR_NOT_REF 0x0005
+#define GOT_ERR_IO 0x0006
+#define GOT_ERR_EOF 0x0007
+#define GOT_ERR_DECOMPRESSION 0x0008
+#define GOT_ERR_NO_SPACE 0x0009
+#define GOT_ERR_BAD_OBJ_HDR 0x0010
static const struct got_error {
int code;
{ GOT_ERR_NOT_ABSPATH, "absolute path expected" },
{ GOT_ERR_BAD_PATH, "bad path" },
{ GOT_ERR_NOT_REF, "no such reference found" },
+ { GOT_ERR_IO, "input/output error" },
+ { GOT_ERR_EOF, "unexpected end of file" },
+ { GOT_ERR_DECOMPRESSION,"decompression failed" },
+ { GOT_ERR_NO_SPACE, "buffer too small" },
+ { GOT_ERR_BAD_OBJ_HDR, "bad object header" },
};
const struct got_error * got_error(int code);
blob - fdfff2e90cf197c3377cf3a2df9b005075469071
blob + e0280c719c9da46b5e6b4d3497f5dbf157b7fc49
--- include/got_object.h
+++ include/got_object.h
u_int8_t sha1[SHA1_DIGEST_LENGTH];
};
+struct got_object {
+ int type;
+#define GOT_OBJ_TYPE_COMMIT 1
+#define GOT_OBJ_TYPE_TREE 2
+#define GOT_OBJ_TYPE_BLOB 3
+
+ size_t size;
+ struct got_object_id id;
+};
+
+struct got_repository;
+
const char * got_object_id_str(struct got_object_id *, char *, size_t);
+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 - 4e9d9cfc4245c5c928a8abeb20463300b7469393
blob + ff3a5659e40c001e5bdb0b4223aaadf60aca59f0
--- lib/object.c
+++ lib/object.c
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sha1.h>
+#include <zlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include "got_error.h"
#include "got_object.h"
+#include "got_repository.h"
+#ifndef MIN
+#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
+#endif
+
+#ifndef nitems
+#define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
+#endif
+
+#define GOT_OBJ_TAG_COMMIT "commit"
+#define GOT_OBJ_TAG_TREE "tree"
+#define GOT_OBJ_TAG_BLOB "blob"
+
const char *
got_object_id_str(struct got_object_id *id, char *buf, size_t size)
{
return buf;
}
+
+struct got_zstream_buf {
+ z_stream z;
+ char *inbuf;
+ size_t inlen;
+ char *outbuf;
+ size_t outlen;
+ int flags;
+#define GOT_ZSTREAM_F_HAVE_MORE 0x01
+};
+
+static void
+inflate_end(struct got_zstream_buf *zb)
+{
+ free(zb->inbuf);
+ free(zb->outbuf);
+ inflateEnd(&zb->z);
+}
+
+static const struct got_error *
+inflate_init(struct got_zstream_buf *zb, size_t bufsize)
+{
+ const struct got_error *err = NULL;
+
+ memset(zb, 0, sizeof(*zb));
+
+ zb->z.zalloc = Z_NULL;
+ zb->z.zfree = Z_NULL;
+ if (inflateInit(&zb->z) != Z_OK) {
+ err = got_error(GOT_ERR_IO);
+ goto done;
+ }
+
+ zb->inlen = zb->outlen = bufsize;
+
+ zb->inbuf = calloc(1, zb->inlen);
+ if (zb->inbuf == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+
+ zb->outbuf = calloc(1, zb->outlen);
+ if (zb->outbuf == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+
+done:
+ if (err)
+ inflate_end(zb);
+ return err;
+}
+
+static const struct got_error *
+inflate_read(struct got_zstream_buf *zb, FILE *f, size_t *outlenp)
+{
+ size_t last_total_out = zb->z.total_out;
+ z_stream *z = &zb->z;
+ int n, ret;
+
+ z->next_out = zb->outbuf;
+ z->avail_out = zb->outlen;
+
+ if (z->avail_in == 0 && (zb->flags & GOT_ZSTREAM_F_HAVE_MORE) == 0) {
+ int i;
+ n = fread(zb->inbuf, 1, zb->inlen, f);
+ if (n == 0) {
+ if (ferror(f))
+ return got_error(GOT_ERR_IO);
+ *outlenp = 0;
+ return NULL;
+ }
+ z->next_in = zb->inbuf;
+ z->avail_in = n;
+ }
+
+ ret = inflate(z, Z_SYNC_FLUSH);
+ if (ret == Z_OK) {
+ if (z->avail_out == 0)
+ zb->flags |= GOT_ZSTREAM_F_HAVE_MORE;
+ else
+ zb->flags &= ~GOT_ZSTREAM_F_HAVE_MORE;
+ } else if (ret != Z_STREAM_END)
+ return got_error(GOT_ERR_DECOMPRESSION);
+
+ *outlenp = z->total_out - last_total_out;
+ return NULL;
+}
+
+static const struct got_error *
+parse_obj_header(struct got_object **obj, char *buf, size_t len)
+{
+ const char *obj_tags[] = {
+ GOT_OBJ_TAG_COMMIT,
+ GOT_OBJ_TAG_TREE,
+ GOT_OBJ_TAG_BLOB
+ };
+ const int obj_types[] = {
+ GOT_OBJ_TYPE_COMMIT,
+ GOT_OBJ_TYPE_TREE,
+ GOT_OBJ_TYPE_BLOB,
+ };
+ int type = 0;
+ size_t size = 0;
+ int i;
+ char *p = strchr(buf, '\0');
+
+ if (p == NULL)
+ return got_error(GOT_ERR_BAD_OBJ_HDR);
+
+ for (i = 0; i < nitems(obj_tags); i++) {
+ const char *tag = obj_tags[i];
+ const char *errstr;
+
+ if (strncmp(buf, tag, strlen(tag)) != 0)
+ continue;
+
+ type = obj_types[i];
+ if (len <= strlen(tag))
+ return got_error(GOT_ERR_BAD_OBJ_HDR);
+ size = strtonum(buf + strlen(tag), 0, LONG_MAX, &errstr);
+ if (errstr != NULL)
+ return got_error(GOT_ERR_BAD_OBJ_HDR);
+ break;
+ }
+
+ if (type == 0)
+ return got_error(GOT_ERR_BAD_OBJ_HDR);
+
+ *obj = calloc(1, sizeof(**obj));
+ (*obj)->type = type;
+ (*obj)->size = size;
+ return NULL;
+}
+
+static const struct got_error *
+read_object_header(struct got_object **obj, struct got_repository *repo,
+ const char *path)
+{
+ const struct got_error *err;
+ FILE *f;
+ struct got_zstream_buf zb;
+ char *p;
+ size_t outlen;
+ int i, ret;
+
+ f = fopen(path, "rb");
+ if (f == NULL)
+ return got_error(GOT_ERR_BAD_PATH);
+
+ err = inflate_init(&zb, 64);
+ if (err) {
+ fclose(f);
+ return err;
+ }
+
+ err = inflate_read(&zb, f, &outlen);
+ if (err)
+ goto done;
+
+ err = parse_obj_header(obj, zb.outbuf, outlen);
+done:
+ inflate_end(&zb);
+ fclose(f);
+ return err;
+}
+
+const struct got_error *
+got_object_open(struct got_object **obj, struct got_repository *repo,
+ struct got_object_id *id)
+{
+ const struct got_error *err = NULL;
+ char *path_objects = got_repo_get_path_objects(repo);
+ char hex[SHA1_DIGEST_STRING_LENGTH];
+ char *path = NULL;
+
+ if (path_objects == NULL)
+ return got_error(GOT_ERR_NO_MEM);
+
+ got_object_id_str(id, hex, sizeof(hex));
+
+ if (asprintf(&path, "%s/%.2x/%s",
+ path_objects, id->sha1[0], hex + 2) == -1) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+
+ err = read_object_header(obj, repo, path);
+ if (err == NULL)
+ memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
+
+done:
+ free(path);
+ free(path_objects);
+ return err;
+}
+
+void
+got_object_close(struct got_object *obj)
+{
+ free(obj);
+}
blob - 4a4a51ff51f09e461601809905d6eb6f3ec619a0
blob + 091f43b0a03fb2b5ddc634dc5e8fcd36ccd7dff6
--- regress/repository/Makefile
+++ regress/repository/Makefile
SRCS = path.c repository.c error.c refs.c object.c repository_test.c
CPPFLAGS = -I${.CURDIR}/../../include
-LDADD = -lutil
+LDADD = -lutil -lz
NOMAN = yes
blob - eb48aeca9c322748e88fc2cc83d9ad58b86c98d3
blob + aeb8b920a4ed73c542162adf523aa4110f9cfd8e
--- regress/repository/repository_test.c
+++ regress/repository/repository_test.c
#define GOT_REPO_PATH "../../../"
static int
-repo_resolve_head_ref(const char *repo_path)
+repo_read_object_header(const char *repo_path)
{
const struct got_error *err;
struct got_repository *repo;
struct got_reference *head_ref;
struct got_object_id *id;
+ struct got_object *obj;
char buf[SHA1_DIGEST_STRING_LENGTH];
int ret;
if (err != NULL || head_ref == NULL)
return 0;
printf("HEAD is at %s\n", got_object_id_str(id, buf, sizeof(buf)));
+ err = got_object_open(&obj, repo, id);
+ if (err != NULL || obj == NULL)
+ return 0;
+ printf("object type=%d size=%lu\n", obj->type, obj->size);
+ got_object_close(obj);
free(id);
got_ref_close(head_ref);
got_repo_close(repo);
return 1;
}
- RUN_TEST(repo_resolve_head_ref(repo_path), "resolve_head_ref");
+ RUN_TEST(repo_read_object_header(repo_path), "read_object_header");
return failure ? 1 : 0;
}