summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamsay Jones <ramsay@ramsay1.demon.co.uk>2009-06-04 16:47:59 +0100
committerAndreas Ericsson <ae@op5.se>2009-06-05 10:22:20 +0200
commite17a3f5673e0dc4d9ade34a0a276e6c202506fdf (patch)
treed9a9eb65ed8db7f1200aa017e5ea2204266e7ae4
parentca481fc4f12cec56b71bd50ae72e3f088b69021f (diff)
downloadlibgit2-e17a3f5673e0dc4d9ade34a0a276e6c202506fdf.tar.gz
Implement git_odb_write()
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Signed-off-by: Andreas Ericsson <ae@op5.se>
-rw-r--r--src/git/odb.h12
-rw-r--r--src/odb.c173
-rw-r--r--tests/NAMING2
-rw-r--r--tests/t0301-write.c551
4 files changed, 734 insertions, 4 deletions
diff --git a/src/git/odb.h b/src/git/odb.h
index 8a8cd3e5f..58b932645 100644
--- a/src/git/odb.h
+++ b/src/git/odb.h
@@ -96,6 +96,18 @@ GIT_EXTERN(int) git_odb__read_packed(git_obj *out, git_odb *db, const git_oid *i
GIT_EXTERN(int) git_odb__read_loose(git_obj *out, git_odb *db, const git_oid *id);
/**
+ * Write an object to the database.
+ *
+ * @param id identity of the object written.
+ * @param db database to which the object should be written.
+ * @param obj object descriptor for the object to write.
+ * @return
+ * - GIT_SUCCESS if the object was written;
+ * - GIT_ERROR otherwise.
+ */
+GIT_EXTERN(int) git_odb_write(git_oid *id, git_odb *db, git_obj *obj);
+
+/**
* Release all memory used by the obj structure.
*
* As a result of this call, obj->data will be set to NULL.
diff --git a/src/odb.c b/src/odb.c
index 6b7d1f799..5f10ae02d 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -85,6 +85,11 @@ struct git_odb {
/** Alternate databases to search. */
git_odb **alternates;
size_t n_alternates;
+
+ /** loose object zlib compression level. */
+ int object_zlib_level;
+ /** loose object file fsync flag. */
+ int fsync_object_files;
};
typedef struct { /* object header data */
@@ -158,13 +163,12 @@ static int format_object_header(char *hdr, size_t n, git_obj *obj)
return len+1;
}
-int git_obj_hash(git_oid *id, git_obj *obj)
+static int hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_obj *obj)
{
git_buf_vec vec[2];
- char hdr[64];
int hdrlen;
- assert(id && obj);
+ assert(id && hdr && len && obj);
if (!git_obj__loose_object_type(obj->type))
return GIT_ERROR;
@@ -172,9 +176,11 @@ int git_obj_hash(git_oid *id, git_obj *obj)
if (!obj->data && obj->len != 0)
return GIT_ERROR;
- if ((hdrlen = format_object_header(hdr, sizeof(hdr), obj)) < 0)
+ if ((hdrlen = format_object_header(hdr, n, obj)) < 0)
return GIT_ERROR;
+ *len = hdrlen;
+
vec[0].data = hdr;
vec[0].len = hdrlen;
vec[1].data = obj->data;
@@ -185,6 +191,16 @@ int git_obj_hash(git_oid *id, git_obj *obj)
return GIT_SUCCESS;
}
+int git_obj_hash(git_oid *id, git_obj *obj)
+{
+ char hdr[64];
+ int hdrlen;
+
+ assert(id && obj);
+
+ return hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj);
+}
+
static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id)
{
size_t len = strlen(dir);
@@ -483,6 +499,125 @@ static int inflate_disk_obj(git_obj *out, gitfo_buf *obj)
return GIT_SUCCESS;
}
+static int make_temp_file(git_file *fd, char *tmp, size_t n, char *file)
+{
+ char *template = "/tmp_obj_XXXXXX";
+ size_t tmplen = strlen(template);
+ size_t dirlen;
+
+ if ((dirlen = git__dirname(tmp, n, file)) < 0)
+ return GIT_ERROR;
+
+ if ((dirlen + tmplen) >= n)
+ return GIT_ERROR;
+
+ strcpy(tmp + dirlen, (dirlen) ? template : template + 1);
+
+ *fd = gitfo_mkstemp(tmp);
+ if (*fd < 0 && dirlen) {
+ /* create directory if it doesn't exist */
+ tmp[dirlen] = '\0';
+ if ((gitfo_exists(tmp) < 0) && gitfo_mkdir(tmp, 0755))
+ return GIT_ERROR;
+ /* try again */
+ strcpy(tmp + dirlen, template);
+ *fd = gitfo_mkstemp(tmp);
+ }
+ if (*fd < 0)
+ return GIT_ERROR;
+
+ return GIT_SUCCESS;
+}
+
+static int deflate_buf(z_stream *s, void *in, size_t len, int flush)
+{
+ int status = Z_OK;
+
+ set_stream_input(s, in, len);
+ while (status == Z_OK) {
+ status = deflate(s, flush);
+ if (s->avail_in == 0)
+ break;
+ }
+ return status;
+}
+
+static int deflate_obj(gitfo_buf *buf, char *hdr, int hdrlen, git_obj *obj, int level)
+{
+ z_stream zs;
+ int status;
+ size_t size;
+
+ assert(buf && !buf->data && hdr && obj);
+ assert(level == Z_DEFAULT_COMPRESSION || (level >= 0 && level <= 9));
+
+ buf->data = NULL;
+ buf->len = 0;
+ init_stream(&zs, NULL, 0);
+
+ if (deflateInit(&zs, level) < Z_OK)
+ return GIT_ERROR;
+
+ size = deflateBound(&zs, hdrlen + obj->len);
+
+ if ((buf->data = git__malloc(size)) == NULL) {
+ deflateEnd(&zs);
+ return GIT_ERROR;
+ }
+
+ set_stream_output(&zs, buf->data, size);
+
+ /* compress the header */
+ status = deflate_buf(&zs, hdr, hdrlen, Z_NO_FLUSH);
+
+ /* if header compressed OK, compress the object */
+ if (status == Z_OK)
+ status = deflate_buf(&zs, obj->data, obj->len, Z_FINISH);
+
+ if (status != Z_STREAM_END) {
+ deflateEnd(&zs);
+ free(buf->data);
+ buf->data = NULL;
+ return GIT_ERROR;
+ }
+
+ buf->len = zs.total_out;
+ deflateEnd(&zs);
+
+ return GIT_SUCCESS;
+}
+
+static int write_obj(gitfo_buf *buf, git_oid *id, git_odb *db)
+{
+ char file[GIT_PATH_MAX];
+ char temp[GIT_PATH_MAX];
+ git_file fd;
+
+ if (object_file_name(file, sizeof(file), db->objects_dir, id))
+ return GIT_ERROR;
+
+ if (make_temp_file(&fd, temp, sizeof(temp), file) < 0)
+ return GIT_ERROR;
+
+ if (gitfo_write(fd, buf->data, buf->len) < 0) {
+ gitfo_close(fd);
+ gitfo_unlink(temp);
+ return GIT_ERROR;
+ }
+
+ if (db->fsync_object_files)
+ gitfo_fsync(fd);
+ gitfo_close(fd);
+ gitfo_chmod(temp, 0444);
+
+ if (gitfo_move_file(temp, file) < 0) {
+ gitfo_unlink(temp);
+ return GIT_ERROR;
+ }
+
+ return GIT_SUCCESS;
+}
+
static int open_alternates(git_odb *db)
{
unsigned n = 0;
@@ -891,6 +1026,9 @@ int git_odb_open(git_odb **out, const char *objects_dir)
gitlck_init(&db->lock);
+ db->object_zlib_level = Z_BEST_SPEED;
+ db->fsync_object_files = 0;
+
*out = db;
return GIT_SUCCESS;
}
@@ -1004,3 +1142,30 @@ int git_odb__read_packed(git_obj *out, git_odb *db, const git_oid *id)
return GIT_ENOTFOUND;
}
+int git_odb_write(git_oid *id, git_odb *db, git_obj *obj)
+{
+ char hdr[64];
+ int hdrlen;
+ gitfo_buf buf = GITFO_BUF_INIT;
+
+ assert(id && db && obj);
+
+ if (hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj) < 0)
+ return GIT_ERROR;
+
+ if (git_odb_exists(db, id))
+ return GIT_SUCCESS;
+
+ if (deflate_obj(&buf, hdr, hdrlen, obj, db->object_zlib_level) < 0)
+ return GIT_ERROR;
+
+ if (write_obj(&buf, id, db) < 0) {
+ gitfo_free_buf(&buf);
+ return GIT_ERROR;
+ }
+
+ gitfo_free_buf(&buf);
+
+ return GIT_SUCCESS;
+}
+
diff --git a/tests/NAMING b/tests/NAMING
index c1052be27..73bb602a7 100644
--- a/tests/NAMING
+++ b/tests/NAMING
@@ -18,3 +18,5 @@ Categories
addressable store.
02__: Basic object read access.
+
+03__: Basic object writing.
diff --git a/tests/t0301-write.c b/tests/t0301-write.c
new file mode 100644
index 000000000..f161ce12c
--- /dev/null
+++ b/tests/t0301-write.c
@@ -0,0 +1,551 @@
+
+#include "test_lib.h"
+#include <git/odb.h>
+#include "fileops.h"
+
+static char *odb_dir = "test-objects";
+
+typedef struct object_data {
+ char *id; /* object id (sha1) */
+ char *dir; /* object store (fan-out) directory name */
+ char *file; /* object store filename */
+} object_data;
+
+static object_data commit = {
+ "3d7f8a6af076c8c3f20071a8935cdbe8228594d1",
+ "test-objects/3d",
+ "test-objects/3d/7f8a6af076c8c3f20071a8935cdbe8228594d1",
+};
+
+static unsigned char commit_data[] = {
+ 0x74, 0x72, 0x65, 0x65, 0x20, 0x64, 0x66, 0x66,
+ 0x32, 0x64, 0x61, 0x39, 0x30, 0x62, 0x32, 0x35,
+ 0x34, 0x65, 0x31, 0x62, 0x65, 0x62, 0x38, 0x38,
+ 0x39, 0x64, 0x31, 0x66, 0x31, 0x66, 0x31, 0x32,
+ 0x38, 0x38, 0x62, 0x65, 0x31, 0x38, 0x30, 0x33,
+ 0x37, 0x38, 0x32, 0x64, 0x66, 0x0a, 0x61, 0x75,
+ 0x74, 0x68, 0x6f, 0x72, 0x20, 0x41, 0x20, 0x55,
+ 0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61,
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78,
+ 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38,
+ 0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30,
+ 0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x20,
+ 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72,
+ 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
+ 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e,
+ 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34,
+ 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30,
+ 0x30, 0x0a, 0x0a, 0x41, 0x20, 0x6f, 0x6e, 0x65,
+ 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x73, 0x75, 0x6d,
+ 0x6d, 0x61, 0x72, 0x79, 0x0a, 0x0a, 0x54, 0x68,
+ 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6f,
+ 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x73,
+ 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x63, 0x6f,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67,
+ 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72,
+ 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6f, 0x66, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70,
+ 0x6f, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67,
+ 0x65, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f,
+ 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x53, 0x69,
+ 0x67, 0x6e, 0x65, 0x64, 0x2d, 0x6f, 0x66, 0x2d,
+ 0x62, 0x79, 0x3a, 0x20, 0x41, 0x20, 0x55, 0x20,
+ 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75,
+ 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61,
+ 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x3e, 0x0a,
+};
+
+static git_obj commit_obj = {
+ commit_data,
+ sizeof(commit_data),
+ GIT_OBJ_COMMIT
+};
+
+static object_data tree = {
+ "dff2da90b254e1beb889d1f1f1288be1803782df",
+ "test-objects/df",
+ "test-objects/df/f2da90b254e1beb889d1f1f1288be1803782df",
+};
+
+static unsigned char tree_data[] = {
+ 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x6f,
+ 0x6e, 0x65, 0x00, 0x8b, 0x13, 0x78, 0x91, 0x79,
+ 0x1f, 0xe9, 0x69, 0x27, 0xad, 0x78, 0xe6, 0x4b,
+ 0x0a, 0xad, 0x7b, 0xde, 0xd0, 0x8b, 0xdc, 0x31,
+ 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x73, 0x6f,
+ 0x6d, 0x65, 0x00, 0xfd, 0x84, 0x30, 0xbc, 0x86,
+ 0x4c, 0xfc, 0xd5, 0xf1, 0x0e, 0x55, 0x90, 0xf8,
+ 0xa4, 0x47, 0xe0, 0x1b, 0x94, 0x2b, 0xfe, 0x31,
+ 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x74, 0x77,
+ 0x6f, 0x00, 0x78, 0x98, 0x19, 0x22, 0x61, 0x3b,
+ 0x2a, 0xfb, 0x60, 0x25, 0x04, 0x2f, 0xf6, 0xbd,
+ 0x87, 0x8a, 0xc1, 0x99, 0x4e, 0x85, 0x31, 0x30,
+ 0x30, 0x36, 0x34, 0x34, 0x20, 0x7a, 0x65, 0x72,
+ 0x6f, 0x00, 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1,
+ 0xd6, 0x43, 0x4b, 0x8b, 0x29, 0xae, 0x77, 0x5a,
+ 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91,
+};
+
+static git_obj tree_obj = {
+ tree_data,
+ sizeof(tree_data),
+ GIT_OBJ_TREE
+};
+
+static object_data tag = {
+ "09d373e1dfdc16b129ceec6dd649739911541e05",
+ "test-objects/09",
+ "test-objects/09/d373e1dfdc16b129ceec6dd649739911541e05",
+};
+
+static unsigned char tag_data[] = {
+ 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x33,
+ 0x64, 0x37, 0x66, 0x38, 0x61, 0x36, 0x61, 0x66,
+ 0x30, 0x37, 0x36, 0x63, 0x38, 0x63, 0x33, 0x66,
+ 0x32, 0x30, 0x30, 0x37, 0x31, 0x61, 0x38, 0x39,
+ 0x33, 0x35, 0x63, 0x64, 0x62, 0x65, 0x38, 0x32,
+ 0x32, 0x38, 0x35, 0x39, 0x34, 0x64, 0x31, 0x0a,
+ 0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x69, 0x74, 0x0a, 0x74, 0x61, 0x67, 0x20,
+ 0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, 0x74,
+ 0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x43, 0x20,
+ 0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72,
+ 0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
+ 0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e,
+ 0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34,
+ 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30,
+ 0x30, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20,
+ 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74,
+ 0x61, 0x67, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63,
+ 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65,
+ 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x30,
+ 0x2e, 0x30, 0x2e, 0x31, 0x0a,
+};
+
+static git_obj tag_obj = {
+ tag_data,
+ sizeof(tag_data),
+ GIT_OBJ_TAG
+};
+
+static object_data zero = {
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
+ "test-objects/e6",
+ "test-objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391",
+};
+
+static unsigned char zero_data[] = {
+ 0x00 /* dummy data */
+};
+
+static git_obj zero_obj = {
+ zero_data,
+ 0,
+ GIT_OBJ_BLOB
+};
+
+static object_data one = {
+ "8b137891791fe96927ad78e64b0aad7bded08bdc",
+ "test-objects/8b",
+ "test-objects/8b/137891791fe96927ad78e64b0aad7bded08bdc",
+};
+
+static unsigned char one_data[] = {
+ 0x0a,
+};
+
+static git_obj one_obj = {
+ one_data,
+ sizeof(one_data),
+ GIT_OBJ_BLOB
+};
+
+static object_data two = {
+ "78981922613b2afb6025042ff6bd878ac1994e85",
+ "test-objects/78",
+ "test-objects/78/981922613b2afb6025042ff6bd878ac1994e85",
+};
+
+static unsigned char two_data[] = {
+ 0x61, 0x0a,
+};
+
+static git_obj two_obj = {
+ two_data,
+ sizeof(two_data),
+ GIT_OBJ_BLOB
+};
+
+static object_data some = {
+ "fd8430bc864cfcd5f10e5590f8a447e01b942bfe",
+ "test-objects/fd",
+ "test-objects/fd/8430bc864cfcd5f10e5590f8a447e01b942bfe",
+};
+
+static unsigned char some_data[] = {
+ 0x2f, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68,
+ 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20,
+ 0x69, 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20,
+ 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+ 0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61,
+ 0x6e, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74,
+ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69,
+ 0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72,
+ 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0a,
+ 0x20, 0x2a, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6e,
+ 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+ 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c,
+ 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x20, 0x32, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61,
+ 0x73, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73,
+ 0x68, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20,
+ 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+ 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x2a, 0x0a,
+ 0x20, 0x2a, 0x20, 0x49, 0x6e, 0x20, 0x61, 0x64,
+ 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74,
+ 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65,
+ 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+ 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e,
+ 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62,
+ 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65,
+ 0x6e, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x2a, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68,
+ 0x6f, 0x72, 0x73, 0x20, 0x67, 0x69, 0x76, 0x65,
+ 0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x6e, 0x6c,
+ 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x70,
+ 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
+ 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x6e,
+ 0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f,
+ 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x0a, 0x20,
+ 0x2a, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
+ 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69,
+ 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69,
+ 0x6e, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x62,
+ 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x74,
+ 0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x67,
+ 0x72, 0x61, 0x6d, 0x73, 0x2c, 0x0a, 0x20, 0x2a,
+ 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20,
+ 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75,
+ 0x74, 0x65, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65,
+ 0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69,
+ 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e,
+ 0x79, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x2a,
+ 0x20, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20,
+ 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c,
+ 0x65, 0x2e, 0x20, 0x20, 0x28, 0x54, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+ 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a,
+ 0x20, 0x2a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72,
+ 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20,
+ 0x64, 0x6f, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79,
+ 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65,
+ 0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63,
+ 0x74, 0x73, 0x3b, 0x20, 0x66, 0x6f, 0x72, 0x20,
+ 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c,
+ 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6f,
+ 0x76, 0x65, 0x72, 0x0a, 0x20, 0x2a, 0x20, 0x6d,
+ 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2c,
+ 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x73,
+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f,
+ 0x6e, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x6e,
+ 0x6f, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x65,
+ 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x0a, 0x20,
+ 0x2a, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x62,
+ 0x69, 0x6e, 0x65, 0x64, 0x20, 0x65, 0x78, 0x65,
+ 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e,
+ 0x29, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20,
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c,
+ 0x65, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73,
+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64,
+ 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x68, 0x6f, 0x70, 0x65, 0x20, 0x74, 0x68, 0x61,
+ 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x6c,
+ 0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65,
+ 0x66, 0x75, 0x6c, 0x2c, 0x20, 0x62, 0x75, 0x74,
+ 0x0a, 0x20, 0x2a, 0x20, 0x57, 0x49, 0x54, 0x48,
+ 0x4f, 0x55, 0x54, 0x20, 0x41, 0x4e, 0x59, 0x20,
+ 0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x59,
+ 0x3b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75,
+ 0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x69,
+ 0x65, 0x64, 0x20, 0x77, 0x61, 0x72, 0x72, 0x61,
+ 0x6e, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x0a, 0x20,
+ 0x2a, 0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41,
+ 0x4e, 0x54, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54,
+ 0x59, 0x20, 0x6f, 0x72, 0x20, 0x46, 0x49, 0x54,
+ 0x4e, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4f, 0x52,
+ 0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49,
+ 0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55,
+ 0x52, 0x50, 0x4f, 0x53, 0x45, 0x2e, 0x20, 0x20,
+ 0x53, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x47, 0x4e, 0x55, 0x0a, 0x20, 0x2a, 0x20, 0x47,
+ 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50,
+ 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69,
+ 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f,
+ 0x72, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x64,
+ 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x0a,
+ 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x59, 0x6f,
+ 0x75, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64,
+ 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x72, 0x65,
+ 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x61,
+ 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+ 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a,
+ 0x20, 0x2a, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67,
+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68,
+ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
+ 0x61, 0x6d, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65,
+ 0x20, 0x43, 0x4f, 0x50, 0x59, 0x49, 0x4e, 0x47,
+ 0x2e, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f,
+ 0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65,
+ 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20,
+ 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+ 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x35, 0x31, 0x20,
+ 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x6c, 0x69, 0x6e,
+ 0x20, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x2c,
+ 0x20, 0x46, 0x69, 0x66, 0x74, 0x68, 0x20, 0x46,
+ 0x6c, 0x6f, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x2a,
+ 0x20, 0x42, 0x6f, 0x73, 0x74, 0x6f, 0x6e, 0x2c,
+ 0x20, 0x4d, 0x41, 0x20, 0x30, 0x32, 0x31, 0x31,
+ 0x30, 0x2d, 0x31, 0x33, 0x30, 0x31, 0x2c, 0x20,
+ 0x55, 0x53, 0x41, 0x2e, 0x0a, 0x20, 0x2a, 0x2f,
+ 0x0a,
+};
+
+static git_obj some_obj = {
+ some_data,
+ sizeof(some_data),
+ GIT_OBJ_BLOB
+};
+
+static int make_odb_dir(void)
+{
+ if (gitfo_mkdir(odb_dir, 0755) < 0) {
+ if (errno == EEXIST) {
+ fprintf(stderr, "odb directory \"%s\" already exists!\n", odb_dir);
+ return -1;
+ }
+ fprintf(stderr, "can't make odb directory \"%s\"\n", odb_dir);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int remove_object_files(object_data *d)
+{
+ if (gitfo_unlink(d->file) < 0) {
+ fprintf(stderr, "can't delete object file \"%s\"\n", d->file);
+ return -1;
+ }
+ if ((gitfo_rmdir(d->dir) < 0) && (errno != ENOTEMPTY)) {
+ fprintf(stderr, "can't remove object directory \"%s\"\n", d->dir);
+ return -1;
+ }
+
+ if (gitfo_rmdir(odb_dir) < 0) {
+ fprintf(stderr, "can't remove odb directory \"%s\"\n", odb_dir);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_object_files(object_data *d)
+{
+ if (gitfo_exists(d->dir) < 0)
+ return -1;
+ if (gitfo_exists(d->file) < 0)
+ return -1;
+ return 0;
+}
+
+static int cmp_objects(git_obj *o1, git_obj *o2)
+{
+ if (o1->type != o2->type)
+ return -1;
+ if (o1->len != o2->len)
+ return -1;
+ if ((o1->len > 0) && (memcmp(o1->data, o2->data, o1->len) != 0))
+ return -1;
+ return 0;
+}
+
+BEGIN_TEST(write_commit)
+ git_odb *db;
+ git_oid id1, id2;
+ git_obj obj;
+
+ must_pass(make_odb_dir());
+ must_pass(git_odb_open(&db, odb_dir));
+ must_pass(git_oid_mkstr(&id1, commit.id));
+
+ must_pass(git_odb_write(&id2, db, &commit_obj));
+ must_be_true(git_oid_cmp(&id1, &id2) == 0);
+ must_pass(check_object_files(&commit));
+
+ must_pass(git_odb__read_loose(&obj, db, &id1));
+ must_pass(cmp_objects(&obj, &commit_obj));
+
+ git_obj_close(&obj);
+ git_odb_close(db);
+ must_pass(remove_object_files(&commit));
+END_TEST
+
+BEGIN_TEST(write_tree)
+ git_odb *db;
+ git_oid id1, id2;
+ git_obj obj;
+
+ must_pass(make_odb_dir());
+ must_pass(git_odb_open(&db, odb_dir));
+ must_pass(git_oid_mkstr(&id1, tree.id));
+
+ must_pass(git_odb_write(&id2, db, &tree_obj));
+ must_be_true(git_oid_cmp(&id1, &id2) == 0);
+ must_pass(check_object_files(&tree));
+
+ must_pass(git_odb__read_loose(&obj, db, &id1));
+ must_pass(cmp_objects(&obj, &tree_obj));
+
+ git_obj_close(&obj);
+ git_odb_close(db);
+ must_pass(remove_object_files(&tree));
+END_TEST
+
+BEGIN_TEST(write_tag)
+ git_odb *db;
+ git_oid id1, id2;
+ git_obj obj;
+
+ must_pass(make_odb_dir());
+ must_pass(git_odb_open(&db, odb_dir));
+ must_pass(git_oid_mkstr(&id1, tag.id));
+
+ must_pass(git_odb_write(&id2, db, &tag_obj));
+ must_be_true(git_oid_cmp(&id1, &id2) == 0);
+ must_pass(check_object_files(&tag));
+
+ must_pass(git_odb__read_loose(&obj, db, &id1));
+ must_pass(cmp_objects(&obj, &tag_obj));
+
+ git_obj_close(&obj);
+ git_odb_close(db);
+ must_pass(remove_object_files(&tag));
+END_TEST
+
+BEGIN_TEST(write_zero)
+ git_odb *db;
+ git_oid id1, id2;
+ git_obj obj;
+
+ must_pass(make_odb_dir());
+ must_pass(git_odb_open(&db, odb_dir));
+ must_pass(git_oid_mkstr(&id1, zero.id));
+
+ must_pass(git_odb_write(&id2, db, &zero_obj));
+ must_be_true(git_oid_cmp(&id1, &id2) == 0);
+ must_pass(check_object_files(&zero));
+
+ must_pass(git_odb__read_loose(&obj, db, &id1));
+ must_pass(cmp_objects(&obj, &zero_obj));
+
+ git_obj_close(&obj);
+ git_odb_close(db);
+ must_pass(remove_object_files(&zero));
+END_TEST
+
+BEGIN_TEST(write_one)
+ git_odb *db;
+ git_oid id1, id2;
+ git_obj obj;
+
+ must_pass(make_odb_dir());
+ must_pass(git_odb_open(&db, odb_dir));
+ must_pass(git_oid_mkstr(&id1, one.id));
+
+ must_pass(git_odb_write(&id2, db, &one_obj));
+ must_be_true(git_oid_cmp(&id1, &id2) == 0);
+ must_pass(check_object_files(&one));
+
+ must_pass(git_odb__read_loose(&obj, db, &id1));
+ must_pass(cmp_objects(&obj, &one_obj));
+
+ git_obj_close(&obj);
+ git_odb_close(db);
+ must_pass(remove_object_files(&one));
+END_TEST
+
+BEGIN_TEST(write_two)
+ git_odb *db;
+ git_oid id1, id2;
+ git_obj obj;
+
+ must_pass(make_odb_dir());
+ must_pass(git_odb_open(&db, odb_dir));
+ must_pass(git_oid_mkstr(&id1, two.id));
+
+ must_pass(git_odb_write(&id2, db, &two_obj));
+ must_be_true(git_oid_cmp(&id1, &id2) == 0);
+ must_pass(check_object_files(&two));
+
+ must_pass(git_odb__read_loose(&obj, db, &id1));
+ must_pass(cmp_objects(&obj, &two_obj));
+
+ git_obj_close(&obj);
+ git_odb_close(db);
+ must_pass(remove_object_files(&two));
+END_TEST
+
+BEGIN_TEST(write_some)
+ git_odb *db;
+ git_oid id1, id2;
+ git_obj obj;
+
+ must_pass(make_odb_dir());
+ must_pass(git_odb_open(&db, odb_dir));
+ must_pass(git_oid_mkstr(&id1, some.id));
+
+ must_pass(git_odb_write(&id2, db, &some_obj));
+ must_be_true(git_oid_cmp(&id1, &id2) == 0);
+ must_pass(check_object_files(&some));
+
+ must_pass(git_odb__read_loose(&obj, db, &id1));
+ must_pass(cmp_objects(&obj, &some_obj));
+
+ git_obj_close(&obj);
+ git_odb_close(db);
+ must_pass(remove_object_files(&some));
+END_TEST
+