midx.con commit multi-pack-index: load into memory (4d80560)
   1#include "cache.h"
   2#include "csum-file.h"
   3#include "lockfile.h"
   4#include "object-store.h"
   5#include "midx.h"
   6
   7#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
   8#define MIDX_VERSION 1
   9#define MIDX_BYTE_FILE_VERSION 4
  10#define MIDX_BYTE_HASH_VERSION 5
  11#define MIDX_BYTE_NUM_CHUNKS 6
  12#define MIDX_BYTE_NUM_PACKS 8
  13#define MIDX_HASH_VERSION 1
  14#define MIDX_HEADER_SIZE 12
  15#define MIDX_HASH_LEN 20
  16#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + MIDX_HASH_LEN)
  17
  18static char *get_midx_filename(const char *object_dir)
  19{
  20        return xstrfmt("%s/pack/multi-pack-index", object_dir);
  21}
  22
  23struct multi_pack_index *load_multi_pack_index(const char *object_dir)
  24{
  25        struct multi_pack_index *m = NULL;
  26        int fd;
  27        struct stat st;
  28        size_t midx_size;
  29        void *midx_map = NULL;
  30        uint32_t hash_version;
  31        char *midx_name = get_midx_filename(object_dir);
  32
  33        fd = git_open(midx_name);
  34
  35        if (fd < 0)
  36                goto cleanup_fail;
  37        if (fstat(fd, &st)) {
  38                error_errno(_("failed to read %s"), midx_name);
  39                goto cleanup_fail;
  40        }
  41
  42        midx_size = xsize_t(st.st_size);
  43
  44        if (midx_size < MIDX_MIN_SIZE) {
  45                error(_("multi-pack-index file %s is too small"), midx_name);
  46                goto cleanup_fail;
  47        }
  48
  49        FREE_AND_NULL(midx_name);
  50
  51        midx_map = xmmap(NULL, midx_size, PROT_READ, MAP_PRIVATE, fd, 0);
  52
  53        FLEX_ALLOC_MEM(m, object_dir, object_dir, strlen(object_dir));
  54        m->fd = fd;
  55        m->data = midx_map;
  56        m->data_len = midx_size;
  57
  58        m->signature = get_be32(m->data);
  59        if (m->signature != MIDX_SIGNATURE) {
  60                error(_("multi-pack-index signature 0x%08x does not match signature 0x%08x"),
  61                      m->signature, MIDX_SIGNATURE);
  62                goto cleanup_fail;
  63        }
  64
  65        m->version = m->data[MIDX_BYTE_FILE_VERSION];
  66        if (m->version != MIDX_VERSION) {
  67                error(_("multi-pack-index version %d not recognized"),
  68                      m->version);
  69                goto cleanup_fail;
  70        }
  71
  72        hash_version = m->data[MIDX_BYTE_HASH_VERSION];
  73        if (hash_version != MIDX_HASH_VERSION) {
  74                error(_("hash version %u does not match"), hash_version);
  75                goto cleanup_fail;
  76        }
  77        m->hash_len = MIDX_HASH_LEN;
  78
  79        m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS];
  80
  81        m->num_packs = get_be32(m->data + MIDX_BYTE_NUM_PACKS);
  82
  83        return m;
  84
  85cleanup_fail:
  86        free(m);
  87        free(midx_name);
  88        if (midx_map)
  89                munmap(midx_map, midx_size);
  90        if (0 <= fd)
  91                close(fd);
  92        return NULL;
  93}
  94
  95static size_t write_midx_header(struct hashfile *f,
  96                                unsigned char num_chunks,
  97                                uint32_t num_packs)
  98{
  99        unsigned char byte_values[4];
 100
 101        hashwrite_be32(f, MIDX_SIGNATURE);
 102        byte_values[0] = MIDX_VERSION;
 103        byte_values[1] = MIDX_HASH_VERSION;
 104        byte_values[2] = num_chunks;
 105        byte_values[3] = 0; /* unused */
 106        hashwrite(f, byte_values, sizeof(byte_values));
 107        hashwrite_be32(f, num_packs);
 108
 109        return MIDX_HEADER_SIZE;
 110}
 111
 112int write_midx_file(const char *object_dir)
 113{
 114        unsigned char num_chunks = 0;
 115        char *midx_name;
 116        struct hashfile *f = NULL;
 117        struct lock_file lk;
 118
 119        midx_name = get_midx_filename(object_dir);
 120        if (safe_create_leading_directories(midx_name)) {
 121                UNLEAK(midx_name);
 122                die_errno(_("unable to create leading directories of %s"),
 123                          midx_name);
 124        }
 125
 126        hold_lock_file_for_update(&lk, midx_name, LOCK_DIE_ON_ERROR);
 127        f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
 128        FREE_AND_NULL(midx_name);
 129
 130        write_midx_header(f, num_chunks, 0);
 131
 132        finalize_hashfile(f, NULL, CSUM_FSYNC | CSUM_HASH_IN_STREAM);
 133        commit_lock_file(&lk);
 134
 135        return 0;
 136}