As we build the multi-pack-index feature by adding chunks at a time,
we want to test that the data is being written correctly.

Create struct midxed_git to store an in-memory representation of a
multi-pack-index and a memory-map of the binary file. Initialize this
struct in load_midxed_git(object_dir).

Create the 'git midx read' subcommand to output basic information about
the multi-pack-index file. This will be expanded as more information is
written to the file.

Signed-off-by: Derrick Stolee <dsto...@microsoft.com>
---
 Documentation/git-midx.txt | 11 +++++++
 builtin/midx.c             | 23 +++++++++++++-
 midx.c                     | 65 ++++++++++++++++++++++++++++++++++++++
 midx.h                     |  9 ++++++
 object-store.h             | 19 +++++++++++
 t/t5319-midx.sh            | 12 ++++++-
 6 files changed, 137 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-midx.txt b/Documentation/git-midx.txt
index dcaeb1a91b..919283fdd8 100644
--- a/Documentation/git-midx.txt
+++ b/Documentation/git-midx.txt
@@ -23,6 +23,11 @@ OPTIONS
        <dir>/packs/multi-pack-index for the current MIDX file, and
        <dir>/packs for the pack-files to index.
 
+read::
+       When given as the verb, read the current MIDX file and output
+       basic information about its contents. Used for debugging
+       purposes only.
+
 write::
        When given as the verb, write a new MIDX file to
        <dir>/packs/multi-pack-index.
@@ -43,6 +48,12 @@ $ git midx write
 $ git midx --object-dir <alt> write
 -------------------------------------------
 
+* Read the MIDX file in the .git/objects folder.
++
+-------------------------------------------
+$ git midx read
+-------------------------------------------
+
 
 GIT
 ---
diff --git a/builtin/midx.c b/builtin/midx.c
index dc0a5acd3f..c7002f664a 100644
--- a/builtin/midx.c
+++ b/builtin/midx.c
@@ -6,7 +6,7 @@
 #include "midx.h"
 
 static char const * const builtin_midx_usage[] ={
-       N_("git midx [--object-dir <dir>] [write]"),
+       N_("git midx [--object-dir <dir>] [read|write]"),
        NULL
 };
 
@@ -14,6 +14,25 @@ static struct opts_midx {
        const char *object_dir;
 } opts;
 
+static int read_midx_file(const char *object_dir)
+{
+       struct midxed_git *m = load_midxed_git(object_dir);
+
+       if (!m)
+               return 0;
+
+       printf("header: %08x %d %d %d %d\n",
+              m->signature,
+              m->version,
+              m->hash_version,
+              m->num_chunks,
+              m->num_packs);
+
+       printf("object_dir: %s\n", m->object_dir);
+
+       return 0;
+}
+
 int cmd_midx(int argc, const char **argv, const char *prefix)
 {
        static struct option builtin_midx_options[] = {
@@ -38,6 +57,8 @@ int cmd_midx(int argc, const char **argv, const char *prefix)
        if (argc == 0)
                return 0;
 
+       if (!strcmp(argv[0], "read"))
+               return read_midx_file(opts.object_dir);
        if (!strcmp(argv[0], "write"))
                return write_midx_file(opts.object_dir);
 
diff --git a/midx.c b/midx.c
index 3e55422a21..fa18770f1d 100644
--- a/midx.c
+++ b/midx.c
@@ -3,12 +3,15 @@
 #include "dir.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_HASH_VERSION 1 /* SHA-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)
 {
@@ -18,6 +21,68 @@ static char *get_midx_filename(const char *object_dir)
        return strbuf_detach(&midx_name, NULL);
 }
 
+struct midxed_git *load_midxed_git(const char *object_dir)
+{
+       struct midxed_git *m;
+       int fd;
+       struct stat st;
+       size_t midx_size;
+       void *midx_map;
+       const char *midx_name = get_midx_filename(object_dir);
+
+       fd = git_open(midx_name);
+       if (fd < 0)
+               return NULL;
+       if (fstat(fd, &st)) {
+               close(fd);
+               return NULL;
+       }
+       midx_size = xsize_t(st.st_size);
+
+       if (midx_size < MIDX_MIN_SIZE) {
+               close(fd);
+               die("multi-pack-index file %s is too small", 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->data = midx_map;
+
+       m->signature = get_be32(m->data);
+       if (m->signature != MIDX_SIGNATURE) {
+               error("multi-pack-index signature %X does not match signature 
%X",
+                     m->signature, MIDX_SIGNATURE);
+               goto cleanup_fail;
+       }
+
+       m->version = *(m->data + 4);
+       if (m->version != MIDX_VERSION) {
+               error("multi-pack-index version %d not recognized",
+                     m->version);
+               goto cleanup_fail;
+       }
+
+       m->hash_version = *(m->data + 5);
+       if (m->hash_version != MIDX_HASH_VERSION) {
+               error("hash version %d not recognized", m->hash_version);
+               goto cleanup_fail;
+       }
+       m->hash_len = MIDX_HASH_LEN;
+
+       m->num_chunks = *(m->data + 6);
+       m->num_packs = get_be32(m->data + 8);
+
+       return m;
+
+cleanup_fail:
+       FREE_AND_NULL(m);
+       munmap(midx_map, midx_size);
+       close(fd);
+       exit(1);
+}
+
 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 3a63673952..a1d18ed991 100644
--- a/midx.h
+++ b/midx.h
@@ -1,4 +1,13 @@
+#ifndef MIDX_H
+#define MIDX_H
+
+#include "git-compat-util.h"
 #include "cache.h"
+#include "object-store.h"
 #include "packfile.h"
 
+struct midxed_git *load_midxed_git(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..77cb82621a 100644
--- a/object-store.h
+++ b/object-store.h
@@ -84,6 +84,25 @@ struct packed_git {
        char pack_name[FLEX_ARRAY]; /* more */
 };
 
+struct midxed_git {
+       struct midxed_git *next;
+
+       int fd;
+
+       const unsigned char *data;
+       size_t data_len;
+
+       uint32_t signature;
+       unsigned char version;
+       unsigned char hash_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/t5319-midx.sh b/t/t5319-midx.sh
index 80f9389837..e78514d8e9 100755
--- a/t/t5319-midx.sh
+++ b/t/t5319-midx.sh
@@ -3,9 +3,19 @@
 test_description='multi-pack-indexes'
 . ./test-lib.sh
 
+midx_read_expect() {
+       cat >expect <<- EOF
+       header: 4d494458 1 1 0 0
+       object_dir: .
+       EOF
+       git midx read --object-dir=. >actual &&
+       test_cmp expect actual
+}
+
 test_expect_success 'write midx with no packs' '
        git midx --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.rc1

Reply via email to