Merge branch 'tb/weak-sha1-for-tail-sum'
The checksum at the tail of files are now computed without collision detection protection. This is safe as the consumer of the information to protect itself from replay attacks checks for hash collisions independently. * tb/weak-sha1-for-tail-sum: csum-file.c: use unsafe SHA-1 implementation when available Makefile: allow specifying a SHA-1 for non-cryptographic uses hash.h: scaffolding for _unsafe hashing variants sha1: do not redefine `platform_SHA_CTX` and friends pack-objects: use finalize_object_file() to rename pack/idx/etc finalize_object_file(): implement collision check finalize_object_file(): refactor unlink_or_warn() placement finalize_object_file(): check for name collision before renaming
This commit is contained in:
124
object-file.c
124
object-file.c
@ -115,6 +115,33 @@ static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
|
||||
oid->algo = GIT_HASH_SHA1;
|
||||
}
|
||||
|
||||
static void git_hash_sha1_init_unsafe(git_hash_ctx *ctx)
|
||||
{
|
||||
git_SHA1_Init_unsafe(&ctx->sha1_unsafe);
|
||||
}
|
||||
|
||||
static void git_hash_sha1_clone_unsafe(git_hash_ctx *dst, const git_hash_ctx *src)
|
||||
{
|
||||
git_SHA1_Clone_unsafe(&dst->sha1_unsafe, &src->sha1_unsafe);
|
||||
}
|
||||
|
||||
static void git_hash_sha1_update_unsafe(git_hash_ctx *ctx, const void *data,
|
||||
size_t len)
|
||||
{
|
||||
git_SHA1_Update_unsafe(&ctx->sha1_unsafe, data, len);
|
||||
}
|
||||
|
||||
static void git_hash_sha1_final_unsafe(unsigned char *hash, git_hash_ctx *ctx)
|
||||
{
|
||||
git_SHA1_Final_unsafe(hash, &ctx->sha1_unsafe);
|
||||
}
|
||||
|
||||
static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, git_hash_ctx *ctx)
|
||||
{
|
||||
git_SHA1_Final_unsafe(oid->hash, &ctx->sha1_unsafe);
|
||||
memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
|
||||
oid->algo = GIT_HASH_SHA1;
|
||||
}
|
||||
|
||||
static void git_hash_sha256_init(git_hash_ctx *ctx)
|
||||
{
|
||||
@ -189,6 +216,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
|
||||
.update_fn = git_hash_unknown_update,
|
||||
.final_fn = git_hash_unknown_final,
|
||||
.final_oid_fn = git_hash_unknown_final_oid,
|
||||
.unsafe_init_fn = git_hash_unknown_init,
|
||||
.unsafe_clone_fn = git_hash_unknown_clone,
|
||||
.unsafe_update_fn = git_hash_unknown_update,
|
||||
.unsafe_final_fn = git_hash_unknown_final,
|
||||
.unsafe_final_oid_fn = git_hash_unknown_final_oid,
|
||||
.empty_tree = NULL,
|
||||
.empty_blob = NULL,
|
||||
.null_oid = NULL,
|
||||
@ -204,6 +236,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
|
||||
.update_fn = git_hash_sha1_update,
|
||||
.final_fn = git_hash_sha1_final,
|
||||
.final_oid_fn = git_hash_sha1_final_oid,
|
||||
.unsafe_init_fn = git_hash_sha1_init_unsafe,
|
||||
.unsafe_clone_fn = git_hash_sha1_clone_unsafe,
|
||||
.unsafe_update_fn = git_hash_sha1_update_unsafe,
|
||||
.unsafe_final_fn = git_hash_sha1_final_unsafe,
|
||||
.unsafe_final_oid_fn = git_hash_sha1_final_oid_unsafe,
|
||||
.empty_tree = &empty_tree_oid,
|
||||
.empty_blob = &empty_blob_oid,
|
||||
.null_oid = &null_oid_sha1,
|
||||
@ -219,6 +256,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
|
||||
.update_fn = git_hash_sha256_update,
|
||||
.final_fn = git_hash_sha256_final,
|
||||
.final_oid_fn = git_hash_sha256_final_oid,
|
||||
.unsafe_init_fn = git_hash_sha256_init,
|
||||
.unsafe_clone_fn = git_hash_sha256_clone,
|
||||
.unsafe_update_fn = git_hash_sha256_update,
|
||||
.unsafe_final_fn = git_hash_sha256_final,
|
||||
.unsafe_final_oid_fn = git_hash_sha256_final_oid,
|
||||
.empty_tree = &empty_tree_oid_sha256,
|
||||
.empty_blob = &empty_blob_oid_sha256,
|
||||
.null_oid = &null_oid_sha256,
|
||||
@ -1932,17 +1974,77 @@ static void write_object_file_prepare_literally(const struct git_hash_algo *algo
|
||||
hash_object_body(algo, &c, buf, len, oid, hdr, hdrlen);
|
||||
}
|
||||
|
||||
static int check_collision(const char *filename_a, const char *filename_b)
|
||||
{
|
||||
char buf_a[4096], buf_b[4096];
|
||||
int fd_a = -1, fd_b = -1;
|
||||
int ret = 0;
|
||||
|
||||
fd_a = open(filename_a, O_RDONLY);
|
||||
if (fd_a < 0) {
|
||||
ret = error_errno(_("unable to open %s"), filename_a);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd_b = open(filename_b, O_RDONLY);
|
||||
if (fd_b < 0) {
|
||||
ret = error_errno(_("unable to open %s"), filename_b);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
ssize_t sz_a, sz_b;
|
||||
|
||||
sz_a = read_in_full(fd_a, buf_a, sizeof(buf_a));
|
||||
if (sz_a < 0) {
|
||||
ret = error_errno(_("unable to read %s"), filename_a);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sz_b = read_in_full(fd_b, buf_b, sizeof(buf_b));
|
||||
if (sz_b < 0) {
|
||||
ret = error_errno(_("unable to read %s"), filename_b);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sz_a != sz_b || memcmp(buf_a, buf_b, sz_a)) {
|
||||
ret = error(_("files '%s' and '%s' differ in contents"),
|
||||
filename_a, filename_b);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sz_a < sizeof(buf_a))
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (fd_a > -1)
|
||||
close(fd_a);
|
||||
if (fd_b > -1)
|
||||
close(fd_b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the just written object into its final resting place.
|
||||
*/
|
||||
int finalize_object_file(const char *tmpfile, const char *filename)
|
||||
{
|
||||
return finalize_object_file_flags(tmpfile, filename, 0);
|
||||
}
|
||||
|
||||
int finalize_object_file_flags(const char *tmpfile, const char *filename,
|
||||
enum finalize_object_file_flags flags)
|
||||
{
|
||||
struct stat st;
|
||||
int ret = 0;
|
||||
|
||||
if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
|
||||
goto try_rename;
|
||||
else if (link(tmpfile, filename))
|
||||
ret = errno;
|
||||
else
|
||||
unlink_or_warn(tmpfile);
|
||||
|
||||
/*
|
||||
* Coda hack - coda doesn't like cross-directory links,
|
||||
@ -1957,16 +2059,24 @@ int finalize_object_file(const char *tmpfile, const char *filename)
|
||||
*/
|
||||
if (ret && ret != EEXIST) {
|
||||
try_rename:
|
||||
if (!rename(tmpfile, filename))
|
||||
if (!stat(filename, &st))
|
||||
ret = EEXIST;
|
||||
else if (!rename(tmpfile, filename))
|
||||
goto out;
|
||||
ret = errno;
|
||||
else
|
||||
ret = errno;
|
||||
}
|
||||
unlink_or_warn(tmpfile);
|
||||
if (ret) {
|
||||
if (ret != EEXIST) {
|
||||
int saved_errno = errno;
|
||||
unlink_or_warn(tmpfile);
|
||||
errno = saved_errno;
|
||||
return error_errno(_("unable to write file %s"), filename);
|
||||
}
|
||||
/* FIXME!!! Collision check here ? */
|
||||
if (!(flags & FOF_SKIP_COLLISION_CHECK) &&
|
||||
check_collision(tmpfile, filename))
|
||||
return -1;
|
||||
unlink_or_warn(tmpfile);
|
||||
}
|
||||
|
||||
out:
|
||||
@ -2219,7 +2329,8 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
|
||||
warning_errno(_("failed utime() on %s"), tmp_file.buf);
|
||||
}
|
||||
|
||||
return finalize_object_file(tmp_file.buf, filename.buf);
|
||||
return finalize_object_file_flags(tmp_file.buf, filename.buf,
|
||||
FOF_SKIP_COLLISION_CHECK);
|
||||
}
|
||||
|
||||
static int freshen_loose_object(const struct object_id *oid)
|
||||
@ -2341,7 +2452,8 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||
strbuf_release(&dir);
|
||||
}
|
||||
|
||||
err = finalize_object_file(tmp_file.buf, filename.buf);
|
||||
err = finalize_object_file_flags(tmp_file.buf, filename.buf,
|
||||
FOF_SKIP_COLLISION_CHECK);
|
||||
if (!err && compat)
|
||||
err = repo_add_loose_object_map(the_repository, oid, &compat_oid);
|
||||
cleanup:
|
||||
|
Reference in New Issue
Block a user