diff --git a/midx.c b/midx.c index 3d0015f782..cd6e766ce2 100644 --- a/midx.c +++ b/midx.c @@ -13,6 +13,8 @@ #include "pack-bitmap.h" #include "pack-revindex.h" +#define MIDX_PACK_ERROR ((void *)(intptr_t)-1) + int midx_checksum_valid(struct multi_pack_index *m); void clear_midx_files_ext(const char *object_dir, const char *ext, const char *keep_hash); @@ -405,7 +407,7 @@ void close_midx(struct multi_pack_index *m) munmap((unsigned char *)m->data, m->data_len); for (i = 0; i < m->num_packs; i++) { - if (m->packs[i]) + if (m->packs[i] && m->packs[i] != MIDX_PACK_ERROR) m->packs[i]->multi_pack_index = 0; } FREE_AND_NULL(m->packs); @@ -458,6 +460,8 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, pack_int_id = midx_for_pack(&m, pack_int_id); + if (m->packs[pack_int_id] == MIDX_PACK_ERROR) + return 1; if (m->packs[pack_int_id]) return 0; @@ -482,8 +486,10 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, strbuf_release(&pack_name); strbuf_release(&key); - if (!p) + if (!p) { + m->packs[pack_int_id] = MIDX_PACK_ERROR; return 1; + } p->multi_pack_index = 1; m->packs[pack_int_id] = p; @@ -495,6 +501,8 @@ struct packed_git *nth_midxed_pack(struct multi_pack_index *m, uint32_t pack_int_id) { uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id); + if (m->packs[local_pack_int_id] == MIDX_PACK_ERROR) + return NULL; return m->packs[local_pack_int_id]; } diff --git a/packfile.c b/packfile.c index 80e35f1032..70c7208f02 100644 --- a/packfile.c +++ b/packfile.c @@ -737,6 +737,17 @@ struct packed_git *add_packed_git(struct repository *r, const char *path, p = alloc_packed_git(r, alloc); memcpy(p->pack_name, path, path_len); + /* + * Note that we have to check auxiliary data structures before we check + * for the ".pack" file to exist to avoid races with a packfile that is + * in the process of being deleted. The ".pack" file is unlinked before + * its auxiliary data structures, so we know that we either get a + * consistent snapshot of all data structures or that we'll fail to + * stat(3p) the packfile itself and thus return `NULL`. + * + * As such, we cannot bail out before the access(3p) calls in case the + * packfile doesn't exist without doing two stat(3p) calls for it. + */ xsnprintf(p->pack_name + path_len, alloc - path_len, ".keep"); if (!access(p->pack_name, F_OK)) p->pack_keep = 1;