Skip to content

Commit f227fc7

Browse files
peffgitster
authored andcommitted
cat-file: make --allow-unknown-type a noop
The cat-file command has some minor support for handling objects with "unknown" types. I.e., strings that are not "blob", "commit", "tree", or "tag". In theory this could be used for debugging or experimenting with extensions to Git. But in practice this support is not very useful: 1. You can get the type and size of such objects, but nothing else. Not even the contents! 2. Only loose objects are supported, since packfiles use numeric ids for the types, rather than strings. 3. Likewise you cannot ever transfer objects between repositories, because they cannot be represented in the packfiles used for the on-the-wire protocol. The support for these unknown types complicates the object-parsing code, and has led to bugs such as b748ddb (unpack_loose_header(): fix infinite loop on broken zlib input, 2025-02-25). So let's drop it. The first step is to remove the user-facing parts, which are accessible only via cat-file. This is technically backwards-incompatible, but given the limitations listed above, these objects couldn't possibly be useful in any workflow. However, we can't just rip out the option entirely. That would hurt a caller who ran: git cat-file -t --allow-unknown-object <oid> and fed it normal, well-formed objects. There --allow-unknown-type was doing nothing, but we wouldn't want to start bailing with an error. So to protect any such callers, we'll retain --allow-unknown-type as a noop. The code change is fairly small (but we'll able to clean up more code in follow-on patches). The test updates drop any use of the option. We still retain tests that feed the broken objects to cat-file without --allow-unknown-type, as we should continue to confirm that those objects are rejected. Note that in one spot we can drop a layer of loop, re-indenting the body; viewing the diff with "-w" helps there. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 53eeed0 commit f227fc7

File tree

3 files changed

+56
-179
lines changed

3 files changed

+56
-179
lines changed

Documentation/git-cat-file.adoc

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ SYNOPSIS
99
--------
1010
[verse]
1111
'git cat-file' <type> <object>
12-
'git cat-file' (-e | -p) <object>
13-
'git cat-file' (-t | -s) [--allow-unknown-type] <object>
12+
'git cat-file' (-e | -p | -t | -s) <object>
1413
'git cat-file' (--textconv | --filters)
1514
[<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
1615
'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
@@ -202,9 +201,6 @@ flush::
202201
only once, even if it is stored multiple times in the
203202
repository.
204203

205-
--allow-unknown-type::
206-
Allow `-s` or `-t` to query broken/corrupt objects of unknown type.
207-
208204
--follow-symlinks::
209205
With `--batch` or `--batch-check`, follow symlinks inside the
210206
repository when requesting objects with extended SHA-1

builtin/cat-file.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ static int stream_blob(const struct object_id *oid)
100100
return 0;
101101
}
102102

103-
static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
104-
int unknown_type)
103+
static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
105104
{
106105
int ret;
107106
struct object_id oid;
@@ -121,9 +120,6 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
121120
if (!path && opt_cw)
122121
get_oid_flags |= GET_OID_REQUIRE_PATH;
123122

124-
if (unknown_type)
125-
flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
126-
127123
if (get_oid_with_context(the_repository, obj_name, get_oid_flags, &oid,
128124
&obj_context))
129125
die("Not a valid object name %s", obj_name);
@@ -1038,8 +1034,7 @@ int cmd_cat_file(int argc,
10381034

10391035
const char * const builtin_catfile_usage[] = {
10401036
N_("git cat-file <type> <object>"),
1041-
N_("git cat-file (-e | -p) <object>"),
1042-
N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
1037+
N_("git cat-file (-e | -p | -t | -s) <object>"),
10431038
N_("git cat-file (--textconv | --filters)\n"
10441039
" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
10451040
N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
@@ -1057,8 +1052,8 @@ int cmd_cat_file(int argc,
10571052
OPT_GROUP(N_("Emit [broken] object attributes")),
10581053
OPT_CMDMODE('t', NULL, &opt, N_("show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"), 't'),
10591054
OPT_CMDMODE('s', NULL, &opt, N_("show object size"), 's'),
1060-
OPT_BOOL(0, "allow-unknown-type", &unknown_type,
1061-
N_("allow -s and -t to work with broken/corrupt objects")),
1055+
OPT_HIDDEN_BOOL(0, "allow-unknown-type", &unknown_type,
1056+
N_("historical option -- no-op")),
10621057
OPT_BOOL(0, "use-mailmap", &use_mailmap, N_("use mail map file")),
10631058
OPT_ALIAS(0, "mailmap", "use-mailmap"),
10641059
/* Batch mode */
@@ -1209,10 +1204,7 @@ int cmd_cat_file(int argc,
12091204
obj_name = argv[1];
12101205
}
12111206

1212-
if (unknown_type && opt != 't' && opt != 's')
1213-
die("git cat-file --allow-unknown-type: use with -s or -t");
1214-
1215-
ret = cat_one_file(opt, exp_type, obj_name, unknown_type);
1207+
ret = cat_one_file(opt, exp_type, obj_name);
12161208

12171209
out:
12181210
list_objects_filter_release(&batch.objects_filter);

t/t1006-cat-file.sh

Lines changed: 50 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -136,18 +136,6 @@ $content"
136136
test_cmp expect actual
137137
'
138138

139-
test_expect_success "Type of $type is correct using --allow-unknown-type" '
140-
echo $type >expect &&
141-
git cat-file -t --allow-unknown-type $oid >actual &&
142-
test_cmp expect actual
143-
'
144-
145-
test_expect_success "Size of $type is correct using --allow-unknown-type" '
146-
echo $size >expect &&
147-
git cat-file -s --allow-unknown-type $oid >actual &&
148-
test_cmp expect actual
149-
'
150-
151139
test -z "$content" ||
152140
test_expect_success "Content of $type is correct" '
153141
echo_without_newline "$content" >expect &&
@@ -677,95 +665,67 @@ test_expect_success 'setup bogus data' '
677665
bogus_long_oid=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin)
678666
'
679667

680-
for arg1 in '' --allow-unknown-type
668+
for arg1 in -s -t -p
681669
do
682-
for arg2 in -s -t -p
683-
do
684-
if test "$arg1" = "--allow-unknown-type" && test "$arg2" = "-p"
685-
then
686-
continue
687-
fi
670+
test_expect_success "cat-file $arg1 error on bogus short OID" '
671+
cat >expect <<-\EOF &&
672+
fatal: invalid object type
673+
EOF
688674
675+
test_must_fail git cat-file $arg1 $bogus_short_oid >out 2>actual &&
676+
test_must_be_empty out &&
677+
test_cmp expect actual
678+
'
689679

690-
test_expect_success "cat-file $arg1 $arg2 error on bogus short OID" '
691-
cat >expect <<-\EOF &&
692-
fatal: invalid object type
680+
test_expect_success "cat-file $arg1 error on bogus full OID" '
681+
if test "$arg1" = "-p"
682+
then
683+
cat >expect <<-EOF
684+
error: header for $bogus_long_oid too long, exceeds 32 bytes
685+
fatal: Not a valid object name $bogus_long_oid
686+
EOF
687+
else
688+
cat >expect <<-EOF
689+
error: header for $bogus_long_oid too long, exceeds 32 bytes
690+
fatal: git cat-file: could not get object info
693691
EOF
692+
fi &&
694693
695-
if test "$arg1" = "--allow-unknown-type"
696-
then
697-
git cat-file $arg1 $arg2 $bogus_short_oid
698-
else
699-
test_must_fail git cat-file $arg1 $arg2 $bogus_short_oid >out 2>actual &&
700-
test_must_be_empty out &&
701-
test_cmp expect actual
702-
fi
703-
'
694+
test_must_fail git cat-file $arg1 $bogus_long_oid >out 2>actual &&
695+
test_must_be_empty out &&
696+
test_cmp expect actual
697+
'
704698

705-
test_expect_success "cat-file $arg1 $arg2 error on bogus full OID" '
706-
if test "$arg2" = "-p"
707-
then
708-
cat >expect <<-EOF
709-
error: header for $bogus_long_oid too long, exceeds 32 bytes
710-
fatal: Not a valid object name $bogus_long_oid
711-
EOF
712-
else
713-
cat >expect <<-EOF
714-
error: header for $bogus_long_oid too long, exceeds 32 bytes
715-
fatal: git cat-file: could not get object info
716-
EOF
717-
fi &&
718-
719-
if test "$arg1" = "--allow-unknown-type"
720-
then
721-
git cat-file $arg1 $arg2 $bogus_short_oid
722-
else
723-
test_must_fail git cat-file $arg1 $arg2 $bogus_long_oid >out 2>actual &&
724-
test_must_be_empty out &&
725-
test_cmp expect actual
726-
fi
727-
'
699+
test_expect_success "cat-file $arg1 error on missing short OID" '
700+
cat >expect.err <<-EOF &&
701+
fatal: Not a valid object name $(test_oid deadbeef_short)
702+
EOF
703+
test_must_fail git cat-file $arg1 $(test_oid deadbeef_short) >out 2>err.actual &&
704+
test_must_be_empty out &&
705+
test_cmp expect.err err.actual
706+
'
728707

729-
test_expect_success "cat-file $arg1 $arg2 error on missing short OID" '
730-
cat >expect.err <<-EOF &&
731-
fatal: Not a valid object name $(test_oid deadbeef_short)
708+
test_expect_success "cat-file $arg1 error on missing full OID" '
709+
if test "$arg1" = "-p"
710+
then
711+
cat >expect.err <<-EOF
712+
fatal: Not a valid object name $(test_oid deadbeef)
732713
EOF
733-
test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef_short) >out 2>err.actual &&
734-
test_must_be_empty out &&
735-
test_cmp expect.err err.actual
736-
'
737-
738-
test_expect_success "cat-file $arg1 $arg2 error on missing full OID" '
739-
if test "$arg2" = "-p"
740-
then
741-
cat >expect.err <<-EOF
742-
fatal: Not a valid object name $(test_oid deadbeef)
743-
EOF
744-
else
745-
cat >expect.err <<-\EOF
746-
fatal: git cat-file: could not get object info
747-
EOF
748-
fi &&
749-
test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef) >out 2>err.actual &&
750-
test_must_be_empty out &&
751-
test_cmp expect.err err.actual
752-
'
753-
done
714+
else
715+
cat >expect.err <<-\EOF
716+
fatal: git cat-file: could not get object info
717+
EOF
718+
fi &&
719+
test_must_fail git cat-file $arg1 $(test_oid deadbeef) >out 2>err.actual &&
720+
test_must_be_empty out &&
721+
test_cmp expect.err err.actual
722+
'
754723
done
755724

756-
test_expect_success '-e is OK with a broken object without --allow-unknown-type' '
725+
test_expect_success '-e is OK with a broken object' '
757726
git cat-file -e $bogus_short_oid
758727
'
759728

760-
test_expect_success '-e can not be combined with --allow-unknown-type' '
761-
test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_oid
762-
'
763-
764-
test_expect_success '-p cannot print a broken object even with --allow-unknown-type' '
765-
test_must_fail git cat-file -p $bogus_short_oid &&
766-
test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_oid
767-
'
768-
769729
test_expect_success '<type> <hash> does not work with objects of broken types' '
770730
cat >err.expect <<-\EOF &&
771731
fatal: invalid object type "bogus"
@@ -788,60 +748,8 @@ test_expect_success 'broken types combined with --batch and --batch-check' '
788748
test_cmp err.expect err.actual
789749
'
790750

791-
test_expect_success 'the --batch and --batch-check options do not combine with --allow-unknown-type' '
792-
test_expect_code 128 git cat-file --batch --allow-unknown-type <bogus-oid &&
793-
test_expect_code 128 git cat-file --batch-check --allow-unknown-type <bogus-oid
794-
'
795-
796-
test_expect_success 'the --allow-unknown-type option does not consider replacement refs' '
797-
cat >expect <<-EOF &&
798-
$bogus_short_type
799-
EOF
800-
git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
801-
test_cmp expect actual &&
802-
803-
# Create it manually, as "git replace" will die on bogus
804-
# types.
805-
head=$(git rev-parse --verify HEAD) &&
806-
test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_oid" &&
807-
test-tool ref-store main update-ref msg "refs/replace/$bogus_short_oid" $head $ZERO_OID REF_SKIP_OID_VERIFICATION &&
808-
809-
cat >expect <<-EOF &&
810-
commit
811-
EOF
812-
git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
813-
test_cmp expect actual
814-
'
815-
816-
test_expect_success "Type of broken object is correct" '
817-
echo $bogus_short_type >expect &&
818-
git cat-file -t --allow-unknown-type $bogus_short_oid >actual &&
819-
test_cmp expect actual
820-
'
821-
822-
test_expect_success "Size of broken object is correct" '
823-
echo $bogus_short_size >expect &&
824-
git cat-file -s --allow-unknown-type $bogus_short_oid >actual &&
825-
test_cmp expect actual
826-
'
827-
828-
test_expect_success 'clean up broken object' '
829-
rm .git/objects/$(test_oid_to_path $bogus_short_oid)
830-
'
831-
832-
test_expect_success "Type of broken object is correct when type is large" '
833-
echo $bogus_long_type >expect &&
834-
git cat-file -t --allow-unknown-type $bogus_long_oid >actual &&
835-
test_cmp expect actual
836-
'
837-
838-
test_expect_success "Size of large broken object is correct when type is large" '
839-
echo $bogus_long_size >expect &&
840-
git cat-file -s --allow-unknown-type $bogus_long_oid >actual &&
841-
test_cmp expect actual
842-
'
843-
844-
test_expect_success 'clean up broken object' '
751+
test_expect_success 'clean up broken objects' '
752+
rm .git/objects/$(test_oid_to_path $bogus_short_oid) &&
845753
rm .git/objects/$(test_oid_to_path $bogus_long_oid)
846754
'
847755

@@ -903,25 +811,6 @@ test_expect_success 'cat-file -t and -s on corrupt loose object' '
903811
)
904812
'
905813

906-
test_expect_success 'truncated object with --allow-unknown-type' - <<\EOT
907-
objtype='a really long type name that exceeds the 32-byte limit' &&
908-
blob=$(git hash-object -w --literally -t "$objtype" /dev/null) &&
909-
objpath=.git/objects/$(test_oid_to_path "$blob") &&
910-
911-
# We want to truncate the object far enough in that we don't hit the
912-
# end while inflating the first 32 bytes (since we want to have to dig
913-
# for the trailing NUL of the header). But we don't want to go too far,
914-
# since our header isn't very big. And of course we are counting
915-
# deflated zlib bytes in the on-disk file, so it's a bit of a guess.
916-
# Empirically 50 seems to work.
917-
mv "$objpath" obj.bak &&
918-
test_when_finished 'mv obj.bak "$objpath"' &&
919-
test_copy_bytes 50 <obj.bak >"$objpath" &&
920-
921-
test_must_fail git cat-file --allow-unknown-type -t $blob 2>err &&
922-
test_grep "unable to unpack $blob header" err
923-
EOT
924-
925814
test_expect_success 'object reading handles zlib dictionary' - <<\EOT
926815
echo 'content that will be recompressed' >file &&
927816
blob=$(git hash-object -w file) &&

0 commit comments

Comments
 (0)