mirror of
https://github.com/git/git.git
synced 2024-05-09 13:46:08 +02:00
Merge branch 'jk/fsck-tree-mode-bits-fix'
"git fsck" reads mode from tree objects but canonicalizes the mode before passing it to the logic to check object sanity, which has hid broken tree objects from the checking logic. This has been corrected, but to help exiting projects with broken tree objects that they cannot fix retroactively, the severity of anomalies this code detects has been demoted to "info" for now. * jk/fsck-tree-mode-bits-fix: fsck: downgrade tree badFilemode to "info" fsck: actually detect bad file modes in trees tree-walk: add a mechanism for getting non-canonicalized modes
This commit is contained in:
commit
363a193c3a
4
fsck.c
4
fsck.c
|
@ -308,7 +308,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
name = fsck_get_object_name(options, &tree->object.oid);
|
name = fsck_get_object_name(options, &tree->object.oid);
|
||||||
if (init_tree_desc_gently(&desc, tree->buffer, tree->size))
|
if (init_tree_desc_gently(&desc, tree->buffer, tree->size, 0))
|
||||||
return -1;
|
return -1;
|
||||||
while (tree_entry_gently(&desc, &entry)) {
|
while (tree_entry_gently(&desc, &entry)) {
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
|
@ -578,7 +578,7 @@ static int fsck_tree(const struct object_id *tree_oid,
|
||||||
const char *o_name;
|
const char *o_name;
|
||||||
struct name_stack df_dup_candidates = { NULL };
|
struct name_stack df_dup_candidates = { NULL };
|
||||||
|
|
||||||
if (init_tree_desc_gently(&desc, buffer, size)) {
|
if (init_tree_desc_gently(&desc, buffer, size, TREE_DESC_RAW_MODES)) {
|
||||||
retval += report(options, tree_oid, OBJ_TREE,
|
retval += report(options, tree_oid, OBJ_TREE,
|
||||||
FSCK_MSG_BAD_TREE,
|
FSCK_MSG_BAD_TREE,
|
||||||
"cannot be parsed as a tree");
|
"cannot be parsed as a tree");
|
||||||
|
|
2
fsck.h
2
fsck.h
|
@ -56,7 +56,6 @@ enum fsck_msg_type {
|
||||||
FUNC(GITMODULES_PATH, ERROR) \
|
FUNC(GITMODULES_PATH, ERROR) \
|
||||||
FUNC(GITMODULES_UPDATE, ERROR) \
|
FUNC(GITMODULES_UPDATE, ERROR) \
|
||||||
/* warnings */ \
|
/* warnings */ \
|
||||||
FUNC(BAD_FILEMODE, WARN) \
|
|
||||||
FUNC(EMPTY_NAME, WARN) \
|
FUNC(EMPTY_NAME, WARN) \
|
||||||
FUNC(FULL_PATHNAME, WARN) \
|
FUNC(FULL_PATHNAME, WARN) \
|
||||||
FUNC(HAS_DOT, WARN) \
|
FUNC(HAS_DOT, WARN) \
|
||||||
|
@ -66,6 +65,7 @@ enum fsck_msg_type {
|
||||||
FUNC(ZERO_PADDED_FILEMODE, WARN) \
|
FUNC(ZERO_PADDED_FILEMODE, WARN) \
|
||||||
FUNC(NUL_IN_COMMIT, WARN) \
|
FUNC(NUL_IN_COMMIT, WARN) \
|
||||||
/* infos (reported as warnings, but ignored by default) */ \
|
/* infos (reported as warnings, but ignored by default) */ \
|
||||||
|
FUNC(BAD_FILEMODE, INFO) \
|
||||||
FUNC(GITMODULES_PARSE, INFO) \
|
FUNC(GITMODULES_PARSE, INFO) \
|
||||||
FUNC(GITIGNORE_SYMLINK, INFO) \
|
FUNC(GITIGNORE_SYMLINK, INFO) \
|
||||||
FUNC(GITATTRIBUTES_SYMLINK, INFO) \
|
FUNC(GITATTRIBUTES_SYMLINK, INFO) \
|
||||||
|
|
|
@ -2231,7 +2231,7 @@ static int add_promisor_object(const struct object_id *oid,
|
||||||
struct tree *tree = (struct tree *)obj;
|
struct tree *tree = (struct tree *)obj;
|
||||||
struct tree_desc desc;
|
struct tree_desc desc;
|
||||||
struct name_entry entry;
|
struct name_entry entry;
|
||||||
if (init_tree_desc_gently(&desc, tree->buffer, tree->size))
|
if (init_tree_desc_gently(&desc, tree->buffer, tree->size, 0))
|
||||||
/*
|
/*
|
||||||
* Error messages are given when packs are
|
* Error messages are given when packs are
|
||||||
* verified, so do not print any here.
|
* verified, so do not print any here.
|
||||||
|
|
|
@ -364,6 +364,20 @@ test_expect_success 'tree entry with type mismatch' '
|
||||||
test_i18ngrep ! "dangling blob" out
|
test_i18ngrep ! "dangling blob" out
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'tree entry with bogus mode' '
|
||||||
|
test_when_finished "remove_object \$blob" &&
|
||||||
|
test_when_finished "remove_object \$tree" &&
|
||||||
|
blob=$(echo blob | git hash-object -w --stdin) &&
|
||||||
|
blob_oct=$(echo $blob | hex2oct) &&
|
||||||
|
tree=$(printf "100000 foo\0${blob_oct}" |
|
||||||
|
git hash-object -t tree --stdin -w --literally) &&
|
||||||
|
git fsck 2>err &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
warning in tree $tree: badFilemode: contains bad file modes
|
||||||
|
EOF
|
||||||
|
test_cmp expect err
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'tag pointing to nonexistent' '
|
test_expect_success 'tag pointing to nonexistent' '
|
||||||
badoid=$(test_oid deadbeef) &&
|
badoid=$(test_oid deadbeef) &&
|
||||||
cat >invalid-tag <<-EOF &&
|
cat >invalid-tag <<-EOF &&
|
||||||
|
|
|
@ -352,4 +352,21 @@ test_expect_success \
|
||||||
grep "Cannot demote unterminatedheader" act
|
grep "Cannot demote unterminatedheader" act
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'badFilemode is not a strict error' '
|
||||||
|
git init --bare badmode.git &&
|
||||||
|
tree=$(
|
||||||
|
cd badmode.git &&
|
||||||
|
blob=$(echo blob | git hash-object -w --stdin | hex2oct) &&
|
||||||
|
printf "123456 foo\0${blob}" |
|
||||||
|
git hash-object -t tree --stdin -w --literally
|
||||||
|
) &&
|
||||||
|
|
||||||
|
rm -rf dst.git &&
|
||||||
|
git init --bare dst.git &&
|
||||||
|
git -C dst.git config transfer.fsckObjects true &&
|
||||||
|
|
||||||
|
git -C badmode.git push ../dst.git $tree:refs/tags/tree 2>err &&
|
||||||
|
grep "$tree: badFilemode" err
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
14
tree-walk.c
14
tree-walk.c
|
@ -47,17 +47,20 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
|
||||||
|
|
||||||
/* Initialize the descriptor entry */
|
/* Initialize the descriptor entry */
|
||||||
desc->entry.path = path;
|
desc->entry.path = path;
|
||||||
desc->entry.mode = canon_mode(mode);
|
desc->entry.mode = (desc->flags & TREE_DESC_RAW_MODES) ? mode : canon_mode(mode);
|
||||||
desc->entry.pathlen = len - 1;
|
desc->entry.pathlen = len - 1;
|
||||||
oidread(&desc->entry.oid, (const unsigned char *)path + len);
|
oidread(&desc->entry.oid, (const unsigned char *)path + len);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer, unsigned long size, struct strbuf *err)
|
static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer,
|
||||||
|
unsigned long size, struct strbuf *err,
|
||||||
|
enum tree_desc_flags flags)
|
||||||
{
|
{
|
||||||
desc->buffer = buffer;
|
desc->buffer = buffer;
|
||||||
desc->size = size;
|
desc->size = size;
|
||||||
|
desc->flags = flags;
|
||||||
if (size)
|
if (size)
|
||||||
return decode_tree_entry(desc, buffer, size, err);
|
return decode_tree_entry(desc, buffer, size, err);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -66,15 +69,16 @@ static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer, u
|
||||||
void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size)
|
void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size)
|
||||||
{
|
{
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
if (init_tree_desc_internal(desc, buffer, size, &err))
|
if (init_tree_desc_internal(desc, buffer, size, &err, 0))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_tree_desc_gently(struct tree_desc *desc, const void *buffer, unsigned long size)
|
int init_tree_desc_gently(struct tree_desc *desc, const void *buffer, unsigned long size,
|
||||||
|
enum tree_desc_flags flags)
|
||||||
{
|
{
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
int result = init_tree_desc_internal(desc, buffer, size, &err);
|
int result = init_tree_desc_internal(desc, buffer, size, &err, flags);
|
||||||
if (result)
|
if (result)
|
||||||
error("%s", err.buf);
|
error("%s", err.buf);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
|
|
|
@ -34,6 +34,11 @@ struct tree_desc {
|
||||||
|
|
||||||
/* counts the number of bytes left in the `buffer`. */
|
/* counts the number of bytes left in the `buffer`. */
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
|
|
||||||
|
/* option flags passed via init_tree_desc_gently() */
|
||||||
|
enum tree_desc_flags {
|
||||||
|
TREE_DESC_RAW_MODES = (1 << 0),
|
||||||
|
} flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +84,8 @@ int update_tree_entry_gently(struct tree_desc *);
|
||||||
*/
|
*/
|
||||||
void init_tree_desc(struct tree_desc *desc, const void *buf, unsigned long size);
|
void init_tree_desc(struct tree_desc *desc, const void *buf, unsigned long size);
|
||||||
|
|
||||||
int init_tree_desc_gently(struct tree_desc *desc, const void *buf, unsigned long size);
|
int init_tree_desc_gently(struct tree_desc *desc, const void *buf, unsigned long size,
|
||||||
|
enum tree_desc_flags flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Visit the next entry in a tree. Returns 1 when there are more entries
|
* Visit the next entry in a tree. Returns 1 when there are more entries
|
||||||
|
|
Loading…
Reference in New Issue