Create a new multi_pack_index struct for loading multi-pack-indexes into
memory. Create a test-tool builtin for reading basic information about
that multi-pack-index to verify the correct data is written.

Signed-off-by: Derrick Stolee <dsto...@microsoft.com>
---
 Makefile                    |  1 +
 midx.c                      | 82 +++++++++++++++++++++++++++++++++++++
 midx.h                      |  4 ++
 object-store.h              | 16 ++++++++
 t/helper/test-read-midx.c   | 34 +++++++++++++++
 t/helper/test-tool.c        |  1 +
 t/helper/test-tool.h        |  1 +
 t/t5319-multi-pack-index.sh | 12 +++++-
 8 files changed, 150 insertions(+), 1 deletion(-)
 create mode 100644 t/helper/test-read-midx.c

diff --git a/Makefile b/Makefile
index f5636c711d..0b801d1b16 100644
--- a/Makefile
+++ b/Makefile
@@ -717,6 +717,7 @@ TEST_BUILTINS_OBJS += test-online-cpus.o
 TEST_BUILTINS_OBJS += test-path-utils.o
 TEST_BUILTINS_OBJS += test-prio-queue.o
 TEST_BUILTINS_OBJS += test-read-cache.o
+TEST_BUILTINS_OBJS += test-read-midx.o
 TEST_BUILTINS_OBJS += test-ref-store.o
 TEST_BUILTINS_OBJS += test-regex.o
 TEST_BUILTINS_OBJS += test-revision-walking.o
diff --git a/midx.c b/midx.c
index f85f2d334d..fb388f5858 100644
--- a/midx.c
+++ b/midx.c
@@ -1,18 +1,100 @@
 #include "cache.h"
 #include "csum-file.h"
 #include "lockfile.h"
+#include "object-store.h"
 #include "midx.h"
 
 #define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
 #define MIDX_VERSION 1
+#define MIDX_BYTE_FILE_VERSION 4
+#define MIDX_BYTE_HASH_VERSION 5
+#define MIDX_BYTE_NUM_CHUNKS 6
+#define MIDX_BYTE_NUM_PACKS 8
 #define MIDX_HASH_VERSION 1
 #define MIDX_HEADER_SIZE 12
+#define MIDX_HASH_LEN 20
+#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + MIDX_HASH_LEN)
 
 static char *get_midx_filename(const char *object_dir)
 {
        return xstrfmt("%s/pack/multi-pack-index", object_dir);
 }
 
+struct multi_pack_index *load_multi_pack_index(const char *object_dir)
+{
+       struct multi_pack_index *m = NULL;
+       int fd;
+       struct stat st;
+       size_t midx_size;
+       void *midx_map = NULL;
+       uint32_t hash_version;
+       char *midx_name = get_midx_filename(object_dir);
+
+       fd = git_open(midx_name);
+
+       if (fd < 0)
+               goto cleanup_fail;
+       if (fstat(fd, &st)) {
+               error_errno(_("failed to read %s"), midx_name);
+               goto cleanup_fail;
+       }
+
+       midx_size = xsize_t(st.st_size);
+
+       if (midx_size < MIDX_MIN_SIZE) {
+               close(fd);
+               error(_("multi-pack-index file %s is too small"), midx_name);
+               goto cleanup_fail;
+       }
+
+       FREE_AND_NULL(midx_name);
+
+       midx_map = xmmap(NULL, midx_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+       m = xcalloc(1, sizeof(*m) + strlen(object_dir) + 1);
+       strcpy(m->object_dir, object_dir);
+       m->fd = fd;
+       m->data = midx_map;
+       m->data_len = midx_size;
+
+       m->signature = get_be32(m->data);
+       if (m->signature != MIDX_SIGNATURE) {
+               error(_("multi-pack-index signature 0x%08x does not match 
signature 0x%08x"),
+                     m->signature, MIDX_SIGNATURE);
+               goto cleanup_fail;
+       }
+
+       m->version = m->data[MIDX_BYTE_FILE_VERSION];
+       if (m->version != MIDX_VERSION) {
+               error(_("multi-pack-index version %d not recognized"),
+                     m->version);
+               goto cleanup_fail;
+       }
+
+       hash_version = m->data[MIDX_BYTE_HASH_VERSION];
+       if (hash_version != MIDX_HASH_VERSION) {
+               error(_("hash version %u does not match"), hash_version);
+               goto cleanup_fail;
+       }
+       m->hash_len = MIDX_HASH_LEN;
+
+       m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS];
+
+       m->num_packs = get_be32(m->data + MIDX_BYTE_NUM_PACKS);
+
+       return m;
+
+cleanup_fail:
+       /* no need to check for NULL when freeing */
+       free(m);
+       free(midx_name);
+       if (midx_map)
+               munmap(midx_map, midx_size);
+       if (0 <= fd)
+               close(fd);
+       return NULL;
+}
+
 static size_t write_midx_header(struct hashfile *f,
                                unsigned char num_chunks,
                                uint32_t num_packs)
diff --git a/midx.h b/midx.h
index dbdbe9f873..2d83dd9ec1 100644
--- a/midx.h
+++ b/midx.h
@@ -1,6 +1,10 @@
 #ifndef __MIDX_H__
 #define __MIDX_H__
 
+struct multi_pack_index;
+
+struct multi_pack_index *load_multi_pack_index(const char *object_dir);
+
 int write_midx_file(const char *object_dir);
 
 #endif
diff --git a/object-store.h b/object-store.h
index d683112fd7..4f410841cc 100644
--- a/object-store.h
+++ b/object-store.h
@@ -84,6 +84,22 @@ struct packed_git {
        char pack_name[FLEX_ARRAY]; /* more */
 };
 
+struct multi_pack_index {
+       int fd;
+
+       const unsigned char *data;
+       size_t data_len;
+
+       uint32_t signature;
+       unsigned char version;
+       unsigned char hash_len;
+       unsigned char num_chunks;
+       uint32_t num_packs;
+       uint32_t num_objects;
+
+       char object_dir[FLEX_ARRAY];
+};
+
 struct raw_object_store {
        /*
         * Path to the repository's object store.
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
new file mode 100644
index 0000000000..5abf969175
--- /dev/null
+++ b/t/helper/test-read-midx.c
@@ -0,0 +1,34 @@
+/*
+ * test-mktemp.c: code to exercise the creation of temporary files
+ */
+#include "test-tool.h"
+#include "cache.h"
+#include "midx.h"
+#include "repository.h"
+#include "object-store.h"
+
+static int read_midx_file(const char *object_dir)
+{
+       struct multi_pack_index *m = load_multi_pack_index(object_dir);
+
+       if (!m)
+               return 0;
+
+       printf("header: %08x %d %d %d\n",
+              m->signature,
+              m->version,
+              m->num_chunks,
+              m->num_packs);
+
+       printf("object_dir: %s\n", m->object_dir);
+
+       return 0;
+}
+
+int cmd__read_midx(int argc, const char **argv)
+{
+       if (argc != 2)
+               usage("read-midx <object_dir>");
+
+       return read_midx_file(argv[1]);
+}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 805a45de9c..1c3ab36e6c 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -27,6 +27,7 @@ static struct test_cmd cmds[] = {
        { "path-utils", cmd__path_utils },
        { "prio-queue", cmd__prio_queue },
        { "read-cache", cmd__read_cache },
+       { "read-midx", cmd__read_midx },
        { "ref-store", cmd__ref_store },
        { "regex", cmd__regex },
        { "revision-walking", cmd__revision_walking },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 7116ddfb94..6af8c08a66 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -21,6 +21,7 @@ int cmd__online_cpus(int argc, const char **argv);
 int cmd__path_utils(int argc, const char **argv);
 int cmd__prio_queue(int argc, const char **argv);
 int cmd__read_cache(int argc, const char **argv);
+int cmd__read_midx(int argc, const char **argv);
 int cmd__ref_store(int argc, const char **argv);
 int cmd__regex(int argc, const char **argv);
 int cmd__revision_walking(int argc, const char **argv);
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index 8622a7cdce..2ecc369529 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -3,9 +3,19 @@
 test_description='multi-pack-indexes'
 . ./test-lib.sh
 
+midx_read_expect () {
+       cat >expect <<-EOF
+       header: 4d494458 1 0 0
+       object_dir: .
+       EOF
+       test-tool read-midx . >actual &&
+       test_cmp expect actual
+}
+
 test_expect_success 'write midx with no packs' '
        git multi-pack-index --object-dir=. write &&
-       test_path_is_file pack/multi-pack-index
+       test_path_is_file pack/multi-pack-index &&
+       midx_read_expect
 '
 
 test_done
-- 
2.18.0.118.gd4f65b8d14

Reply via email to