Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Documentation/git-update-index.txt | 12 +++++++- builtin/update-index.c | 11 +++++++ cache.h | 2 + read-cache.c | 54 ++++++++++++++++++++++++++++-------- 4 files changed, 66 insertions(+), 13 deletions(-) diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index a3081f4..2574a4e 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -13,7 +13,7 @@ SYNOPSIS [--add] [--remove | --force-remove] [--replace] [--refresh] [-q] [--unmerged] [--ignore-missing] [(--cacheinfo <mode> <object> <file>)...] - [--chmod=(+|-)x] + [--chmod=(+|-)x] [--[no-]crc32] [--assume-unchanged | --no-assume-unchanged] [--skip-worktree | --no-skip-worktree] [--ignore-submodules] @@ -109,6 +109,16 @@ you will need to handle the situation manually. set and unset the "skip-worktree" bit for the paths. See section "Skip-worktree bit" below for more information. +--crc32:: +--no-crc32:: + Normally SHA-1 is used to check for index integrity. When the + index is large, SHA-1 computation cost can be significant. + --crc32 will convert current index to use (cheaper) crc32 + instead. Note that later writes to index by other commands can + convert the index back to SHA-1. Older git versions may not + understand crc32 index, --no-crc32 can be used to convert it + back to SHA-1. + -g:: --again:: Runs 'git update-index' itself on the paths whose index diff --git a/builtin/update-index.c b/builtin/update-index.c index a6a23fa..6913226 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -707,6 +707,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) { int newfd, entries, has_errors = 0, line_termination = '\n'; int read_from_stdin = 0; + int do_crc = -1; int prefix_length = prefix ? strlen(prefix) : 0; char set_executable_bit = 0; struct refresh_params refresh_args = {0, &has_errors}; @@ -791,6 +792,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) "(for porcelains) forget saved unresolved conflicts", PARSE_OPT_NOARG | PARSE_OPT_NONEG, resolve_undo_clear_callback}, + OPT_BOOL(0, "crc32", &do_crc, + "use crc32 as checksum instead of sha1"), OPT_END() }; @@ -852,6 +855,14 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) } argc = parse_options_end(&ctx); + if (do_crc != -1) { + if (do_crc) + the_index.hdr_flags |= CACHE_F_CRC; + else + the_index.hdr_flags &= ~CACHE_F_CRC; + active_cache_changed = 1; + } + if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; diff --git a/cache.h b/cache.h index c2e884a..7352402 100644 --- a/cache.h +++ b/cache.h @@ -105,6 +105,8 @@ struct cache_header { unsigned int hdr_entries; }; +#define CACHE_F_CRC 1 /* use crc32 instead of sha1 for index checksum */ + struct ext_cache_header { struct cache_header h; unsigned int hdr_flags; diff --git a/read-cache.c b/read-cache.c index fd21af6..a34878e 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1185,20 +1185,33 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int reall static int verify_hdr(struct cache_header *hdr, unsigned long size) { + int do_crc; git_SHA_CTX c; unsigned char sha1[20]; if (hdr->hdr_signature != htonl(CACHE_SIGNATURE)) return error("bad signature"); - if (hdr->hdr_version != htonl(2) && - hdr->hdr_version != htonl(3) && - hdr->hdr_version != htonl(4)) + if (hdr->hdr_version == htonl(2) || + hdr->hdr_version == htonl(3)) + do_crc = 0; + else if (hdr->hdr_version == htonl(4)) { + struct ext_cache_header *ehdr = (struct ext_cache_header *)hdr; + do_crc = ntohl(ehdr->hdr_flags) & CACHE_F_CRC; + } + else return error("bad index version"); - git_SHA1_Init(&c); - git_SHA1_Update(&c, hdr, size - 20); - git_SHA1_Final(sha1, &c); - if (hashcmp(sha1, (unsigned char *)hdr + size - 20)) - return error("bad index file sha1 signature"); + if (do_crc) { + uint32_t crc = crc32(0, NULL, 0); + crc = crc32(crc,(void *) hdr, size - sizeof(uint32_t)); + if (crc != *(uint32_t*)((unsigned char *)hdr + size - sizeof(uint32_t))) + return error("bad index file crc32 signature"); + } else { + git_SHA1_Init(&c); + git_SHA1_Update(&c, hdr, size - 20); + git_SHA1_Final(sha1, &c); + if (hashcmp(sha1, (unsigned char *)hdr + size - 20)) + return error("bad index file sha1 signature"); + } return 0; } @@ -1421,11 +1434,24 @@ static int write_index_ext_header(struct sha1file *f, static int ce_flush(struct sha1file *f) { unsigned char sha1[20]; - int fd = sha1close(f, sha1, 0); + int fd; - if (fd < 0) - return -1; - return (write_in_full(fd, sha1, 20) != 20) ? -1 : 0; + if (f->do_crc) { + uint32_t crc; + + assert(f->do_sha1 == 0); + sha1flush(f); + crc = crc32_end(f); + fd = sha1close(f, sha1, 0); + if (fd < 0) + return -1; + return (write_in_full(fd, &crc, sizeof(crc)) != sizeof(crc)) ? -1 : 0; + } else { + fd = sha1close(f, sha1, 0); + if (fd < 0) + return -1; + return (write_in_full(fd, sha1, 20) != 20) ? -1 : 0; + } } static void ce_smudge_racily_clean_entry(struct cache_entry *ce) @@ -1568,6 +1594,10 @@ int write_index(struct index_state *istate, int newfd) hdr.h.hdr_entries = htonl(entries - removed); f = sha1fd(newfd, NULL); + if (istate->hdr_flags & CACHE_F_CRC) { + crc32_begin(f); + f->do_sha1 = 0; + } if (ce_write(f, &hdr, hdr_size) < 0) return -1; -- 1.7.8.36.g69ee2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html