diff options
| -rw-r--r-- | Documentation/git-cat-file.adoc | 6 | ||||
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | builtin/cat-file.c | 31 | ||||
| -rw-r--r-- | builtin/fsck.c | 13 | ||||
| -rw-r--r-- | builtin/hash-object.c | 69 | ||||
| -rw-r--r-- | object-file.c | 142 | ||||
| -rw-r--r-- | object-file.h | 17 | ||||
| -rw-r--r-- | object-store.c | 17 | ||||
| -rw-r--r-- | object-store.h | 3 | ||||
| -rw-r--r-- | packfile.c | 7 | ||||
| -rw-r--r-- | streaming.c | 2 | ||||
| -rw-r--r-- | t/helper/meson.build | 1 | ||||
| -rw-r--r-- | t/helper/test-tool.c | 1 | ||||
| -rw-r--r-- | t/helper/test-tool.h | 1 | ||||
| -rw-r--r-- | t/helper/test-zlib.c | 62 | ||||
| -rw-r--r-- | t/lib-loose.sh | 30 | ||||
| -rwxr-xr-x | t/t1006-cat-file.sh | 216 | ||||
| -rwxr-xr-x | t/t1007-hash-object.sh | 11 | ||||
| -rwxr-xr-x | t/t1450-fsck.sh | 32 | ||||
| -rwxr-xr-x | t/t1512-rev-parse-disambiguation.sh | 5 |
20 files changed, 220 insertions, 447 deletions
diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc index fc4b92f104..cde79ad242 100644 --- a/Documentation/git-cat-file.adoc +++ b/Documentation/git-cat-file.adoc @@ -9,8 +9,7 @@ SYNOPSIS -------- [verse] 'git cat-file' <type> <object> -'git cat-file' (-e | -p) <object> -'git cat-file' (-t | -s) [--allow-unknown-type] <object> +'git cat-file' (-e | -p | -t | -s) <object> 'git cat-file' (--textconv | --filters) [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>] 'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects] @@ -202,9 +201,6 @@ flush:: only once, even if it is stored multiple times in the repository. ---allow-unknown-type:: - Allow `-s` or `-t` to query broken/corrupt objects of unknown type. - --follow-symlinks:: With `--batch` or `--batch-check`, follow symlinks inside the repository when requesting objects with extended SHA-1 @@ -859,6 +859,7 @@ TEST_BUILTINS_OBJS += test-wildmatch.o TEST_BUILTINS_OBJS += test-windows-named-pipe.o TEST_BUILTINS_OBJS += test-write-cache.o TEST_BUILTINS_OBJS += test-xml-encode.o +TEST_BUILTINS_OBJS += test-zlib.o # Do not add more tests here unless they have extra dependencies. Add # them in TEST_BUILTINS_OBJS above. diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 3914a2a3f6..67a5ff2b9e 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -100,8 +100,7 @@ static int stream_blob(const struct object_id *oid) return 0; } -static int cat_one_file(int opt, const char *exp_type, const char *obj_name, - int unknown_type) +static int cat_one_file(int opt, const char *exp_type, const char *obj_name) { int ret; struct object_id oid; @@ -110,7 +109,6 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, unsigned long size; struct object_context obj_context = {0}; struct object_info oi = OBJECT_INFO_INIT; - struct strbuf sb = STRBUF_INIT; unsigned flags = OBJECT_INFO_LOOKUP_REPLACE; unsigned get_oid_flags = GET_OID_RECORD_PATH | @@ -121,9 +119,6 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, if (!path && opt_cw) get_oid_flags |= GET_OID_REQUIRE_PATH; - if (unknown_type) - flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE; - if (get_oid_with_context(the_repository, obj_name, get_oid_flags, &oid, &obj_context)) die("Not a valid object name %s", obj_name); @@ -136,16 +131,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, buf = NULL; switch (opt) { case 't': - oi.type_name = &sb; + oi.typep = &type; if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0) die("git cat-file: could not get object info"); - if (sb.len) { - printf("%s\n", sb.buf); - strbuf_release(&sb); - ret = 0; - goto cleanup; - } - break; + printf("%s\n", type_name(type)); + ret = 0; + goto cleanup; case 's': oi.sizep = &size; @@ -1038,8 +1029,7 @@ int cmd_cat_file(int argc, const char * const builtin_catfile_usage[] = { N_("git cat-file <type> <object>"), - N_("git cat-file (-e | -p) <object>"), - N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"), + N_("git cat-file (-e | -p | -t | -s) <object>"), N_("git cat-file (--textconv | --filters)\n" " [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"), N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n" @@ -1057,8 +1047,8 @@ int cmd_cat_file(int argc, OPT_GROUP(N_("Emit [broken] object attributes")), OPT_CMDMODE('t', NULL, &opt, N_("show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"), 't'), OPT_CMDMODE('s', NULL, &opt, N_("show object size"), 's'), - OPT_BOOL(0, "allow-unknown-type", &unknown_type, - N_("allow -s and -t to work with broken/corrupt objects")), + OPT_HIDDEN_BOOL(0, "allow-unknown-type", &unknown_type, + N_("historical option -- no-op")), OPT_BOOL(0, "use-mailmap", &use_mailmap, N_("use mail map file")), OPT_ALIAS(0, "mailmap", "use-mailmap"), /* Batch mode */ @@ -1209,10 +1199,7 @@ int cmd_cat_file(int argc, obj_name = argv[1]; } - if (unknown_type && opt != 't' && opt != 's') - die("git cat-file --allow-unknown-type: use with -s or -t"); - - ret = cat_one_file(opt, exp_type, obj_name, unknown_type); + ret = cat_one_file(opt, exp_type, obj_name); out: list_objects_filter_release(&batch.objects_filter); diff --git a/builtin/fsck.c b/builtin/fsck.c index 6cac28356c..e7d96a9c8e 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -614,12 +614,11 @@ static void get_default_heads(void) struct for_each_loose_cb { struct progress *progress; - struct strbuf obj_type; }; -static int fsck_loose(const struct object_id *oid, const char *path, void *data) +static int fsck_loose(const struct object_id *oid, const char *path, + void *data UNUSED) { - struct for_each_loose_cb *cb_data = data; struct object *obj; enum object_type type = OBJ_NONE; unsigned long size; @@ -629,8 +628,6 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data) struct object_id real_oid = *null_oid(the_hash_algo); int err = 0; - strbuf_reset(&cb_data->obj_type); - oi.type_name = &cb_data->obj_type; oi.sizep = &size; oi.typep = &type; @@ -642,10 +639,6 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data) err = error(_("%s: object corrupt or missing: %s"), oid_to_hex(oid), path); } - if (type != OBJ_NONE && type < 0) - err = error(_("%s: object is of unknown type '%s': %s"), - oid_to_hex(&real_oid), cb_data->obj_type.buf, - path); if (err < 0) { errors_found |= ERROR_OBJECT; free(contents); @@ -697,7 +690,6 @@ static void fsck_object_dir(const char *path) { struct progress *progress = NULL; struct for_each_loose_cb cb_data = { - .obj_type = STRBUF_INIT, .progress = progress, }; @@ -712,7 +704,6 @@ static void fsck_object_dir(const char *path) &cb_data); display_progress(progress, 256); stop_progress(&progress); - strbuf_release(&cb_data.obj_type); } static int fsck_head_link(const char *head_ref_name, diff --git a/builtin/hash-object.c b/builtin/hash-object.c index cd53fa3bde..6a99ec250d 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -19,49 +19,15 @@ #include "strbuf.h" #include "write-or-die.h" -enum { - HASH_OBJECT_CHECK = (1 << 0), - HASH_OBJECT_WRITE = (1 << 1), -}; - -/* - * This is to create corrupt objects for debugging and as such it - * needs to bypass the data conversion performed by, and the type - * limitation imposed by, index_fd() and its callees. - */ -static int hash_literally(struct object_id *oid, int fd, const char *type, unsigned flags) +static void hash_fd(int fd, const char *type, const char *path, unsigned flags) { - struct strbuf buf = STRBUF_INIT; - int ret; - - if (strbuf_read(&buf, fd, 4096) < 0) - ret = -1; - else - ret = write_object_file_literally(buf.buf, buf.len, type, oid, - (flags & HASH_OBJECT_WRITE) ? WRITE_OBJECT_FILE_PERSIST : 0); - close(fd); - strbuf_release(&buf); - return ret; -} - -static void hash_fd(int fd, const char *type, const char *path, unsigned flags, - int literally) -{ - unsigned int index_flags = 0; struct stat st; struct object_id oid; - if (flags & HASH_OBJECT_WRITE) - index_flags |= INDEX_WRITE_OBJECT; - if (flags & HASH_OBJECT_CHECK) - index_flags |= INDEX_FORMAT_CHECK; - if (fstat(fd, &st) < 0 || - (literally - ? hash_literally(&oid, fd, type, flags) - : index_fd(the_repository->index, &oid, fd, &st, - type_from_string(type), path, index_flags))) - die((flags & HASH_OBJECT_WRITE) + index_fd(the_repository->index, &oid, fd, &st, + type_from_string(type), path, flags)) + die((flags & INDEX_WRITE_OBJECT) ? "Unable to add %s to database" : "Unable to hash %s", path); printf("%s\n", oid_to_hex(&oid)); @@ -69,15 +35,14 @@ static void hash_fd(int fd, const char *type, const char *path, unsigned flags, } static void hash_object(const char *path, const char *type, const char *vpath, - unsigned flags, int literally) + unsigned flags) { int fd; fd = xopen(path, O_RDONLY); - hash_fd(fd, type, vpath, flags, literally); + hash_fd(fd, type, vpath, flags); } -static void hash_stdin_paths(const char *type, int no_filters, unsigned flags, - int literally) +static void hash_stdin_paths(const char *type, int no_filters, unsigned flags) { struct strbuf buf = STRBUF_INIT; struct strbuf unquoted = STRBUF_INIT; @@ -89,8 +54,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags, die("line is badly quoted"); strbuf_swap(&buf, &unquoted); } - hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags, - literally); + hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags); } strbuf_release(&buf); strbuf_release(&unquoted); @@ -111,19 +75,20 @@ int cmd_hash_object(int argc, int hashstdin = 0; int stdin_paths = 0; int no_filters = 0; - int literally = 0; int nongit = 0; - unsigned flags = HASH_OBJECT_CHECK; + unsigned flags = INDEX_FORMAT_CHECK; const char *vpath = NULL; char *vpath_free = NULL; const struct option hash_object_options[] = { OPT_STRING('t', NULL, &type, N_("type"), N_("object type")), OPT_BIT('w', NULL, &flags, N_("write the object into the object database"), - HASH_OBJECT_WRITE), + INDEX_WRITE_OBJECT), OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")), OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")), OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")), - OPT_BOOL( 0, "literally", &literally, N_("just hash any random garbage to create corrupt objects for debugging Git")), + OPT_NEGBIT( 0, "literally", &flags, + N_("just hash any random garbage to create corrupt objects for debugging Git"), + INDEX_FORMAT_CHECK), OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")), OPT_END() }; @@ -133,7 +98,7 @@ int cmd_hash_object(int argc, argc = parse_options(argc, argv, prefix, hash_object_options, hash_object_usage, 0); - if (flags & HASH_OBJECT_WRITE) + if (flags & INDEX_WRITE_OBJECT) prefix = setup_git_directory(); else prefix = setup_git_directory_gently(&nongit); @@ -169,7 +134,7 @@ int cmd_hash_object(int argc, } if (hashstdin) - hash_fd(0, type, vpath, flags, literally); + hash_fd(0, type, vpath, flags); for (i = 0 ; i < argc; i++) { const char *arg = argv[i]; @@ -178,12 +143,12 @@ int cmd_hash_object(int argc, if (prefix) arg = to_free = prefix_filename(prefix, arg); hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg, - flags, literally); + flags); free(to_free); } if (stdin_paths) - hash_stdin_paths(type, no_filters, flags, literally); + hash_stdin_paths(type, no_filters, flags); free(vpath_free); diff --git a/object-file.c b/object-file.c index dc56a4766d..1ac04c2891 100644 --- a/object-file.c +++ b/object-file.c @@ -130,12 +130,6 @@ int has_loose_object(const struct object_id *oid) return check_and_freshen(oid, 0); } -static int format_object_header_literally(char *str, size_t size, - const char *type, size_t objsize) -{ - return xsnprintf(str, size, "%s %"PRIuMAX, type, (uintmax_t)objsize) + 1; -} - int format_object_header(char *str, size_t size, enum object_type type, size_t objsize) { @@ -144,7 +138,7 @@ int format_object_header(char *str, size_t size, enum object_type type, if (!name) BUG("could not get a type name for 'enum object_type' value %d", type); - return format_object_header_literally(str, size, name, objsize); + return xsnprintf(str, size, "%s %"PRIuMAX, name, (uintmax_t)objsize) + 1; } int check_object_signature(struct repository *r, const struct object_id *oid, @@ -299,8 +293,7 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, - unsigned long bufsiz, - struct strbuf *header) + unsigned long bufsiz) { int status; @@ -325,32 +318,9 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream, return ULHR_OK; /* - * We have a header longer than MAX_HEADER_LEN. The "header" - * here is only non-NULL when we run "cat-file - * --allow-unknown-type". + * We have a header longer than MAX_HEADER_LEN. */ - if (!header) - return ULHR_TOO_LONG; - - /* - * buffer[0..bufsiz] was not large enough. Copy the partial - * result out to header, and then append the result of further - * reading the stream. - */ - strbuf_add(header, buffer, stream->next_out - (unsigned char *)buffer); - - do { - stream->next_out = buffer; - stream->avail_out = bufsiz; - - obj_read_unlock(); - status = git_inflate(stream, 0); - obj_read_lock(); - strbuf_add(header, buffer, stream->next_out - (unsigned char *)buffer); - if (memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer)) - return 0; - } while (status == Z_OK); - return ULHR_BAD; + return ULHR_TOO_LONG; } static void *unpack_loose_rest(git_zstream *stream, @@ -427,8 +397,6 @@ int parse_loose_header(const char *hdr, struct object_info *oi) } type = type_from_string_gently(type_buf, type_len, 1); - if (oi->type_name) - strbuf_add(oi->type_name, type_buf, type_len); if (oi->typep) *oi->typep = type; @@ -476,10 +444,8 @@ int loose_object_info(struct repository *r, void *map; git_zstream stream; char hdr[MAX_HEADER_LEN]; - struct strbuf hdrbuf = STRBUF_INIT; unsigned long size_scratch; enum object_type type_scratch; - int allow_unknown = flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE; if (oi->delta_base_oid) oidclr(oi->delta_base_oid, the_repository->hash_algo); @@ -492,7 +458,7 @@ int loose_object_info(struct repository *r, * return value implicitly indicates whether the * object even exists. */ - if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) { + if (!oi->typep && !oi->sizep && !oi->contentp) { struct stat st; if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK)) return quick_has_loose(r, oid) ? 0 : -1; @@ -521,18 +487,15 @@ int loose_object_info(struct repository *r, if (oi->disk_sizep) *oi->disk_sizep = mapsize; - switch (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr), - allow_unknown ? &hdrbuf : NULL)) { + switch (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr))) { case ULHR_OK: - if (parse_loose_header(hdrbuf.len ? hdrbuf.buf : hdr, oi) < 0) + if (parse_loose_header(hdr, oi) < 0) status = error(_("unable to parse %s header"), oid_to_hex(oid)); - else if (!allow_unknown && *oi->typep < 0) + else if (*oi->typep < 0) die(_("invalid object type")); if (!oi->contentp) break; - if (hdrbuf.len) - BUG("unpacking content with unknown types not yet supported"); *oi->contentp = unpack_loose_rest(&stream, hdr, *oi->sizep, oid); if (*oi->contentp) goto cleanup; @@ -558,7 +521,6 @@ cleanup: munmap(map, mapsize); if (oi->sizep == &size_scratch) oi->sizep = NULL; - strbuf_release(&hdrbuf); if (oi->typep == &type_scratch) oi->typep = NULL; oi->whence = OI_LOOSE; @@ -590,17 +552,6 @@ static void write_object_file_prepare(const struct git_hash_algo *algo, hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen); } -static void write_object_file_prepare_literally(const struct git_hash_algo *algo, - const void *buf, unsigned long len, - const char *type, struct object_id *oid, - char *hdr, int *hdrlen) -{ - struct git_hash_ctx c; - - *hdrlen = format_object_header_literally(hdr, *hdrlen, type, len); - hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen); -} - #define CHECK_COLLISION_DEST_VANISHED -2 static int check_collision(const char *source, const char *dest) @@ -730,21 +681,14 @@ out: return 0; } -static void hash_object_file_literally(const struct git_hash_algo *algo, - const void *buf, unsigned long len, - const char *type, struct object_id *oid) -{ - char hdr[MAX_HEADER_LEN]; - int hdrlen = sizeof(hdr); - - write_object_file_prepare_literally(algo, buf, len, type, oid, hdr, &hdrlen); -} - void hash_object_file(const struct git_hash_algo *algo, const void *buf, unsigned long len, enum object_type type, struct object_id *oid) { - hash_object_file_literally(algo, buf, len, type_name(type), oid); + char hdr[MAX_HEADER_LEN]; + int hdrlen = sizeof(hdr); + + write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen); } /* Finalize a file on disk, and close it. */ @@ -1146,53 +1090,6 @@ int write_object_file_flags(const void *buf, unsigned long len, return 0; } -int write_object_file_literally(const void *buf, unsigned long len, - const char *type, struct object_id *oid, - unsigned flags) -{ - char *header; - struct repository *repo = the_repository; - const struct git_hash_algo *algo = repo->hash_algo; - const struct git_hash_algo *compat = repo->compat_hash_algo; - struct object_id compat_oid; - int hdrlen, status = 0; - int compat_type = -1; - - if (compat) { - compat_type = type_from_string_gently(type, -1, 1); - if (compat_type == OBJ_BLOB) - hash_object_file(compat, buf, len, compat_type, - &compat_oid); - else if (compat_type != -1) { - struct strbuf converted = STRBUF_INIT; - convert_object_file(the_repository, - &converted, algo, compat, - buf, len, compat_type, 0); - hash_object_file(compat, converted.buf, converted.len, - compat_type, &compat_oid); - strbuf_release(&converted); - } - } - - /* type string, SP, %lu of the length plus NUL must fit this */ - hdrlen = strlen(type) + MAX_HEADER_LEN; - header = xmalloc(hdrlen); - write_object_file_prepare_literally(the_hash_algo, buf, len, type, - oid, header, &hdrlen); - - if (!(flags & WRITE_OBJECT_FILE_PERSIST)) - goto cleanup; - if (freshen_packed_object(oid) || freshen_loose_object(oid)) - goto cleanup; - status = write_loose_object(oid, header, hdrlen, buf, len, 0, 0); - if (compat_type != -1) - return repo_add_loose_object_map(repo, oid, &compat_oid); - -cleanup: - free(header); - return status; -} - int force_object_loose(const struct object_id *oid, time_t mtime) { struct repository *repo = the_repository; @@ -1682,8 +1579,7 @@ int read_loose_object(const char *path, goto out; } - if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr), - NULL) != ULHR_OK) { + if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) != ULHR_OK) { error(_("unable to unpack header of %s"), path); goto out_inflate; } @@ -1693,6 +1589,12 @@ int read_loose_object(const char *path, goto out_inflate; } + if (*oi->typep < 0) { + error(_("unable to parse type from header '%s' of %s"), + hdr, path); + goto out_inflate; + } + if (*oi->typep == OBJ_BLOB && *size > repo_settings_get_big_file_threshold(the_repository)) { if (check_stream_oid(&stream, hdr, *size, path, expected_oid) < 0) @@ -1703,9 +1605,9 @@ int read_loose_object(const char *path, error(_("unable to unpack contents of %s"), path); goto out_inflate; } - hash_object_file_literally(the_repository->hash_algo, - *contents, *size, - oi->type_name->buf, real_oid); + hash_object_file(the_repository->hash_algo, + *contents, *size, + *oi->typep, real_oid); if (!oideq(expected_oid, real_oid)) goto out_inflate; } diff --git a/object-file.h b/object-file.h index a85b2e5b49..6f41142452 100644 --- a/object-file.h +++ b/object-file.h @@ -133,12 +133,7 @@ int format_object_header(char *str, size_t size, enum object_type type, * - ULHR_BAD on error * - ULHR_TOO_LONG if the header was too long * - * It will only parse up to MAX_HEADER_LEN bytes unless an optional - * "hdrbuf" argument is non-NULL. This is intended for use with - * OBJECT_INFO_ALLOW_UNKNOWN_TYPE to extract the bad type for (error) - * reporting. The full header will be extracted to "hdrbuf" for use - * with parse_loose_header(), ULHR_TOO_LONG will still be returned - * from this function to indicate that the header was too long. + * It will only parse up to MAX_HEADER_LEN bytes. */ enum unpack_loose_header_result { ULHR_OK, @@ -149,8 +144,7 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, - unsigned long bufsiz, - struct strbuf *hdrbuf); + unsigned long bufsiz); /** * parse_loose_header() parses the starting "<type> <len>\0" of an @@ -165,7 +159,7 @@ int parse_loose_header(const char *hdr, struct object_info *oi); enum { /* - * By default, `write_object_file_literally()` does not actually write + * By default, `write_object_file()` does not actually write * anything into the object store, but only computes the object ID. * This flag changes that so that the object will be written as a loose * object and persisted. @@ -180,7 +174,7 @@ enum { int write_object_file_flags(const void *buf, unsigned long len, enum object_type type, struct object_id *oid, - struct object_id *comapt_oid_in, unsigned flags); + struct object_id *compat_oid_in, unsigned flags); static inline int write_object_file(const void *buf, unsigned long len, enum object_type type, struct object_id *oid) { @@ -193,9 +187,6 @@ struct input_stream { int is_finished; }; -int write_object_file_literally(const void *buf, unsigned long len, - const char *type, struct object_id *oid, - unsigned flags); int stream_loose_object(struct input_stream *in_stream, size_t len, struct object_id *oid); diff --git a/object-store.c b/object-store.c index 517f1fd145..58cde0313a 100644 --- a/object-store.c +++ b/object-store.c @@ -646,8 +646,6 @@ static int do_oid_object_info_extended(struct repository *r, *(oi->disk_sizep) = 0; if (oi->delta_base_oid) oidclr(oi->delta_base_oid, the_repository->hash_algo); - if (oi->type_name) - strbuf_addstr(oi->type_name, type_name(co->type)); if (oi->contentp) *oi->contentp = xmemdupz(co->buf, co->size); oi->whence = OI_CACHED; @@ -727,7 +725,7 @@ static int oid_object_info_convert(struct repository *r, { const struct git_hash_algo *input_algo = &hash_algos[input_oid->algo]; int do_die = flags & OBJECT_INFO_DIE_IF_CORRUPT; - struct strbuf type_name = STRBUF_INIT; + enum object_type type; struct object_id oid, delta_base_oid; struct object_info new_oi, *oi; unsigned long size; @@ -753,7 +751,7 @@ static int oid_object_info_convert(struct repository *r, if (input_oi->sizep || input_oi->contentp) { new_oi.contentp = &content; new_oi.sizep = &size; - new_oi.type_name = &type_name; + new_oi.typep = &type; } oi = &new_oi; } @@ -766,12 +764,7 @@ static int oid_object_info_convert(struct repository *r, if (new_oi.contentp) { struct strbuf outbuf = STRBUF_INIT; - enum object_type type; - type = type_from_string_gently(type_name.buf, type_name.len, - !do_die); - if (type == -1) - return -1; if (type != OBJ_BLOB) { ret = convert_object_file(the_repository, &outbuf, the_hash_algo, input_algo, @@ -788,10 +781,8 @@ static int oid_object_info_convert(struct repository *r, *input_oi->contentp = content; else free(content); - if (input_oi->type_name) - *input_oi->type_name = type_name; - else - strbuf_release(&type_name); + if (input_oi->typep) + *input_oi->typep = type; } if (new_oi.delta_base_oid == &delta_base_oid) { if (repo_oid_to_algop(r, &delta_base_oid, input_algo, diff --git a/object-store.h b/object-store.h index 141b801113..c589008535 100644 --- a/object-store.h +++ b/object-store.h @@ -206,7 +206,6 @@ struct object_info { unsigned long *sizep; off_t *disk_sizep; struct object_id *delta_base_oid; - struct strbuf *type_name; void **contentp; /* Response */ @@ -241,8 +240,6 @@ struct object_info { /* Invoke lookup_replace_object() on the given hash */ #define OBJECT_INFO_LOOKUP_REPLACE 1 -/* Allow reading from a loose object file of unknown/bogus type */ -#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2 /* Do not retry packed storage after checking packed and loose storage */ #define OBJECT_INFO_QUICK 8 /* diff --git a/packfile.c b/packfile.c index d91016f1c7..80e35f1032 100644 --- a/packfile.c +++ b/packfile.c @@ -1598,17 +1598,12 @@ int packed_object_info(struct repository *r, struct packed_git *p, *oi->disk_sizep = pack_pos_to_offset(p, pos + 1) - obj_offset; } - if (oi->typep || oi->type_name) { + if (oi->typep) { enum object_type ptot; ptot = packed_to_object_type(r, p, obj_offset, type, &w_curs, curpos); if (oi->typep) *oi->typep = ptot; - if (oi->type_name) { - const char *tn = type_name(ptot); - if (tn) - strbuf_addstr(oi->type_name, tn); - } if (ptot < 0) { type = OBJ_BAD; goto out; diff --git a/streaming.c b/streaming.c index 127d6b5d6a..6d6512e2e0 100644 --- a/streaming.c +++ b/streaming.c @@ -238,7 +238,7 @@ static int open_istream_loose(struct git_istream *st, struct repository *r, return -1; switch (unpack_loose_header(&st->z, st->u.loose.mapped, st->u.loose.mapsize, st->u.loose.hdr, - sizeof(st->u.loose.hdr), NULL)) { + sizeof(st->u.loose.hdr))) { case ULHR_OK: break; case ULHR_BAD: diff --git a/t/helper/meson.build b/t/helper/meson.build index d4e8b26df8..675e64c010 100644 --- a/t/helper/meson.build +++ b/t/helper/meson.build @@ -77,6 +77,7 @@ test_tool_sources = [ 'test-windows-named-pipe.c', 'test-write-cache.c', 'test-xml-encode.c', + 'test-zlib.c', ] test_tool = executable('test-tool', diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 74812ed86d..a7abc618b3 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -91,6 +91,7 @@ static struct test_cmd cmds[] = { { "windows-named-pipe", cmd__windows_named_pipe }, #endif { "write-cache", cmd__write_cache }, + { "zlib", cmd__zlib }, }; static NORETURN void die_usage(void) diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 2571a3ccfe..7f150fa1eb 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -84,6 +84,7 @@ int cmd__wildmatch(int argc, const char **argv); int cmd__windows_named_pipe(int argc, const char **argv); #endif int cmd__write_cache(int argc, const char **argv); +int cmd__zlib(int argc, const char **argv); int cmd_hash_impl(int ac, const char **av, int algo, int unsafe); diff --git a/t/helper/test-zlib.c b/t/helper/test-zlib.c new file mode 100644 index 0000000000..de7e9edee1 --- /dev/null +++ b/t/helper/test-zlib.c @@ -0,0 +1,62 @@ +#include "test-tool.h" +#include "git-zlib.h" +#include "strbuf.h" + +static const char *zlib_usage = "test-tool zlib [inflate|deflate]"; + +static void do_zlib(struct git_zstream *stream, + int (*zlib_func)(git_zstream *, int), + int fd_in, int fd_out) +{ + struct strbuf buf_in = STRBUF_INIT; + int status = Z_OK; + + if (strbuf_read(&buf_in, fd_in, 0) < 0) + die_errno("read error"); + + stream->next_in = (unsigned char *)buf_in.buf; + stream->avail_in = buf_in.len; + + while (status == Z_OK || + (status == Z_BUF_ERROR && !stream->avail_out)) { + unsigned char buf_out[4096]; + + stream->next_out = buf_out; + stream->avail_out = sizeof(buf_out); + + status = zlib_func(stream, Z_FINISH); + if (write_in_full(fd_out, buf_out, + sizeof(buf_out) - stream->avail_out) < 0) + die_errno("write error"); + } + + if (status != Z_STREAM_END) + die("zlib error %d", status); + + strbuf_release(&buf_in); +} + +int cmd__zlib(int argc, const char **argv) +{ + git_zstream stream; + + if (argc != 2) + usage(zlib_usage); + + memset(&stream, 0, sizeof(stream)); + + if (!strcmp(argv[1], "inflate")) { + git_inflate_init(&stream); + do_zlib(&stream, git_inflate, 0, 1); + git_inflate_end(&stream); + } else if (!strcmp(argv[1], "deflate")) { + git_deflate_init(&stream, Z_DEFAULT_COMPRESSION); + do_zlib(&stream, git_deflate, 0, 1); + git_deflate_end(&stream); + } else { + error("unknown mode: %s", argv[1]); + usage(zlib_usage); + } + + return 0; +} diff --git a/t/lib-loose.sh b/t/lib-loose.sh new file mode 100644 index 0000000000..3613631eaf --- /dev/null +++ b/t/lib-loose.sh @@ -0,0 +1,30 @@ +# Support routines for hand-crafting loose objects. + +# Write a loose object into the odb at $1, with object type $2 and contents +# from stdin. Writes the oid to stdout. Example: +# +# oid=$(echo foo | loose_obj .git/objects blob) +# +loose_obj () { + cat >tmp_loose.content && + size=$(wc -c <tmp_loose.content) && + { + # Do not quote $size here; we want the shell + # to strip whitespace that "wc" adds on some platforms. + printf "%s %s\0" "$2" $size && + cat tmp_loose.content + } >tmp_loose.raw && + + oid=$(test-tool $test_hash_algo <tmp_loose.raw) && + suffix=${oid#??} && + prefix=${oid%$suffix} && + dir=$1/$prefix && + file=$dir/$suffix && + + test-tool zlib deflate <tmp_loose.raw >tmp_loose.zlib && + mkdir -p "$dir" && + mv tmp_loose.zlib "$file" && + + rm tmp_loose.raw tmp_loose.content && + echo "$oid" +} diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index ce8b27bf54..317da6869c 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -3,6 +3,7 @@ test_description='git cat-file' . ./test-lib.sh +. "$TEST_DIRECTORY/lib-loose.sh" test_cmdmode_usage () { test_expect_code 129 "$@" 2>err && @@ -136,18 +137,6 @@ $content" test_cmp expect actual ' - test_expect_success "Type of $type is correct using --allow-unknown-type" ' - echo $type >expect && - git cat-file -t --allow-unknown-type $oid >actual && - test_cmp expect actual - ' - - test_expect_success "Size of $type is correct using --allow-unknown-type" ' - echo $size >expect && - git cat-file -s --allow-unknown-type $oid >actual && - test_cmp expect actual - ' - test -z "$content" || test_expect_success "Content of $type is correct" ' echo_without_newline "$content" >expect && @@ -669,103 +658,75 @@ test_expect_success 'setup bogus data' ' bogus_short_type="bogus" && bogus_short_content="bogus" && bogus_short_size=$(strlen "$bogus_short_content") && - bogus_short_oid=$(echo_without_newline "$bogus_short_content" | git hash-object -t $bogus_short_type --literally -w --stdin) && + bogus_short_oid=$(echo_without_newline "$bogus_short_content" | loose_obj .git/objects $bogus_short_type) && bogus_long_type="abcdefghijklmnopqrstuvwxyz1234679" && bogus_long_content="bogus" && bogus_long_size=$(strlen "$bogus_long_content") && - bogus_long_oid=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin) + bogus_long_oid=$(echo_without_newline "$bogus_long_content" | loose_obj .git/objects $bogus_long_type) ' -for arg1 in '' --allow-unknown-type +for arg1 in -s -t -p do - for arg2 in -s -t -p - do - if test "$arg1" = "--allow-unknown-type" && test "$arg2" = "-p" - then - continue - fi + test_expect_success "cat-file $arg1 error on bogus short OID" ' + cat >expect <<-\EOF && + fatal: invalid object type + EOF + test_must_fail git cat-file $arg1 $bogus_short_oid >out 2>actual && + test_must_be_empty out && + test_cmp expect actual + ' - test_expect_success "cat-file $arg1 $arg2 error on bogus short OID" ' - cat >expect <<-\EOF && - fatal: invalid object type + test_expect_success "cat-file $arg1 error on bogus full OID" ' + if test "$arg1" = "-p" + then + cat >expect <<-EOF + error: header for $bogus_long_oid too long, exceeds 32 bytes + fatal: Not a valid object name $bogus_long_oid + EOF + else + cat >expect <<-EOF + error: header for $bogus_long_oid too long, exceeds 32 bytes + fatal: git cat-file: could not get object info EOF + fi && - if test "$arg1" = "--allow-unknown-type" - then - git cat-file $arg1 $arg2 $bogus_short_oid - else - test_must_fail git cat-file $arg1 $arg2 $bogus_short_oid >out 2>actual && - test_must_be_empty out && - test_cmp expect actual - fi - ' + test_must_fail git cat-file $arg1 $bogus_long_oid >out 2>actual && + test_must_be_empty out && + test_cmp expect actual + ' - test_expect_success "cat-file $arg1 $arg2 error on bogus full OID" ' - if test "$arg2" = "-p" - then - cat >expect <<-EOF - error: header for $bogus_long_oid too long, exceeds 32 bytes - fatal: Not a valid object name $bogus_long_oid - EOF - else - cat >expect <<-EOF - error: header for $bogus_long_oid too long, exceeds 32 bytes - fatal: git cat-file: could not get object info - EOF - fi && - - if test "$arg1" = "--allow-unknown-type" - then - git cat-file $arg1 $arg2 $bogus_short_oid - else - test_must_fail git cat-file $arg1 $arg2 $bogus_long_oid >out 2>actual && - test_must_be_empty out && - test_cmp expect actual - fi - ' + test_expect_success "cat-file $arg1 error on missing short OID" ' + cat >expect.err <<-EOF && + fatal: Not a valid object name $(test_oid deadbeef_short) + EOF + test_must_fail git cat-file $arg1 $(test_oid deadbeef_short) >out 2>err.actual && + test_must_be_empty out && + test_cmp expect.err err.actual + ' - test_expect_success "cat-file $arg1 $arg2 error on missing short OID" ' - cat >expect.err <<-EOF && - fatal: Not a valid object name $(test_oid deadbeef_short) + test_expect_success "cat-file $arg1 error on missing full OID" ' + if test "$arg1" = "-p" + then + cat >expect.err <<-EOF + fatal: Not a valid object name $(test_oid deadbeef) EOF - test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef_short) >out 2>err.actual && - test_must_be_empty out && - test_cmp expect.err err.actual - ' - - test_expect_success "cat-file $arg1 $arg2 error on missing full OID" ' - if test "$arg2" = "-p" - then - cat >expect.err <<-EOF - fatal: Not a valid object name $(test_oid deadbeef) - EOF - else - cat >expect.err <<-\EOF - fatal: git cat-file: could not get object info - EOF - fi && - test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef) >out 2>err.actual && - test_must_be_empty out && - test_cmp expect.err err.actual - ' - done + else + cat >expect.err <<-\EOF + fatal: git cat-file: could not get object info + EOF + fi && + test_must_fail git cat-file $arg1 $(test_oid deadbeef) >out 2>err.actual && + test_must_be_empty out && + test_cmp expect.err err.actual + ' done -test_expect_success '-e is OK with a broken object without --allow-unknown-type' ' +test_expect_success '-e is OK with a broken object' ' git cat-file -e $bogus_short_oid ' -test_expect_success '-e can not be combined with --allow-unknown-type' ' - test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_oid -' - -test_expect_success '-p cannot print a broken object even with --allow-unknown-type' ' - test_must_fail git cat-file -p $bogus_short_oid && - test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_oid -' - test_expect_success '<type> <hash> does not work with objects of broken types' ' cat >err.expect <<-\EOF && fatal: invalid object type "bogus" @@ -788,60 +749,8 @@ test_expect_success 'broken types combined with --batch and --batch-check' ' test_cmp err.expect err.actual ' -test_expect_success 'the --batch and --batch-check options do not combine with --allow-unknown-type' ' - test_expect_code 128 git cat-file --batch --allow-unknown-type <bogus-oid && - test_expect_code 128 git cat-file --batch-check --allow-unknown-type <bogus-oid -' - -test_expect_success 'the --allow-unknown-type option does not consider replacement refs' ' - cat >expect <<-EOF && - $bogus_short_type - EOF - git cat-file -t --allow-unknown-type $bogus_short_oid >actual && - test_cmp expect actual && - - # Create it manually, as "git replace" will die on bogus - # types. - head=$(git rev-parse --verify HEAD) && - test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_oid" && - test-tool ref-store main update-ref msg "refs/replace/$bogus_short_oid" $head $ZERO_OID REF_SKIP_OID_VERIFICATION && - - cat >expect <<-EOF && - commit - EOF - git cat-file -t --allow-unknown-type $bogus_short_oid >actual && - test_cmp expect actual -' - -test_expect_success "Type of broken object is correct" ' - echo $bogus_short_type >expect && - git cat-file -t --allow-unknown-type $bogus_short_oid >actual && - test_cmp expect actual -' - -test_expect_success "Size of broken object is correct" ' - echo $bogus_short_size >expect && - git cat-file -s --allow-unknown-type $bogus_short_oid >actual && - test_cmp expect actual -' - -test_expect_success 'clean up broken object' ' - rm .git/objects/$(test_oid_to_path $bogus_short_oid) -' - -test_expect_success "Type of broken object is correct when type is large" ' - echo $bogus_long_type >expect && - git cat-file -t --allow-unknown-type $bogus_long_oid >actual && - test_cmp expect actual -' - -test_expect_success "Size of large broken object is correct when type is large" ' - echo $bogus_long_size >expect && - git cat-file -s --allow-unknown-type $bogus_long_oid >actual && - test_cmp expect actual -' - -test_expect_success 'clean up broken object' ' +test_expect_success 'clean up broken objects' ' + rm .git/objects/$(test_oid_to_path $bogus_short_oid) && rm .git/objects/$(test_oid_to_path $bogus_long_oid) ' @@ -903,25 +812,6 @@ test_expect_success 'cat-file -t and -s on corrupt loose object' ' ) ' -test_expect_success 'truncated object with --allow-unknown-type' - <<\EOT - objtype='a really long type name that exceeds the 32-byte limit' && - blob=$(git hash-object -w --literally -t "$objtype" /dev/null) && - objpath=.git/objects/$(test_oid_to_path "$blob") && - - # We want to truncate the object far enough in that we don't hit the - # end while inflating the first 32 bytes (since we want to have to dig - # for the trailing NUL of the header). But we don't want to go too far, - # since our header isn't very big. And of course we are counting - # deflated zlib bytes in the on-disk file, so it's a bit of a guess. - # Empirically 50 seems to work. - mv "$objpath" obj.bak && - test_when_finished 'mv obj.bak "$objpath"' && - test_copy_bytes 50 <obj.bak >"$objpath" && - - test_must_fail git cat-file --allow-unknown-type -t $blob 2>err && - test_grep "unable to unpack $blob header" err -EOT - test_expect_success 'object reading handles zlib dictionary' - <<\EOT echo 'content that will be recompressed' >file && blob=$(git hash-object -w file) && diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index b3cf53ff8c..dbbe9fb0d4 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -248,15 +248,8 @@ test_expect_success 'hash-object complains about truncated type name' ' test_must_fail git hash-object -t bl --stdin </dev/null ' -test_expect_success '--literally' ' - t=1234567890 && - echo example | git hash-object -t $t --literally --stdin -' - -test_expect_success '--literally with extra-long type' ' - t=12345678901234567890123456789012345678901234567890 && - t="$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t" && - echo example | git hash-object -t $t --literally --stdin +test_expect_success '--literally complains about non-standard types' ' + test_must_fail git hash-object -t bogus --literally --stdin ' test_expect_success '--stdin outside of repository (uses SHA-1)' ' diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 0105045376..5ae86c42be 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -7,6 +7,7 @@ test_description='git fsck random collection of tests ' . ./test-lib.sh +. "$TEST_DIRECTORY/lib-loose.sh" test_expect_success setup ' git config gc.auto 0 && @@ -71,30 +72,6 @@ test_expect_success 'object with hash mismatch' ' ) ' -test_expect_success 'object with hash and type mismatch' ' - git init --bare hash-type-mismatch && - ( - cd hash-type-mismatch && - - oid=$(echo blob | git hash-object -w --stdin -t garbage --literally) && - oldoid=$oid && - old=$(test_oid_to_path "$oid") && - new=$(dirname $old)/$(test_oid ff_2) && - oid="$(dirname $new)$(basename $new)" && - - mv objects/$old objects/$new && - git update-index --add --cacheinfo 100644 $oid foo && - tree=$(git write-tree) && - cmt=$(echo bogus | git commit-tree $tree) && - git update-ref refs/heads/bogus $cmt && - - - test_must_fail git fsck 2>out && - grep "^error: $oldoid: hash-path mismatch, found at: .*$new" out && - grep "^error: $oldoid: object is of unknown type '"'"'garbage'"'"'" out - ) -' - test_expect_success 'zlib corrupt loose object output ' ' git init --bare corrupt-loose-output && ( @@ -997,12 +974,13 @@ test_expect_success 'fsck error and recovery on invalid object type' ' ( cd garbage-type && - garbage_blob=$(git hash-object --stdin -w -t garbage --literally </dev/null) && + garbage_blob=$(loose_obj objects garbage </dev/null) && test_must_fail git fsck 2>err && grep -e "^error" -e "^fatal" err >errors && - test_line_count = 1 errors && - grep "$garbage_blob: object is of unknown type '"'"'garbage'"'"':" err + test_line_count = 2 errors && + test_grep "unable to parse type from header .garbage" err && + test_grep "$garbage_blob: object corrupt or missing:" err ) ' diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh index 70f1e0a998..1a380a4184 100755 --- a/t/t1512-rev-parse-disambiguation.sh +++ b/t/t1512-rev-parse-disambiguation.sh @@ -24,6 +24,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +. "$TEST_DIRECTORY/lib-loose.sh" test_cmp_failed_rev_parse () { dir=$1 @@ -67,8 +68,8 @@ test_expect_success 'ambiguous loose bad object parsed as OBJ_BAD' ' cd blob.bad && # Both have the prefix "bad0" - echo xyzfaowcoh | git hash-object -t bad -w --stdin --literally && - echo xyzhjpyvwl | git hash-object -t bad -w --stdin --literally + echo xyzfaowcoh | loose_obj objects bad && + echo xyzhjpyvwl | loose_obj objects bad ) && test_cmp_failed_rev_parse blob.bad bad0 <<-\EOF |
