Files
git/pack-mtimes.c
Patrick Steinhardt 97dc141fd6 object-file: move git_open_cloexec() to "compat/open.c"
The `git_open_cloexec()` wrapper function provides the ability to open a
file with `O_CLOEXEC` in a platform-agnostic way. This function is
provided by "object-file.c" even though it is not specific to the object
subsystem at all.

Move the file into "compat/open.c". This file already exists before this
commit, but has only been compiled conditionally depending on whether or
not open(3p) may return EINTR. With this change we now unconditionally
compile the object, but wrap `git_open_with_retry()` in an ifdef.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-04-15 08:24:35 -07:00

133 lines
2.9 KiB
C

#include "git-compat-util.h"
#include "gettext.h"
#include "pack-mtimes.h"
#include "object-store-ll.h"
#include "packfile.h"
#include "strbuf.h"
static char *pack_mtimes_filename(struct packed_git *p)
{
size_t len;
if (!strip_suffix(p->pack_name, ".pack", &len))
BUG("pack_name does not end in .pack");
return xstrfmt("%.*s.mtimes", (int)len, p->pack_name);
}
#define MTIMES_HEADER_SIZE (12)
struct mtimes_header {
uint32_t signature;
uint32_t version;
uint32_t hash_id;
};
static int load_pack_mtimes_file(char *mtimes_file,
uint32_t num_objects,
const uint32_t **data_p, size_t *len_p)
{
int fd, ret = 0;
struct stat st;
uint32_t *data = NULL;
size_t mtimes_size, expected_size;
struct mtimes_header header;
fd = git_open(mtimes_file);
if (fd < 0) {
ret = -1;
goto cleanup;
}
if (fstat(fd, &st)) {
ret = error_errno(_("failed to read %s"), mtimes_file);
goto cleanup;
}
mtimes_size = xsize_t(st.st_size);
if (mtimes_size < MTIMES_HEADER_SIZE) {
ret = error(_("mtimes file %s is too small"), mtimes_file);
goto cleanup;
}
data = xmmap(NULL, mtimes_size, PROT_READ, MAP_PRIVATE, fd, 0);
header.signature = ntohl(data[0]);
header.version = ntohl(data[1]);
header.hash_id = ntohl(data[2]);
if (header.signature != MTIMES_SIGNATURE) {
ret = error(_("mtimes file %s has unknown signature"), mtimes_file);
goto cleanup;
}
if (header.version != 1) {
ret = error(_("mtimes file %s has unsupported version %"PRIu32),
mtimes_file, header.version);
goto cleanup;
}
if (!(header.hash_id == 1 || header.hash_id == 2)) {
ret = error(_("mtimes file %s has unsupported hash id %"PRIu32),
mtimes_file, header.hash_id);
goto cleanup;
}
expected_size = MTIMES_HEADER_SIZE;
expected_size = st_add(expected_size, st_mult(sizeof(uint32_t), num_objects));
expected_size = st_add(expected_size, 2 * (header.hash_id == 1 ? GIT_SHA1_RAWSZ : GIT_SHA256_RAWSZ));
if (mtimes_size != expected_size) {
ret = error(_("mtimes file %s is corrupt"), mtimes_file);
goto cleanup;
}
cleanup:
if (ret) {
if (data)
munmap(data, mtimes_size);
} else {
*len_p = mtimes_size;
*data_p = data;
}
if (fd >= 0)
close(fd);
return ret;
}
int load_pack_mtimes(struct packed_git *p)
{
char *mtimes_name = NULL;
int ret = 0;
if (!p->is_cruft)
return ret; /* not a cruft pack */
if (p->mtimes_map)
return ret; /* already loaded */
ret = open_pack_index(p);
if (ret < 0)
goto cleanup;
mtimes_name = pack_mtimes_filename(p);
ret = load_pack_mtimes_file(mtimes_name,
p->num_objects,
&p->mtimes_map,
&p->mtimes_size);
cleanup:
free(mtimes_name);
return ret;
}
uint32_t nth_packed_mtime(struct packed_git *p, uint32_t pos)
{
if (!p->mtimes_map)
BUG("pack .mtimes file not loaded for %s", p->pack_name);
if (p->num_objects <= pos)
BUG("pack .mtimes out-of-bounds (%"PRIu32" vs %"PRIu32")",
pos, p->num_objects);
return get_be32(p->mtimes_map + pos + 3);
}