From: Junio C Hamano Date: Wed, 13 Dec 2017 21:28:54 +0000 (-0800) Subject: Merge branch 'bc/hash-algo' X-Git-Tag: v2.16.0-rc0~65 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/721cc4314cb593e799213ad5f926a1e9fc5779b0?ds=inline;hp=-c Merge branch 'bc/hash-algo' An infrastructure to define what hash function is used in Git is introduced, and an effort to plumb that throughout various codepaths has been started. * bc/hash-algo: repository: fix a sparse 'using integer as NULL pointer' warning Switch empty tree and blob lookups to use hash abstraction Integrate hash algorithm support with repo setup Add structure representing hash algorithm setup: expose enumerated repo info --- 721cc4314cb593e799213ad5f926a1e9fc5779b0 diff --combined builtin/am.c index 02853b3e05,99dbde3e85..3d98e52085 --- a/builtin/am.c +++ b/builtin/am.c @@@ -1433,7 -1433,7 +1433,7 @@@ static void write_index_patch(const str if (!get_oid_tree("HEAD", &head)) tree = lookup_tree(&head); else - tree = lookup_tree(&empty_tree_oid); + tree = lookup_tree(the_hash_algo->empty_tree); fp = xfopen(am_path(state, "patch"), "w"); init_revisions(&rev_info, NULL); @@@ -2148,7 -2148,7 +2148,7 @@@ static void am_abort(struct am_state *s has_curr_head ? &curr_head : NULL, 0, UPDATE_REFS_DIE_ON_ERR); else if (curr_branch) - delete_ref(NULL, curr_branch, NULL, REF_NODEREF); + delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF); free(curr_branch); am_destroy(state); diff --combined builtin/checkout.c index 3faae382de,2b64805f35..e1e157d205 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@@ -514,7 -514,7 +514,7 @@@ static int merge_working_tree(const str } tree = parse_tree_indirect(old->commit ? &old->commit->object.oid : - &empty_tree_oid); + the_hash_algo->empty_tree); init_tree_desc(&trees[0], tree->buffer, tree->size); tree = parse_tree_indirect(&new->commit->object.oid); init_tree_desc(&trees[1], tree->buffer, tree->size); @@@ -663,7 -663,7 +663,7 @@@ static void update_refs_for_switch(cons /* Nothing to do. */ } else if (opts->force_detach || !new->path) { /* No longer on any branch. */ update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL, - REF_NODEREF, UPDATE_REFS_DIE_ON_ERR); + REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR); if (!opts->quiet) { if (old->path && advice_detached_head && !opts->force_detach) @@@ -1287,11 -1287,11 +1287,11 @@@ int cmd_checkout(int argc, const char * if (opts.new_branch) { struct strbuf buf = STRBUF_INIT; - opts.branch_exists = - validate_new_branchname(opts.new_branch, &buf, - !!opts.new_branch_force, - !!opts.new_branch_force); - + if (opts.new_branch_force) + opts.branch_exists = validate_branchname(opts.new_branch, &buf); + else + opts.branch_exists = + validate_new_branchname(opts.new_branch, &buf, 0); strbuf_release(&buf); } diff --combined builtin/pull.c index 166b777ed6,3d26f8ff32..511dbbe0f6 --- a/builtin/pull.c +++ b/builtin/pull.c @@@ -113,8 -113,6 +113,8 @@@ static char *opt_depth static char *opt_unshallow; static char *opt_update_shallow; static char *opt_refmap; +static char *opt_ipv4; +static char *opt_ipv6; static struct option pull_options[] = { /* Shared options */ @@@ -220,12 -218,6 +220,12 @@@ OPT_PASSTHRU(0, "refmap", &opt_refmap, N_("refmap"), N_("specify fetch refmap"), PARSE_OPT_NONEG), + OPT_PASSTHRU('4', "ipv4", &opt_ipv4, NULL, + N_("use IPv4 addresses only"), + PARSE_OPT_NOARG), + OPT_PASSTHRU('6', "ipv6", &opt_ipv6, NULL, + N_("use IPv6 addresses only"), + PARSE_OPT_NOARG), OPT_END() }; @@@ -530,10 -522,6 +530,10 @@@ static int run_fetch(const char *repo, argv_array_push(&args, opt_update_shallow); if (opt_refmap) argv_array_push(&args, opt_refmap); + if (opt_ipv4) + argv_array_push(&args, opt_ipv4); + if (opt_ipv6) + argv_array_push(&args, opt_ipv6); if (repo) { argv_array_push(&args, repo); @@@ -557,7 -545,7 +557,7 @@@ static int pull_into_void(const struct * index/worktree changes that the user already made on the unborn * branch. */ - if (checkout_fast_forward(&empty_tree_oid, merge_head, 0)) + if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0)) return 1; if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR)) @@@ -763,15 -751,12 +763,15 @@@ static int get_octopus_merge_base(struc if (!is_null_oid(fork_point)) commit_list_insert(lookup_commit_reference(fork_point), &revs); - result = reduce_heads(get_octopus_merge_bases(revs)); + result = get_octopus_merge_bases(revs); free_commit_list(revs); + reduce_heads_replace(&result); + if (!result) return 1; oidcpy(merge_base, &result->item->object.oid); + free_commit_list(result); return 0; } diff --combined cache.h index cb5db7bf83,d68895b45f..d3e240228c --- a/cache.h +++ b/cache.h @@@ -14,6 -14,7 +14,7 @@@ #include "hash.h" #include "path.h" #include "sha1-array.h" + #include "repository.h" #ifndef platform_SHA_CTX /* @@@ -77,6 -78,8 +78,8 @@@ struct object_id unsigned char hash[GIT_MAX_RAWSZ]; }; + #define the_hash_algo the_repository->hash_algo + #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT) #define DTYPE(de) ((de)->d_type) #else @@@ -204,7 -207,6 +207,7 @@@ struct cache_entry #define CE_ADDED (1 << 19) #define CE_HASHED (1 << 20) +#define CE_FSMONITOR_VALID (1 << 21) #define CE_WT_REMOVE (1 << 22) /* remove in work directory */ #define CE_CONFLICTED (1 << 23) @@@ -328,7 -330,6 +331,7 @@@ static inline unsigned int canon_mode(u #define CACHE_TREE_CHANGED (1 << 5) #define SPLIT_INDEX_ORDERED (1 << 6) #define UNTRACKED_CHANGED (1 << 7) +#define FSMONITOR_CHANGED (1 << 8) struct split_index; struct untracked_cache; @@@ -347,8 -348,6 +350,8 @@@ struct index_state struct hashmap dir_hash; unsigned char sha1[20]; struct untracked_cache *untracked; + uint64_t fsmonitor_last_update; + struct ewah_bitmap *fsmonitor_dirty; }; extern struct index_state the_index; @@@ -450,16 -449,6 +453,16 @@@ static inline enum object_type object_t #define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH" #define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS" +/* + * Environment variable used in handshaking the wire protocol. + * Contains a colon ':' separated list of keys with optional values + * 'key[=value]'. Presence of unknown keys and values must be + * ignored. + */ +#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL" +/* HTTP header used to handshake the wire protocol */ +#define GIT_PROTOCOL_HEADER "Git-Protocol" + /* * This environment variable is expected to contain a boolean indicating * whether we should or should not treat: @@@ -714,14 -703,11 +717,14 @@@ extern void *read_blob_data_from_index( #define CE_MATCH_IGNORE_MISSING 0x08 /* enable stat refresh */ #define CE_MATCH_REFRESH 0x10 -extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int); -extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int); +/* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */ +#define CE_MATCH_IGNORE_FSMONITOR 0X20 +extern int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); +extern int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); #define HASH_WRITE_OBJECT 1 #define HASH_FORMAT_CHECK 2 +#define HASH_RENORMALIZE 4 extern int index_fd(struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); extern int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags); @@@ -762,7 -748,6 +765,7 @@@ extern int hold_locked_index(struct loc extern void set_alternate_index_output(const char *); extern int verify_index_checksum; +extern int verify_ce_order; /* Environment bits from configuration mechanism */ extern int trust_executable_bit; @@@ -816,7 -801,6 +819,7 @@@ extern int core_apply_sparse_checkout extern int precomposed_unicode; extern int protect_hfs; extern int protect_ntfs; +extern const char *core_fsmonitor; /* * Include broken refs in all ref iterations, which will @@@ -907,6 -891,7 +910,7 @@@ struct repository_format int version; int precious_objects; int is_bare; + int hash_algo; char *work_tree; struct string_list unknown_extensions; }; @@@ -1039,22 -1024,22 +1043,22 @@@ extern const struct object_id empty_blo static inline int is_empty_blob_sha1(const unsigned char *sha1) { - return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN); + return !hashcmp(sha1, the_hash_algo->empty_blob->hash); } static inline int is_empty_blob_oid(const struct object_id *oid) { - return !hashcmp(oid->hash, EMPTY_BLOB_SHA1_BIN); + return !oidcmp(oid, the_hash_algo->empty_blob); } static inline int is_empty_tree_sha1(const unsigned char *sha1) { - return !hashcmp(sha1, EMPTY_TREE_SHA1_BIN); + return !hashcmp(sha1, the_hash_algo->empty_tree->hash); } static inline int is_empty_tree_oid(const struct object_id *oid) { - return !hashcmp(oid->hash, EMPTY_TREE_SHA1_BIN); + return !oidcmp(oid, the_hash_algo->empty_tree); } /* set default permissions by passing mode arguments to open(2) */ diff --combined diff-lib.c index 5173023cd3,893fee432c..8104603a3b --- a/diff-lib.c +++ b/diff-lib.c @@@ -12,7 -12,6 +12,7 @@@ #include "refs.h" #include "submodule.h" #include "dir.h" +#include "fsmonitor.h" /* * diff-files @@@ -218,7 -217,7 +218,7 @@@ int run_diff_files(struct rev_info *rev } else if (revs->diffopt.ita_invisible_in_index && ce_intent_to_add(ce)) { diff_addremove(&revs->diffopt, '+', ce->ce_mode, - &empty_tree_oid, 0, + the_hash_algo->empty_tree, 0, ce->name, 0); continue; } @@@ -230,7 -229,6 +230,7 @@@ if (!changed && !dirty_submodule) { ce_mark_uptodate(ce); + mark_fsmonitor_valid(ce); if (!revs->diffopt.flags.find_copies_harder) continue; } diff --combined merge-recursive.c index d00b274381,f89cc751e1..a4c280dfc7 --- a/merge-recursive.c +++ b/merge-recursive.c @@@ -1901,9 -1901,8 +1901,9 @@@ static int process_entry(struct merge_o oid = b_oid; conf = _("directory/file"); } - if (dir_in_way(path, !o->call_depth, - S_ISGITLINK(a_mode))) { + if (dir_in_way(path, + !o->call_depth && !S_ISGITLINK(a_mode), + 0)) { char *new_path = unique_path(o, path, add_branch); clean_merge = 0; output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. " @@@ -2082,7 -2081,7 +2082,7 @@@ int merge_recursive(struct merge_option /* if there is no common ancestor, use an empty tree */ struct tree *tree; - tree = lookup_tree(&empty_tree_oid); + tree = lookup_tree(the_hash_algo->empty_tree); merged_common_ancestors = make_virtual_commit(tree, "ancestor"); } @@@ -2202,7 -2201,6 +2202,7 @@@ static void merge_recursive_config(stru void init_merge_options(struct merge_options *o) { + const char *merge_verbosity; memset(o, 0, sizeof(struct merge_options)); o->verbosity = 2; o->buffer_output = 1; @@@ -2211,9 -2209,9 +2211,9 @@@ o->renormalize = 0; o->detect_rename = 1; merge_recursive_config(o); - if (getenv("GIT_MERGE_VERBOSITY")) - o->verbosity = - strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); + merge_verbosity = getenv("GIT_MERGE_VERBOSITY"); + if (merge_verbosity) + o->verbosity = strtol(merge_verbosity, NULL, 10); if (o->verbosity >= 5) o->buffer_output = 0; strbuf_init(&o->obuf, 0); @@@ -2253,8 -2251,6 +2253,8 @@@ int parse_merge_opt(struct merge_option DIFF_XDL_SET(o, IGNORE_WHITESPACE); else if (!strcmp(s, "ignore-space-at-eol")) DIFF_XDL_SET(o, IGNORE_WHITESPACE_AT_EOL); + else if (!strcmp(s, "ignore-cr-at-eol")) + DIFF_XDL_SET(o, IGNORE_CR_AT_EOL); else if (!strcmp(s, "renormalize")) o->renormalize = 1; else if (!strcmp(s, "no-renormalize")) diff --combined sequencer.c index fa94ed652d,2c191aeb36..e90bc316bb --- a/sequencer.c +++ b/sequencer.c @@@ -347,7 -347,7 +347,7 @@@ static int read_oneliner(struct strbuf static struct tree *empty_tree(void) { - return lookup_tree(&empty_tree_oid); + return lookup_tree(the_hash_algo->empty_tree); } static int error_dirty_index(struct replay_opts *opts) @@@ -438,8 -438,7 +438,8 @@@ static int do_recursive_merge(struct co char **xopt; static struct lock_file index_lock; - hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); + if (hold_locked_index(&index_lock, LOCK_REPORT_ON_ERROR) < 0) + return -1; read_cache(); @@@ -706,7 -705,7 +706,7 @@@ static int is_original_commit_empty(str oid_to_hex(&parent->object.oid)); ptree_oid = &parent->tree->object.oid; } else { - ptree_oid = &empty_tree_oid; /* commit is root */ + ptree_oid = the_hash_algo->empty_tree; /* commit is root */ } return !oidcmp(ptree_oid, &commit->tree->object.oid); @@@ -959,7 -958,7 +959,7 @@@ static int do_pick_commit(enum todo_com } else { unborn = get_oid("HEAD", &head); if (unborn) - oidcpy(&head, &empty_tree_oid); + oidcpy(&head, the_hash_algo->empty_tree); if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", NULL, 0)) return error_dirty_index(opts); @@@ -1118,11 -1117,11 +1118,11 @@@ */ if (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) && update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL, - REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) + REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) res = -1; if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) && update_ref(NULL, "REVERT_HEAD", &commit->object.oid, NULL, - REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) + REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) res = -1; if (res) { @@@ -2131,7 -2130,7 +2131,7 @@@ cleanup_head_ref msg = reflog_message(opts, "finish", "%s onto %s", head_ref.buf, buf.buf); if (update_ref(msg, head_ref.buf, &head, &orig, - REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) { + REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) { res = error(_("could not update %s"), head_ref.buf); goto cleanup_head_ref; @@@ -2671,19 -2670,6 +2671,19 @@@ leave_check return res; } +static int rewrite_file(const char *path, const char *buf, size_t len) +{ + int rc = 0; + int fd = open(path, O_WRONLY | O_TRUNC); + if (fd < 0) + return error_errno(_("could not open '%s' for writing"), path); + if (write_in_full(fd, buf, len) < 0) + rc = error_errno(_("could not write to '%s'"), path); + if (close(fd) && !rc) + rc = error_errno(_("could not close '%s'"), path); + return rc; +} + /* skip picking commits whose parents are unchanged */ int skip_unnecessary_picks(void) { @@@ -2756,11 -2742,29 +2756,11 @@@ } close(fd); - fd = open(rebase_path_todo(), O_WRONLY, 0666); - if (fd < 0) { - error_errno(_("could not open '%s' for writing"), - rebase_path_todo()); + if (rewrite_file(rebase_path_todo(), todo_list.buf.buf + offset, + todo_list.buf.len - offset) < 0) { todo_list_release(&todo_list); return -1; } - if (write_in_full(fd, todo_list.buf.buf + offset, - todo_list.buf.len - offset) < 0) { - error_errno(_("could not write to '%s'"), - rebase_path_todo()); - close(fd); - todo_list_release(&todo_list); - return -1; - } - if (ftruncate(fd, todo_list.buf.len - offset) < 0) { - error_errno(_("could not truncate '%s'"), - rebase_path_todo()); - todo_list_release(&todo_list); - close(fd); - return -1; - } - close(fd); todo_list.current = i; if (is_fixup(peek_command(&todo_list, 0))) @@@ -2945,7 -2949,15 +2945,7 @@@ int rearrange_squash(void } } - fd = open(todo_file, O_WRONLY); - if (fd < 0) - res = error_errno(_("could not open '%s'"), todo_file); - else if (write(fd, buf.buf, buf.len) < 0) - res = error_errno(_("could not write to '%s'"), todo_file); - else if (ftruncate(fd, buf.len) < 0) - res = error_errno(_("could not truncate '%s'"), - todo_file); - close(fd); + res = rewrite_file(todo_file, buf.buf, buf.len); strbuf_release(&buf); } diff --combined sha1_file.c index afe4b90f6e,a04389be71..b44f5247ca --- a/sha1_file.c +++ b/sha1_file.c @@@ -39,6 -39,64 +39,64 @@@ const struct object_id empty_blob_oid EMPTY_BLOB_SHA1_BIN_LITERAL }; + static void git_hash_sha1_init(void *ctx) + { + git_SHA1_Init((git_SHA_CTX *)ctx); + } + + static void git_hash_sha1_update(void *ctx, const void *data, size_t len) + { + git_SHA1_Update((git_SHA_CTX *)ctx, data, len); + } + + static void git_hash_sha1_final(unsigned char *hash, void *ctx) + { + git_SHA1_Final(hash, (git_SHA_CTX *)ctx); + } + + static void git_hash_unknown_init(void *ctx) + { + die("trying to init unknown hash"); + } + + static void git_hash_unknown_update(void *ctx, const void *data, size_t len) + { + die("trying to update unknown hash"); + } + + static void git_hash_unknown_final(unsigned char *hash, void *ctx) + { + die("trying to finalize unknown hash"); + } + + const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { + { + NULL, + 0x00000000, + 0, + 0, + 0, + git_hash_unknown_init, + git_hash_unknown_update, + git_hash_unknown_final, + NULL, + NULL, + }, + { + "sha-1", + /* "sha1", big-endian */ + 0x73686131, + sizeof(git_SHA_CTX), + GIT_SHA1_RAWSZ, + GIT_SHA1_HEXSZ, + git_hash_sha1_init, + git_hash_sha1_update, + git_hash_sha1_final, + &empty_tree_oid, + &empty_blob_oid, + }, + }; + /* * This is meant to hold a *small* number of objects that you would * want read_sha1_file() to be able to return, but yet you do not want @@@ -74,18 -132,6 +132,18 @@@ static struct cached_object *find_cache return NULL; } + +static enum safe_crlf get_safe_crlf(unsigned flags) +{ + if (flags & HASH_RENORMALIZE) + return SAFE_CRLF_RENORMALIZE; + else if (flags & HASH_WRITE_OBJECT) + return safe_crlf; + else + return SAFE_CRLF_FALSE; +} + + int mkdir_in_gitdir(const char *path) { if (mkdir(path, 0777)) { @@@ -416,9 -462,6 +474,9 @@@ static void link_alt_odb_entries(const struct strbuf objdirbuf = STRBUF_INIT; struct strbuf entry = STRBUF_INIT; + if (!alt || !*alt) + return; + if (depth > 5) { error("%s: ignoring alternate object stores, nesting too deep.", relative_base); @@@ -619,6 -662,7 +677,6 @@@ void prepare_alt_odb(void return; alt = getenv(ALTERNATE_DB_ENVIRONMENT); - if (!alt) alt = ""; alt_odb_tail = &alt_odb_list; link_alt_odb_entries(alt, PATH_SEP, NULL, 0); @@@ -1164,9 -1208,6 +1222,9 @@@ int sha1_object_info_extended(const uns lookup_replace_object(sha1) : sha1; + if (is_null_sha1(real)) + return -1; + if (!oi) oi = &blank_oi; @@@ -1694,7 -1735,7 +1752,7 @@@ static int index_mem(struct object_id * if ((type == OBJ_BLOB) && path) { struct strbuf nbuf = STRBUF_INIT; if (convert_to_git(&the_index, path, buf, size, &nbuf, - write_object ? safe_crlf : SAFE_CRLF_FALSE)) { + get_safe_crlf(flags))) { buf = strbuf_detach(&nbuf, &size); re_allocated = 1; } @@@ -1728,7 -1769,7 +1786,7 @@@ static int index_stream_convert_blob(st assert(would_convert_to_git_filter_fd(path)); convert_to_git_filter_fd(&the_index, path, fd, &sbuf, - write_object ? safe_crlf : SAFE_CRLF_FALSE); + get_safe_crlf(flags)); if (write_object) ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB), diff --combined submodule.c index 95e6aff2bb,ec269a6fc0..fa25888783 --- a/submodule.c +++ b/submodule.c @@@ -62,7 -62,7 +62,7 @@@ int is_staging_gitmodules_ok(const stru if ((pos >= 0) && (pos < istate->cache_nr)) { struct stat st; if (lstat(GITMODULES_FILE, &st) == 0 && - ce_match_stat(istate->cache[pos], &st, 0) & DATA_CHANGED) + ce_match_stat(istate->cache[pos], &st, CE_MATCH_IGNORE_FSMONITOR) & DATA_CHANGED) return 0; } @@@ -587,7 -587,7 +587,7 @@@ void show_submodule_inline_diff(struct struct object_id *one, struct object_id *two, unsigned dirty_submodule) { - const struct object_id *old = &empty_tree_oid, *new = &empty_tree_oid; + const struct object_id *old = the_hash_algo->empty_tree, *new = the_hash_algo->empty_tree; struct commit *left = NULL, *right = NULL; struct commit_list *merge_bases = NULL; struct child_process cp = CHILD_PROCESS_INIT; @@@ -1670,8 -1670,7 +1670,8 @@@ int submodule_move_head(const char *pat cp.dir = path; prepare_submodule_repo_env(&cp.env_array); - argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL); + argv_array_pushl(&cp.args, "update-ref", "HEAD", + "--no-deref", new, NULL); if (run_command(&cp)) { ret = -1;