Skip to content

Commit

Permalink
Merge branch 'bc/hash-algo'
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gitster committed Dec 13, 2017
2 parents 95ec6b1 + c250e02 commit 721cc43
Show file tree
Hide file tree
Showing 15 changed files with 175 additions and 37 deletions.
2 changes: 1 addition & 1 deletion builtin/am.c
Expand Up @@ -1433,7 +1433,7 @@ static void write_index_patch(const struct am_state *state)
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);
Expand Down
2 changes: 1 addition & 1 deletion builtin/checkout.c
Expand Up @@ -514,7 +514,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
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);
Expand Down
2 changes: 1 addition & 1 deletion builtin/diff.c
Expand Up @@ -379,7 +379,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
add_head_to_pending(&rev);
if (!rev.pending.nr) {
struct tree *tree;
tree = lookup_tree(&empty_tree_oid);
tree = lookup_tree(the_hash_algo->empty_tree);
add_pending_object(&rev, &tree->object, "HEAD");
}
break;
Expand Down
2 changes: 1 addition & 1 deletion builtin/pull.c
Expand Up @@ -557,7 +557,7 @@ static int pull_into_void(const struct object_id *merge_head,
* 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))
Expand Down
12 changes: 8 additions & 4 deletions cache.h
Expand Up @@ -14,6 +14,7 @@
#include "hash.h"
#include "path.h"
#include "sha1-array.h"
#include "repository.h"

#ifndef platform_SHA_CTX
/*
Expand Down Expand Up @@ -77,6 +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
Expand Down Expand Up @@ -907,6 +910,7 @@ struct repository_format {
int version;
int precious_objects;
int is_bare;
int hash_algo;
char *work_tree;
struct string_list unknown_extensions;
};
Expand Down Expand Up @@ -1039,22 +1043,22 @@ extern const struct object_id empty_blob_oid;

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) */
Expand Down
2 changes: 1 addition & 1 deletion diff-lib.c
Expand Up @@ -218,7 +218,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
} 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;
}
Expand Down
57 changes: 57 additions & 0 deletions hash.h
@@ -1,6 +1,8 @@
#ifndef HASH_H
#define HASH_H

#include "git-compat-util.h"

#if defined(SHA1_PPC)
#include "ppc/sha1.h"
#elif defined(SHA1_APPLE)
Expand All @@ -13,4 +15,59 @@
#include "block-sha1/sha1.h"
#endif

/*
* Note that these constants are suitable for indexing the hash_algos array and
* comparing against each other, but are otherwise arbitrary, so they should not
* be exposed to the user or serialized to disk. To know whether a
* git_hash_algo struct points to some usable hash function, test the format_id
* field for being non-zero. Use the name field for user-visible situations and
* the format_id field for fixed-length fields on disk.
*/
/* An unknown hash function. */
#define GIT_HASH_UNKNOWN 0
/* SHA-1 */
#define GIT_HASH_SHA1 1
/* Number of algorithms supported (including unknown). */
#define GIT_HASH_NALGOS (GIT_HASH_SHA1 + 1)

typedef void (*git_hash_init_fn)(void *ctx);
typedef void (*git_hash_update_fn)(void *ctx, const void *in, size_t len);
typedef void (*git_hash_final_fn)(unsigned char *hash, void *ctx);

struct git_hash_algo {
/*
* The name of the algorithm, as appears in the config file and in
* messages.
*/
const char *name;

/* A four-byte version identifier, used in pack indices. */
uint32_t format_id;

/* The size of a hash context (e.g. git_SHA_CTX). */
size_t ctxsz;

/* The length of the hash in binary. */
size_t rawsz;

/* The length of the hash in hex characters. */
size_t hexsz;

/* The hash initialization function. */
git_hash_init_fn init_fn;

/* The hash update function. */
git_hash_update_fn update_fn;

/* The hash finalization function. */
git_hash_final_fn final_fn;

/* The OID of the empty tree. */
const struct object_id *empty_tree;

/* The OID of the empty blob. */
const struct object_id *empty_blob;
};
extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];

#endif
2 changes: 1 addition & 1 deletion merge-recursive.c
Expand Up @@ -2082,7 +2082,7 @@ int merge_recursive(struct merge_options *o,
/* 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");
}

Expand Down
2 changes: 1 addition & 1 deletion notes-merge.c
Expand Up @@ -595,7 +595,7 @@ int notes_merge(struct notes_merge_options *o,
bases = get_merge_bases(local, remote);
if (!bases) {
base_oid = &null_oid;
base_tree_oid = &empty_tree_oid;
base_tree_oid = the_hash_algo->empty_tree;
if (o->verbosity >= 4)
printf("No merge base found; doing history-less merge\n");
} else if (!bases->next) {
Expand Down
9 changes: 8 additions & 1 deletion repository.c
Expand Up @@ -5,7 +5,7 @@

/* The main repository */
static struct repository the_repo = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, 0, 0
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, NULL, 0, 0
};
struct repository *the_repository = &the_repo;

Expand Down Expand Up @@ -64,6 +64,11 @@ void repo_set_gitdir(struct repository *repo, const char *path)
free(old_gitdir);
}

void repo_set_hash_algo(struct repository *repo, int hash_algo)
{
repo->hash_algo = &hash_algos[hash_algo];
}

/*
* Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
* Return 0 upon success and a non-zero value upon failure.
Expand Down Expand Up @@ -136,6 +141,8 @@ int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
if (read_and_verify_repository_format(&format, repo->commondir))
goto error;

repo_set_hash_algo(repo, format.hash_algo);

if (worktree)
repo_set_worktree(repo, worktree);

Expand Down
5 changes: 5 additions & 0 deletions repository.h
Expand Up @@ -4,6 +4,7 @@
struct config_set;
struct index_state;
struct submodule_cache;
struct git_hash_algo;

struct repository {
/* Environment */
Expand Down Expand Up @@ -67,6 +68,9 @@ struct repository {
*/
struct index_state *index;

/* Repository's current hash algorithm, as serialized on disk. */
const struct git_hash_algo *hash_algo;

/* Configurations */
/*
* Bit used during initialization to indicate if repository state (like
Expand All @@ -86,6 +90,7 @@ extern struct repository *the_repository;

extern void repo_set_gitdir(struct repository *repo, const char *path);
extern void repo_set_worktree(struct repository *repo, const char *path);
extern void repo_set_hash_algo(struct repository *repo, int algo);
extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);
extern int repo_submodule_init(struct repository *submodule,
struct repository *superproject,
Expand Down
6 changes: 3 additions & 3 deletions sequencer.c
Expand Up @@ -347,7 +347,7 @@ static int read_oneliner(struct strbuf *buf,

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)
Expand Down Expand Up @@ -706,7 +706,7 @@ static int is_original_commit_empty(struct commit *commit)
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);
Expand Down Expand Up @@ -959,7 +959,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
} 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);
Expand Down

0 comments on commit 721cc43

Please sign in to comment.