mirror of
https://github.com/git/git.git
synced 2024-11-23 18:05:29 +08:00
396f257018
When constructing a multi-pack-index file for a given object directory, read the files within the enclosed pack directory and find matches that end with ".idx" and find the correct paired packfile using add_packed_git(). Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
183 lines
4.1 KiB
C
183 lines
4.1 KiB
C
#include "cache.h"
|
|
#include "csum-file.h"
|
|
#include "dir.h"
|
|
#include "lockfile.h"
|
|
#include "packfile.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) {
|
|
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);
|
|
|
|
FLEX_ALLOC_MEM(m, object_dir, object_dir, strlen(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:
|
|
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)
|
|
{
|
|
unsigned char byte_values[4];
|
|
|
|
hashwrite_be32(f, MIDX_SIGNATURE);
|
|
byte_values[0] = MIDX_VERSION;
|
|
byte_values[1] = MIDX_HASH_VERSION;
|
|
byte_values[2] = num_chunks;
|
|
byte_values[3] = 0; /* unused */
|
|
hashwrite(f, byte_values, sizeof(byte_values));
|
|
hashwrite_be32(f, num_packs);
|
|
|
|
return MIDX_HEADER_SIZE;
|
|
}
|
|
|
|
struct pack_list {
|
|
struct packed_git **list;
|
|
uint32_t nr;
|
|
uint32_t alloc_list;
|
|
};
|
|
|
|
static void add_pack_to_midx(const char *full_path, size_t full_path_len,
|
|
const char *file_name, void *data)
|
|
{
|
|
struct pack_list *packs = (struct pack_list *)data;
|
|
|
|
if (ends_with(file_name, ".idx")) {
|
|
ALLOC_GROW(packs->list, packs->nr + 1, packs->alloc_list);
|
|
|
|
packs->list[packs->nr] = add_packed_git(full_path,
|
|
full_path_len,
|
|
0);
|
|
if (!packs->list[packs->nr]) {
|
|
warning(_("failed to add packfile '%s'"),
|
|
full_path);
|
|
return;
|
|
}
|
|
|
|
packs->nr++;
|
|
}
|
|
}
|
|
|
|
int write_midx_file(const char *object_dir)
|
|
{
|
|
unsigned char num_chunks = 0;
|
|
char *midx_name;
|
|
uint32_t i;
|
|
struct hashfile *f = NULL;
|
|
struct lock_file lk;
|
|
struct pack_list packs;
|
|
|
|
midx_name = get_midx_filename(object_dir);
|
|
if (safe_create_leading_directories(midx_name)) {
|
|
UNLEAK(midx_name);
|
|
die_errno(_("unable to create leading directories of %s"),
|
|
midx_name);
|
|
}
|
|
|
|
packs.nr = 0;
|
|
packs.alloc_list = 16;
|
|
packs.list = NULL;
|
|
ALLOC_ARRAY(packs.list, packs.alloc_list);
|
|
|
|
for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &packs);
|
|
|
|
hold_lock_file_for_update(&lk, midx_name, LOCK_DIE_ON_ERROR);
|
|
f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
|
|
FREE_AND_NULL(midx_name);
|
|
|
|
write_midx_header(f, num_chunks, packs.nr);
|
|
|
|
finalize_hashfile(f, NULL, CSUM_FSYNC | CSUM_HASH_IN_STREAM);
|
|
commit_lock_file(&lk);
|
|
|
|
for (i = 0; i < packs.nr; i++) {
|
|
if (packs.list[i]) {
|
|
close_pack(packs.list[i]);
|
|
free(packs.list[i]);
|
|
}
|
|
}
|
|
|
|
free(packs.list);
|
|
return 0;
|
|
}
|