Merge branch 'ps/odb-generic-corrupt-objects' into en/midx-missing-pack-fallback
* ps/odb-generic-corrupt-objects: odb: handle `OBJECT_INFO_DIE_IF_CORRUPT` generically odb/source: allow `read_object_info()` to bubble up error messages odb/source: let callers discern missing and corrupt objects odb/source: introduce error status when reading objects odb/source-packed: flag known-bad objects as corrupt and not missingseen
commit
48fc56621c
|
|
@ -1759,7 +1759,7 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
|
|||
struct odb_source *source = the_repository->objects->sources->next;
|
||||
for (; source; source = source->next) {
|
||||
struct odb_source_files *files = odb_source_files_downcast(source);
|
||||
if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0))
|
||||
if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0, NULL))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1786,7 +1786,7 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
|
|||
struct multi_pack_index *m = get_multi_pack_index(files->packed);
|
||||
struct pack_entry e;
|
||||
|
||||
if (m && fill_midx_entry(m, oid, &e)) {
|
||||
if (m && fill_midx_entry(m, oid, &e, NULL)) {
|
||||
want = want_object_in_pack_one(e.p, oid, exclude, found_pack, found_offset, found_mtime);
|
||||
if (want != -1)
|
||||
return want;
|
||||
|
|
@ -4171,7 +4171,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
|
|||
|
||||
for (; !found && source; source = source->next) {
|
||||
struct odb_source_files *files = odb_source_files_downcast(source);
|
||||
if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0))
|
||||
if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0, NULL))
|
||||
found = 1;
|
||||
}
|
||||
|
||||
|
|
@ -4637,7 +4637,7 @@ static int force_object_loose(struct odb_source *source,
|
|||
|
||||
for (struct odb_source *s = source->odb->sources; s; s = s->next) {
|
||||
struct odb_source_files *files = odb_source_files_downcast(s);
|
||||
if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0))
|
||||
if (!odb_source_read_object_info(&files->loose->base, oid, NULL, 0, NULL))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
10
midx.c
10
midx.c
|
|
@ -591,7 +591,8 @@ uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos)
|
|||
|
||||
int fill_midx_entry(struct multi_pack_index *m,
|
||||
const struct object_id *oid,
|
||||
struct pack_entry *e)
|
||||
struct pack_entry *e,
|
||||
struct packed_git **bad_pack)
|
||||
{
|
||||
uint32_t pos;
|
||||
uint32_t pack_int_id;
|
||||
|
|
@ -618,8 +619,11 @@ int fill_midx_entry(struct multi_pack_index *m,
|
|||
return 0;
|
||||
|
||||
if (oidset_size(&p->bad_objects) &&
|
||||
oidset_contains(&p->bad_objects, oid))
|
||||
oidset_contains(&p->bad_objects, oid)) {
|
||||
if (bad_pack && !*bad_pack)
|
||||
*bad_pack = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
e->offset = nth_midxed_offset(m, pos);
|
||||
e->p = p;
|
||||
|
|
@ -1028,7 +1032,7 @@ int verify_midx_file(struct odb_source_packed *source, unsigned flags)
|
|||
|
||||
nth_midxed_object_oid(&oid, m, pairs[i].pos);
|
||||
|
||||
if (!fill_midx_entry(m, &oid, &e)) {
|
||||
if (!fill_midx_entry(m, &oid, &e, NULL)) {
|
||||
midx_report(_("failed to load pack entry for oid[%d] = %s"),
|
||||
pairs[i].pos, oid_to_hex(&oid));
|
||||
continue;
|
||||
|
|
|
|||
3
midx.h
3
midx.h
|
|
@ -117,7 +117,8 @@ uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos);
|
|||
struct object_id *nth_midxed_object_oid(struct object_id *oid,
|
||||
struct multi_pack_index *m,
|
||||
uint32_t n);
|
||||
int fill_midx_entry(struct multi_pack_index *m, const struct object_id *oid, struct pack_entry *e);
|
||||
int fill_midx_entry(struct multi_pack_index *m, const struct object_id *oid,
|
||||
struct pack_entry *e, struct packed_git **bad_pack);
|
||||
int midx_contains_pack(struct multi_pack_index *m,
|
||||
const char *idx_or_pack_name);
|
||||
int midx_layer_contains_pack(struct multi_pack_index *m,
|
||||
|
|
|
|||
63
odb.c
63
odb.c
|
|
@ -15,7 +15,6 @@
|
|||
#include "object-name.h"
|
||||
#include "odb.h"
|
||||
#include "odb/source-inmemory.h"
|
||||
#include "packfile.h"
|
||||
#include "path.h"
|
||||
#include "promisor-remote.h"
|
||||
#include "quote.h"
|
||||
|
|
@ -547,12 +546,15 @@ static int register_all_submodule_sources(struct object_database *odb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int do_oid_object_info_extended(struct object_database *odb,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi, unsigned flags)
|
||||
static enum odb_read_status do_oid_object_info_extended(struct object_database *odb,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi, unsigned flags)
|
||||
{
|
||||
struct strbuf corrupt_err = STRBUF_INIT;
|
||||
const struct object_id *real = oid;
|
||||
enum odb_read_status ret;
|
||||
int already_retried = 0;
|
||||
bool corrupt = false;
|
||||
|
||||
if (flags & OBJECT_INFO_LOOKUP_REPLACE)
|
||||
real = lookup_replace_object(odb->repo, oid);
|
||||
|
|
@ -560,7 +562,7 @@ static int do_oid_object_info_extended(struct object_database *odb,
|
|||
if (is_null_oid(real))
|
||||
return -1;
|
||||
|
||||
if (!odb_source_read_object_info(odb->inmemory_objects, oid, oi, flags))
|
||||
if (!odb_source_read_object_info(odb->inmemory_objects, oid, oi, flags, NULL))
|
||||
return 0;
|
||||
|
||||
odb_prepare_alternates(odb);
|
||||
|
|
@ -568,9 +570,14 @@ static int do_oid_object_info_extended(struct object_database *odb,
|
|||
while (1) {
|
||||
struct odb_source *source;
|
||||
|
||||
for (source = odb->sources; source; source = source->next)
|
||||
if (!odb_source_read_object_info(source, real, oi, flags))
|
||||
return 0;
|
||||
for (source = odb->sources; source; source = source->next) {
|
||||
ret = odb_source_read_object_info(source, real, oi, flags,
|
||||
corrupt_err.len ? NULL : &corrupt_err);
|
||||
if (!ret)
|
||||
goto out;
|
||||
if (ret != ODB_READ_NOT_FOUND)
|
||||
corrupt = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the object hasn't been found we try a second read and
|
||||
|
|
@ -578,10 +585,15 @@ static int do_oid_object_info_extended(struct object_database *odb,
|
|||
* caches or reload on-disk state.
|
||||
*/
|
||||
if (!(flags & OBJECT_INFO_QUICK)) {
|
||||
for (source = odb->sources; source; source = source->next)
|
||||
if (!odb_source_read_object_info(source, real, oi,
|
||||
flags | OBJECT_INFO_SECOND_READ))
|
||||
return 0;
|
||||
for (source = odb->sources; source; source = source->next) {
|
||||
ret = odb_source_read_object_info(source, real, oi,
|
||||
flags | OBJECT_INFO_SECOND_READ,
|
||||
corrupt_err.len ? NULL : &corrupt_err);
|
||||
if (!ret)
|
||||
goto out;
|
||||
if (ret != ODB_READ_NOT_FOUND)
|
||||
corrupt = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -604,16 +616,23 @@ static int do_oid_object_info_extended(struct object_database *odb,
|
|||
}
|
||||
|
||||
if (flags & OBJECT_INFO_DIE_IF_CORRUPT) {
|
||||
const struct packed_git *p;
|
||||
if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
|
||||
die(_("replacement %s not found for %s"),
|
||||
oid_to_hex(real), oid_to_hex(oid));
|
||||
if ((p = has_packed_and_bad(odb->repo, real)))
|
||||
die(_("packed object %s (stored in %s) is corrupt"),
|
||||
oid_to_hex(real), p->pack_name);
|
||||
if (corrupt) {
|
||||
if (corrupt_err.len)
|
||||
die("%s", corrupt_err.buf);
|
||||
die(_("object %s is corrupt"), oid_to_hex(real));
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
||||
ret = corrupt ? ODB_READ_ERROR : ODB_READ_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
strbuf_release(&corrupt_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int oid_object_info_convert(struct repository *r,
|
||||
|
|
@ -696,12 +715,12 @@ static int oid_object_info_convert(struct repository *r,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int odb_read_object_info_extended(struct object_database *odb,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags)
|
||||
enum odb_read_status odb_read_object_info_extended(struct object_database *odb,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags)
|
||||
{
|
||||
int ret;
|
||||
enum odb_read_status ret;
|
||||
|
||||
if (oid->algo && (hash_algo_by_ptr(odb->repo->hash_algo) != oid->algo))
|
||||
return oid_object_info_convert(odb->repo, oid, oi, flags);
|
||||
|
|
|
|||
17
odb.h
17
odb.h
|
|
@ -435,14 +435,23 @@ enum object_info_flags {
|
|||
OBJECT_INFO_FOR_PREFETCH = (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK),
|
||||
};
|
||||
|
||||
enum odb_read_status {
|
||||
/* The read was successful. */
|
||||
ODB_READ_OK = 0,
|
||||
/* The read resulted in a generic error. */
|
||||
ODB_READ_ERROR = -1,
|
||||
/* The object could not be found. */
|
||||
ODB_READ_NOT_FOUND = -2,
|
||||
};
|
||||
|
||||
/*
|
||||
* Read object info from the object database and populate the `object_info`
|
||||
* structure. Returns 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
int odb_read_object_info_extended(struct object_database *odb,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags);
|
||||
enum odb_read_status odb_read_object_info_extended(struct object_database *odb,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags);
|
||||
|
||||
/*
|
||||
* Read a subset of object info for the given object ID. Returns an `enum
|
||||
|
|
|
|||
|
|
@ -59,18 +59,35 @@ static void odb_source_files_prepare(struct odb_source *source,
|
|||
odb_source_prepare(&files->packed->base, flags);
|
||||
}
|
||||
|
||||
static int odb_source_files_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags)
|
||||
static enum odb_read_status odb_source_files_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags,
|
||||
struct strbuf *errmsg)
|
||||
{
|
||||
struct odb_source_files *files = odb_source_files_downcast(source);
|
||||
enum odb_read_status ret_packed, ret_loose;
|
||||
|
||||
if (!odb_source_read_object_info(&files->packed->base, oid, oi, flags) ||
|
||||
!odb_source_read_object_info(&files->loose->base, oid, oi, flags))
|
||||
ret_packed = odb_source_read_object_info(&files->packed->base, oid, oi,
|
||||
flags, errmsg);
|
||||
if (!ret_packed)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
ret_loose = odb_source_read_object_info(&files->loose->base, oid, oi, flags,
|
||||
ret_packed == ODB_READ_NOT_FOUND ? errmsg : NULL);
|
||||
if (!ret_loose)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Reading the packed object may have failed even though the object
|
||||
* exists, for example because it is corrupt. Report this failure to
|
||||
* the caller in case neither of the sources was able to read the
|
||||
* object, and prefer the error of the packed source in case both
|
||||
* reads have failed.
|
||||
*/
|
||||
if (ret_packed != ODB_READ_NOT_FOUND)
|
||||
return ret_packed;
|
||||
return ret_loose;
|
||||
}
|
||||
|
||||
static int odb_source_files_read_object_stream(struct odb_read_stream **out,
|
||||
|
|
|
|||
|
|
@ -56,17 +56,18 @@ static void populate_object_info(struct odb_source_inmemory *source,
|
|||
oi->source_infop->source = &source->base;
|
||||
}
|
||||
|
||||
static int odb_source_inmemory_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags UNUSED)
|
||||
static enum odb_read_status odb_source_inmemory_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags UNUSED,
|
||||
struct strbuf *errmsg UNUSED)
|
||||
{
|
||||
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
|
||||
const struct inmemory_object *object;
|
||||
|
||||
object = find_cached_object(inmemory, oid);
|
||||
if (!object)
|
||||
return -1;
|
||||
return ODB_READ_NOT_FOUND;
|
||||
|
||||
populate_object_info(inmemory, oi, object);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
|
|||
const char *path,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags)
|
||||
enum object_info_flags flags,
|
||||
struct strbuf *errmsg)
|
||||
{
|
||||
int ret;
|
||||
int fd;
|
||||
|
|
@ -91,11 +92,16 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
|
|||
struct stat st;
|
||||
|
||||
if ((!oi || (!oi->disk_sizep && !oi->mtimep)) && (flags & OBJECT_INFO_QUICK)) {
|
||||
ret = quick_has_loose(loose, oid) ? 0 : -1;
|
||||
ret = quick_has_loose(loose, oid) ? 0 : ODB_READ_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lstat(path, &st) < 0) {
|
||||
if (errno == ENOENT) {
|
||||
ret = ODB_READ_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -113,9 +119,12 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
|
|||
|
||||
fd = git_open(path);
|
||||
if (fd < 0) {
|
||||
if (errno != ENOENT)
|
||||
error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
|
||||
ret = -1;
|
||||
if (errno == ENOENT) {
|
||||
ret = ODB_READ_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +164,7 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
|
|||
|
||||
if (parse_loose_header(hdr, oi) < 0) {
|
||||
ret = error(_("unable to parse %s header"), oid_to_hex(oid));
|
||||
goto corrupt;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*oi->typep < 0)
|
||||
|
|
@ -165,7 +174,7 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
|
|||
*oi->contentp = unpack_loose_rest(&stream, hdr, *oi->sizep, oid);
|
||||
if (!*oi->contentp) {
|
||||
ret = -1;
|
||||
goto corrupt;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,21 +182,19 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
|
|||
case ULHR_BAD:
|
||||
ret = error(_("unable to unpack %s header"),
|
||||
oid_to_hex(oid));
|
||||
goto corrupt;
|
||||
goto out;
|
||||
case ULHR_TOO_LONG:
|
||||
ret = error(_("header for %s too long, exceeds %d bytes"),
|
||||
oid_to_hex(oid), MAX_HEADER_LEN);
|
||||
goto corrupt;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
corrupt:
|
||||
if (ret && (flags & OBJECT_INFO_DIE_IF_CORRUPT))
|
||||
die(_("loose object %s (stored in %s) is corrupt"),
|
||||
oid_to_hex(oid), path);
|
||||
|
||||
out:
|
||||
if (ret && ret != ODB_READ_NOT_FOUND && errmsg)
|
||||
strbuf_addf(errmsg, _("loose object %s (stored in %s) is corrupt"),
|
||||
oid_to_hex(oid), path);
|
||||
if (stream_to_end)
|
||||
git_inflate_end(stream_to_end);
|
||||
if (map)
|
||||
|
|
@ -206,10 +213,11 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int odb_source_loose_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags)
|
||||
static enum odb_read_status odb_source_loose_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags,
|
||||
struct strbuf *errmsg)
|
||||
{
|
||||
struct odb_source_loose *loose = odb_source_loose_downcast(source);
|
||||
static struct strbuf buf = STRBUF_INIT;
|
||||
|
|
@ -221,10 +229,10 @@ static int odb_source_loose_read_object_info(struct odb_source *source,
|
|||
* second time.
|
||||
*/
|
||||
if (flags & OBJECT_INFO_SECOND_READ)
|
||||
return -1;
|
||||
return ODB_READ_NOT_FOUND;
|
||||
|
||||
odb_loose_path(loose, &buf, oid);
|
||||
return read_object_info_from_path(loose, buf.buf, oid, oi, flags);
|
||||
return read_object_info_from_path(loose, buf.buf, oid, oi, flags, errmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -421,7 +429,7 @@ static int for_each_object_wrapper_cb(const struct object_id *oid,
|
|||
if (data->request) {
|
||||
struct object_info oi = *data->request;
|
||||
|
||||
if (read_object_info_from_path(data->loose, path, oid, &oi, 0) < 0)
|
||||
if (read_object_info_from_path(data->loose, path, oid, &oi, 0, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
return data->cb(oid, &oi, data->cb_data);
|
||||
|
|
@ -439,7 +447,7 @@ static int for_each_prefixed_object_wrapper_cb(const struct object_id *oid,
|
|||
struct object_info oi = *data->request;
|
||||
|
||||
if (odb_source_read_object_info(&data->loose->base,
|
||||
oid, &oi, 0) < 0)
|
||||
oid, &oi, 0, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
return data->cb(oid, &oi, data->cb_data);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
#include "abspath.h"
|
||||
#include "chdir-notify.h"
|
||||
#include "dir.h"
|
||||
#include "gettext.h"
|
||||
#include "git-zlib.h"
|
||||
#include "hex.h"
|
||||
#include "list-objects-filter-options.h"
|
||||
#include "mergesort.h"
|
||||
#include "midx.h"
|
||||
|
|
@ -10,21 +12,23 @@
|
|||
#include "odb/streaming.h"
|
||||
#include "packfile.h"
|
||||
#include "pack-bitmap.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
static int find_pack_entry(struct odb_source_packed *store,
|
||||
const struct object_id *oid,
|
||||
struct pack_entry *e)
|
||||
struct pack_entry *e,
|
||||
struct packed_git **bad_pack)
|
||||
{
|
||||
struct packfile_list_entry *l;
|
||||
|
||||
odb_source_prepare(&store->base, 0);
|
||||
if (store->midx && fill_midx_entry(store->midx, oid, e))
|
||||
if (store->midx && fill_midx_entry(store->midx, oid, e, bad_pack))
|
||||
return 1;
|
||||
|
||||
for (l = store->packs.head; l; l = l->next) {
|
||||
struct packed_git *p = l->pack;
|
||||
|
||||
if (!p->multi_pack_index && packfile_fill_entry(p, oid, e)) {
|
||||
if (!p->multi_pack_index && packfile_fill_entry(p, oid, e, bad_pack)) {
|
||||
if (!store->skip_mru_updates)
|
||||
packfile_list_prepend(&store->packs, p);
|
||||
return 1;
|
||||
|
|
@ -34,12 +38,14 @@ static int find_pack_entry(struct odb_source_packed *store,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int odb_source_packed_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags)
|
||||
static enum odb_read_status odb_source_packed_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags,
|
||||
struct strbuf *errmsg)
|
||||
{
|
||||
struct odb_source_packed *packed = odb_source_packed_downcast(source);
|
||||
struct packed_git *bad_pack = NULL;
|
||||
struct pack_entry e;
|
||||
int ret;
|
||||
|
||||
|
|
@ -51,23 +57,45 @@ static int odb_source_packed_read_object_info(struct odb_source *source,
|
|||
if (flags & OBJECT_INFO_SECOND_READ)
|
||||
odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
|
||||
|
||||
if (!find_pack_entry(packed, oid, &e))
|
||||
return 1;
|
||||
if (!find_pack_entry(packed, oid, &e, &bad_pack)) {
|
||||
/*
|
||||
* The lookup may have failed because the object is known to be
|
||||
* corrupt in one of the packfiles. Report the object as
|
||||
* corrupt instead of missing in that case.
|
||||
*/
|
||||
if (bad_pack) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ODB_READ_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We know that the caller doesn't actually need the
|
||||
* information below, so return early.
|
||||
*/
|
||||
if (!oi)
|
||||
return 0;
|
||||
if (!oi) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = packed_object_info(packed, e.p, e.offset, oi);
|
||||
if (ret < 0) {
|
||||
bad_pack = e.p;
|
||||
mark_bad_packed_object(e.p, oid);
|
||||
return -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (ret < 0 && bad_pack && errmsg)
|
||||
strbuf_addf(errmsg, _("packed object %s (stored in %s) is corrupt"),
|
||||
oid_to_hex(oid), bad_pack->pack_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int odb_source_packed_read_object_stream(struct odb_read_stream **out,
|
||||
|
|
@ -77,7 +105,7 @@ static int odb_source_packed_read_object_stream(struct odb_read_stream **out,
|
|||
struct odb_source_packed *packed = odb_source_packed_downcast(source);
|
||||
struct pack_entry e;
|
||||
|
||||
if (!find_pack_entry(packed, oid, &e))
|
||||
if (!find_pack_entry(packed, oid, &e, NULL))
|
||||
return -1;
|
||||
|
||||
return packfile_read_object_stream(out, oid, e.p, e.offset);
|
||||
|
|
@ -583,7 +611,7 @@ static int odb_source_packed_freshen_object(struct odb_source *source,
|
|||
timesp = ×
|
||||
}
|
||||
|
||||
if (!find_pack_entry(packed, oid, &e))
|
||||
if (!find_pack_entry(packed, oid, &e, NULL))
|
||||
return 0;
|
||||
if (e.p->is_cruft)
|
||||
return 0;
|
||||
|
|
|
|||
34
odb/source.h
34
odb/source.h
|
|
@ -27,6 +27,7 @@ enum odb_source_type {
|
|||
|
||||
struct object_id;
|
||||
struct odb_read_stream;
|
||||
struct strbuf;
|
||||
struct strvec;
|
||||
|
||||
/*
|
||||
|
|
@ -110,13 +111,17 @@ struct odb_source {
|
|||
* second read in case they know that the first read would have
|
||||
* already surfaced the object without reloading any on-disk state.
|
||||
*
|
||||
* The callback is expected to return a negative error code in case
|
||||
* reading the object has failed, 0 otherwise.
|
||||
* The callback is expected to return an `enum odb_read_status`. Please
|
||||
* refer to the individual values that can be returned. In case reading
|
||||
* the object has failed with a generic error and `errmsg` is non-NULL,
|
||||
* the callback is expected to populate it with a human-readable
|
||||
* message that describes the failure.
|
||||
*/
|
||||
int (*read_object_info)(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags);
|
||||
enum odb_read_status (*read_object_info)(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags,
|
||||
struct strbuf *errmsg);
|
||||
|
||||
/*
|
||||
* This callback is expected to create a new read stream that can be
|
||||
|
|
@ -340,14 +345,19 @@ static inline void odb_source_prepare(struct odb_source *source,
|
|||
|
||||
/*
|
||||
* Read an object from the object database source identified by its object ID.
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
* Please refer to `enum odb_read_status` for the individual error codes.
|
||||
*
|
||||
* In case reading the object has failed with a generic error and `errmsg` is
|
||||
* non-NULL it will be populated with a human-readable message that describes
|
||||
* the failure.
|
||||
*/
|
||||
static inline int odb_source_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags)
|
||||
static inline enum odb_read_status odb_source_read_object_info(struct odb_source *source,
|
||||
const struct object_id *oid,
|
||||
struct object_info *oi,
|
||||
enum object_info_flags flags,
|
||||
struct strbuf *errmsg)
|
||||
{
|
||||
return source->read_object_info(source, oid, oi, flags);
|
||||
return source->read_object_info(source, oid, oi, flags, errmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
29
packfile.c
29
packfile.c
|
|
@ -985,23 +985,6 @@ void mark_bad_packed_object(struct packed_git *p, const struct object_id *oid)
|
|||
oidset_insert(&p->bad_objects, oid);
|
||||
}
|
||||
|
||||
const struct packed_git *has_packed_and_bad(struct repository *r,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
struct odb_source *source;
|
||||
|
||||
for (source = r->objects->sources; source; source = source->next) {
|
||||
struct odb_source_files *files = odb_source_files_downcast(source);
|
||||
struct packfile_list_entry *e;
|
||||
|
||||
for (e = files->packed->packs.head; e; e = e->next)
|
||||
if (oidset_contains(&e->pack->bad_objects, oid))
|
||||
return e->pack;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
off_t get_delta_base(struct packed_git *p,
|
||||
struct pack_window **w_curs,
|
||||
off_t *curpos,
|
||||
|
|
@ -1859,13 +1842,17 @@ int is_pack_valid(struct packed_git *p)
|
|||
|
||||
int packfile_fill_entry(struct packed_git *p,
|
||||
const struct object_id *oid,
|
||||
struct pack_entry *e)
|
||||
struct pack_entry *e,
|
||||
struct packed_git **bad_pack)
|
||||
{
|
||||
off_t offset;
|
||||
|
||||
if (oidset_size(&p->bad_objects) &&
|
||||
oidset_contains(&p->bad_objects, oid))
|
||||
oidset_contains(&p->bad_objects, oid)) {
|
||||
if (bad_pack && !*bad_pack)
|
||||
*bad_pack = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = find_pack_entry_one(oid, p);
|
||||
if (!offset)
|
||||
|
|
@ -1941,7 +1928,7 @@ int has_object_pack(struct repository *r, const struct object_id *oid)
|
|||
odb_prepare_alternates(r->objects);
|
||||
for (source = r->objects->sources; source; source = source->next) {
|
||||
struct odb_source_files *files = odb_source_files_downcast(source);
|
||||
if (!odb_source_read_object_info(&files->packed->base, oid, NULL, 0))
|
||||
if (!odb_source_read_object_info(&files->packed->base, oid, NULL, 0, NULL))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -1962,7 +1949,7 @@ int has_object_kept_pack(struct repository *r, const struct object_id *oid,
|
|||
|
||||
for (; *cache; cache++) {
|
||||
struct packed_git *p = *cache;
|
||||
if (packfile_fill_entry(p, oid, &e))
|
||||
if (packfile_fill_entry(p, oid, &e, NULL))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -294,7 +294,8 @@ off_t find_pack_entry_one(const struct object_id *oid, struct packed_git *);
|
|||
|
||||
int packfile_fill_entry(struct packed_git *p,
|
||||
const struct object_id *oid,
|
||||
struct pack_entry *e);
|
||||
struct pack_entry *e,
|
||||
struct packed_git **bad_pack);
|
||||
|
||||
int is_pack_valid(struct packed_git *);
|
||||
void *unpack_entry(struct repository *r, struct packed_git *, off_t,
|
||||
|
|
@ -328,7 +329,6 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source,
|
|||
uint32_t *maybe_index_pos, struct object_info *oi);
|
||||
|
||||
void mark_bad_packed_object(struct packed_git *, const struct object_id *);
|
||||
const struct packed_git *has_packed_and_bad(struct repository *, const struct object_id *);
|
||||
|
||||
int has_object_pack(struct repository *r, const struct object_id *oid);
|
||||
int has_object_kept_pack(struct repository *r, const struct object_id *oid,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ static int read_midx_file(const char *object_dir, const char *checksum,
|
|||
for (i = 0; i < m->num_objects; i++) {
|
||||
nth_midxed_object_oid(&oid, m,
|
||||
i + m->num_objects_in_base);
|
||||
fill_midx_entry(m, &oid, &e);
|
||||
fill_midx_entry(m, &oid, &e, NULL);
|
||||
|
||||
printf("%s %"PRIu64"\t%s\n",
|
||||
oid_to_hex(&oid), e.offset, e.p->pack_name);
|
||||
|
|
|
|||
|
|
@ -145,4 +145,22 @@ test_expect_success 'partial clone of corrupted repository' '
|
|||
test_must_fail git -C corrupt-partial checkout --force
|
||||
'
|
||||
|
||||
test_expect_success 'corrupted loose commit can be read from alternate' '
|
||||
git init repo-a &&
|
||||
tree=$(git -C repo-a write-tree) &&
|
||||
commit=$(git -C repo-a commit-tree $tree </dev/null) &&
|
||||
|
||||
cp -r repo-a repo-b &&
|
||||
(
|
||||
cd repo-b &&
|
||||
echo ../../../repo-a/.git/objects >.git/objects/info/alternates &&
|
||||
corrupt_byte "$commit" 1
|
||||
) &&
|
||||
|
||||
git -C repo-a cat-file -p "$commit" >expect &&
|
||||
git -C repo-b cat-file -p "$commit" >actual 2>err &&
|
||||
test_cmp expect actual &&
|
||||
test_grep "inflate: data stream error" err
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ static void cl_assert_object_info(struct odb_source_inmemory *source,
|
|||
.contentp = &actual_content,
|
||||
};
|
||||
|
||||
cl_must_pass(odb_source_read_object_info(&source->base, oid, &oi, 0));
|
||||
cl_must_pass(odb_source_read_object_info(&source->base, oid, &oi, 0, NULL));
|
||||
cl_assert_equal_u(actual_size, strlen(expected_content));
|
||||
cl_assert_equal_u(actual_type, expected_type);
|
||||
cl_assert_equal_s((char *) actual_content, expected_content);
|
||||
|
|
@ -72,7 +72,8 @@ void test_odb_inmemory__read_missing_object(void)
|
|||
const char *end;
|
||||
|
||||
cl_must_pass(parse_oid_hex_algop(RANDOM_OID, &oid, &end, repo.hash_algo));
|
||||
cl_must_fail(odb_source_read_object_info(&source->base, &oid, NULL, 0));
|
||||
cl_assert_equal_i(odb_source_read_object_info(&source->base, &oid, NULL, 0, NULL),
|
||||
ODB_READ_NOT_FOUND);
|
||||
|
||||
odb_source_free(&source->base);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue