From: Junio C Hamano Date: Thu, 7 Feb 2019 06:05:21 +0000 (-0800) Subject: Merge branch 'dt/cat-file-batch-ambiguous' X-Git-Tag: v2.21.0-rc0~27 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/cfd9167c15e7b09f3964204964a4c158108c6403?ds=inline;hp=-c Merge branch 'dt/cat-file-batch-ambiguous' "git cat-file --batch" reported a dangling symbolic link by mistake, when it wanted to report that a given name is ambiguous. * dt/cat-file-batch-ambiguous: t1512: test ambiguous cat-file --batch and --batch-output Do not print 'dangling' for cat-file in case of ambiguity --- cfd9167c15e7b09f3964204964a4c158108c6403 diff --combined Documentation/git-cat-file.txt index 9a2e9cdafb,e27a940985..8eca671b82 --- a/Documentation/git-cat-file.txt +++ b/Documentation/git-cat-file.txt @@@ -23,8 -23,8 +23,8 @@@ In the second form, a list of objects ( stdin, and the SHA-1, type, and size of each object is printed on stdout. The output format can be overridden using the optional `` argument. If either `--textconv` or `--filters` was specified, the input is expected to -list the object names followed by the path name, separated by a single white -space, so that the appropriate drivers can be determined. +list the object names followed by the path name, separated by a single +whitespace, so that the appropriate drivers can be determined. OPTIONS ------- @@@ -79,7 -79,7 +79,7 @@@ Print object information and contents for each object provided on stdin. May not be combined with any other options or arguments except `--textconv` or `--filters`, in which case the input lines - also need to specify the path, separated by white space. See the + also need to specify the path, separated by whitespace. See the section `BATCH OUTPUT` below for details. --batch-check:: @@@ -87,7 -87,7 +87,7 @@@ Print object information for each object provided on stdin. May not be combined with any other options or arguments except `--textconv` or `--filters`, in which case the input lines also - need to specify the path, separated by white space. See the + need to specify the path, separated by whitespace. See the section `BATCH OUTPUT` below for details. --batch-all-objects:: @@@ -252,6 -252,12 +252,12 @@@ the repository, then `cat-file` will ig SP missing LF ------------ + If a name is specified that might refer to more than one object (an ambiguous short sha), then `cat-file` will ignore any custom format and print: + + ------------ + SP ambiguous LF + ------------ + If --follow-symlinks is used, and a symlink in the repository points outside the repository, then `cat-file` will ignore any custom format and print: diff --combined cache.h index 038e3764a9,70652e99dc..156a839484 --- a/cache.h +++ b/cache.h @@@ -45,20 -45,10 +45,20 @@@ unsigned long git_deflate_bound(git_zst /* The length in bytes and in hex digits of an object name (SHA-1 value). */ #define GIT_SHA1_RAWSZ 20 #define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ) +/* The block size of SHA-1. */ +#define GIT_SHA1_BLKSZ 64 + +/* The length in bytes and in hex digits of an object name (SHA-256 value). */ +#define GIT_SHA256_RAWSZ 32 +#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ) +/* The block size of SHA-256. */ +#define GIT_SHA256_BLKSZ 64 /* The length in byte and in hex digits of the largest possible hash value. */ -#define GIT_MAX_RAWSZ GIT_SHA1_RAWSZ -#define GIT_MAX_HEXSZ GIT_SHA1_HEXSZ +#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ +#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ +/* The largest possible block size for any supported hash. */ +#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ struct object_id { unsigned char hash[GIT_MAX_RAWSZ]; @@@ -755,7 -745,6 +755,7 @@@ extern int index_name_pos(const struct #define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */ #define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */ #define ADD_CACHE_KEEP_CACHE_TREE 32 /* Do not invalidate cache-tree */ +#define ADD_CACHE_RENORMALIZE 64 /* Pass along HASH_RENORMALIZE */ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option); extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name); @@@ -1039,12 -1028,16 +1039,12 @@@ extern const struct object_id null_oid static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) { /* - * This is a temporary optimization hack. By asserting the size here, - * we let the compiler know that it's always going to be 20, which lets - * it turn this fixed-size memcmp into a few inline instructions. - * - * This will need to be extended or ripped out when we learn about - * hashes of different sizes. + * Teach the compiler that there are only two possibilities of hash size + * here, so that it can optimize for this case as much as possible. */ - if (the_hash_algo->rawsz != 20) - BUG("hash size not yet supported by hashcmp"); - return memcmp(sha1, sha2, the_hash_algo->rawsz); + if (the_hash_algo->rawsz == GIT_MAX_RAWSZ) + return memcmp(sha1, sha2, GIT_MAX_RAWSZ); + return memcmp(sha1, sha2, GIT_SHA1_RAWSZ); } static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2) @@@ -1054,13 -1047,7 +1054,13 @@@ static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2) { - return !hashcmp(sha1, sha2); + /* + * We write this here instead of deferring to hashcmp so that the + * compiler can properly inline it and avoid calling memcmp. + */ + if (the_hash_algo->rawsz == GIT_MAX_RAWSZ) + return !memcmp(sha1, sha2, GIT_MAX_RAWSZ); + return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ); } static inline int oideq(const struct object_id *oid1, const struct object_id *oid2) @@@ -1085,7 -1072,7 +1085,7 @@@ static inline void hashcpy(unsigned cha static inline void oidcpy(struct object_id *dst, const struct object_id *src) { - hashcpy(dst->hash, src->hash); + memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ); } static inline struct object_id *oiddup(const struct object_id *src) @@@ -1345,6 -1332,24 +1345,24 @@@ struct object_context GET_OID_TREE | GET_OID_TREEISH | \ GET_OID_BLOB) + enum get_oid_result { + FOUND = 0, + MISSING_OBJECT = -1, /* The requested object is missing */ + SHORT_NAME_AMBIGUOUS = -2, + /* The following only apply when symlinks are followed */ + DANGLING_SYMLINK = -4, /* + * The initial symlink is there, but + * (transitively) points to a missing + * in-tree file + */ + SYMLINK_LOOP = -5, + NOT_DIR = -6, /* + * Somewhere along the symlink chain, a path is + * requested which contains a file as a + * non-final element. + */ + }; + extern int get_oid(const char *str, struct object_id *oid); extern int get_oid_commit(const char *str, struct object_id *oid); extern int get_oid_committish(const char *str, struct object_id *oid); @@@ -1352,7 -1357,7 +1370,7 @@@ extern int get_oid_tree(const char *str extern int get_oid_treeish(const char *str, struct object_id *oid); extern int get_oid_blob(const char *str, struct object_id *oid); extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix); - extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc); + extern enum get_oid_result get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc); typedef int each_abbrev_fn(const struct object_id *oid, void *); @@@ -1378,9 -1383,9 +1396,9 @@@ extern int get_oid_hex(const char *hex extern int hex_to_bytes(unsigned char *binary, const char *hex, size_t len); /* - * Convert a binary sha1 to its hex equivalent. The `_r` variant is reentrant, + * Convert a binary hash to its hex equivalent. The `_r` variant is reentrant, * and writes the NUL-terminated output to the buffer `out`, which must be at - * least `GIT_SHA1_HEXSZ + 1` bytes, and returns a pointer to out for + * least `GIT_MAX_HEXSZ + 1` bytes, and returns a pointer to out for * convenience. * * The non-`_r` variant returns a static buffer, but uses a ring of 4 @@@ -1388,13 -1393,10 +1406,13 @@@ * * printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two)); */ -extern char *sha1_to_hex_r(char *out, const unsigned char *sha1); -extern char *oid_to_hex_r(char *out, const struct object_id *oid); -extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */ -extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */ +char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *); +char *sha1_to_hex_r(char *out, const unsigned char *sha1); +char *oid_to_hex_r(char *out, const struct object_id *oid); +char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *); /* static buffer result! */ +char *sha1_to_hex(const unsigned char *sha1); /* same static buffer */ +char *hash_to_hex(const unsigned char *hash); /* same static buffer */ +char *oid_to_hex(const struct object_id *oid); /* same static buffer */ /* * Parse a 40-character hexadecimal object ID starting from hex, updating the diff --combined tree-walk.c index 277e3b3243,fb7959b21d..1e4bbc8a0e --- a/tree-walk.c +++ b/tree-walk.c @@@ -48,8 -48,7 +48,8 @@@ static int decode_tree_entry(struct tre /* Initialize the descriptor entry */ desc->entry.path = path; desc->entry.mode = canon_mode(mode); - desc->entry.oid = (const struct object_id *)(path + len); + desc->entry.pathlen = len - 1; + hashcpy(desc->entry.oid.hash, (const unsigned char *)path + len); return 0; } @@@ -108,7 -107,7 +108,7 @@@ static void entry_extract(struct tree_d static int update_tree_entry_internal(struct tree_desc *desc, struct strbuf *err) { const void *buf = desc->buffer; - const unsigned char *end = desc->entry.oid->hash + the_hash_algo->rawsz; + const unsigned char *end = (const unsigned char *)desc->entry.path + desc->entry.pathlen + 1 + the_hash_algo->rawsz; unsigned long size = desc->size; unsigned long len = end - (const unsigned char *)buf; @@@ -176,11 -175,9 +176,11 @@@ void setup_traverse_info(struct travers pathlen--; info->pathlen = pathlen ? pathlen + 1 : 0; info->name.path = base; - info->name.oid = (void *)(base + pathlen + 1); - if (pathlen) + info->name.pathlen = pathlen; + if (pathlen) { + hashcpy(info->name.oid.hash, (const unsigned char *)base + pathlen + 1); info->prev = &dummy; + } } char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n) @@@ -505,10 -502,10 +505,10 @@@ static int find_tree_entry(struct tree_ int namelen = strlen(name); while (t->size) { const char *entry; - const struct object_id *oid; + struct object_id oid; int entrylen, cmp; - oid = tree_entry_extract(t, &entry, mode); + oidcpy(&oid, tree_entry_extract(t, &entry, mode)); entrylen = tree_entry_len(&t->entry); update_tree_entry(t); if (entrylen > namelen) @@@ -519,7 -516,7 +519,7 @@@ if (cmp < 0) break; if (entrylen == namelen) { - oidcpy(result, oid); + oidcpy(result, &oid); return 0; } if (name[entrylen] != '/') @@@ -527,10 -524,10 +527,10 @@@ if (!S_ISDIR(*mode)) break; if (++entrylen == namelen) { - oidcpy(result, oid); + oidcpy(result, &oid); return 0; } - return get_tree_entry(oid, name + entrylen, result, mode); + return get_tree_entry(&oid, name + entrylen, result, mode); } return -1; } @@@ -582,10 -579,10 +582,10 @@@ int get_tree_entry(const struct object_ * with the sha1 of the found object, and *mode will hold the mode of * the object. * - * See the code for enum follow_symlink_result for a description of + * See the code for enum get_oid_result for a description of * the return values. */ - enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode) + enum get_oid_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode) { int retval = MISSING_OBJECT; struct dir_state *parents = NULL; diff --combined tree-walk.h index a4ad28ea5e,de6b95179d..8225171866 --- a/tree-walk.h +++ b/tree-walk.h @@@ -1,12 -1,12 +1,12 @@@ #ifndef TREE_WALK_H #define TREE_WALK_H -struct index_state; -struct strbuf; +#include "cache.h" struct name_entry { - const struct object_id *oid; + struct object_id oid; const char *path; + int pathlen; unsigned int mode; }; @@@ -20,12 -20,12 +20,12 @@@ static inline const struct object_id *t { *pathp = desc->entry.path; *modep = desc->entry.mode; - return desc->entry.oid; + return &desc->entry.oid; } static inline int tree_entry_len(const struct name_entry *ne) { - return (const char *)ne->oid - ne->path - 1; + return ne->pathlen; } /* @@@ -51,23 -51,7 +51,7 @@@ struct traverse_info typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *); int traverse_trees(struct index_state *istate, int n, struct tree_desc *t, struct traverse_info *info); - enum follow_symlinks_result { - FOUND = 0, /* This includes out-of-tree links */ - MISSING_OBJECT = -1, /* The initial symlink is missing */ - DANGLING_SYMLINK = -2, /* - * The initial symlink is there, but - * (transitively) points to a missing - * in-tree file - */ - SYMLINK_LOOP = -3, - NOT_DIR = -4, /* - * Somewhere along the symlink chain, a path is - * requested which contains a file as a - * non-final element. - */ - }; - - enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode); + enum get_oid_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode); struct traverse_info { const char *traverse_path;