Merge branch 'eb/hash-transition'
Work to support a repository that work with both SHA-1 and SHA-256 hash algorithms has started. * eb/hash-transition: (30 commits) t1016-compatObjectFormat: add tests to verify the conversion between objects t1006: test oid compatibility with cat-file t1006: rename sha1 to oid test-lib: compute the compatibility hash so tests may use it builtin/ls-tree: let the oid determine the output algorithm object-file: handle compat objects in check_object_signature tree-walk: init_tree_desc take an oid to get the hash algorithm builtin/cat-file: let the oid determine the output algorithm rev-parse: add an --output-object-format parameter repository: implement extensions.compatObjectFormat object-file: update object_info_extended to reencode objects object-file-convert: convert commits that embed signed tags object-file-convert: convert commit objects when writing object-file-convert: don't leak when converting tag objects object-file-convert: convert tag objects when writing object-file-convert: add a function to convert trees between algorithms object: factor out parse_mode out of fast-import and tree-walk into in object.h cache: add a function to read an OID of a specific algorithm tag: sign both hashes commit: export add_header_signature to support handling signatures on tags ...
This commit is contained in:
212
object-file.c
212
object-file.c
@@ -35,6 +35,8 @@
|
||||
#include "setup.h"
|
||||
#include "submodule.h"
|
||||
#include "fsck.h"
|
||||
#include "loose.h"
|
||||
#include "object-file-convert.h"
|
||||
|
||||
/* The maximum size for an object header. */
|
||||
#define MAX_HEADER_LEN 32
|
||||
@@ -1084,9 +1086,11 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
|
||||
void *buf, unsigned long size,
|
||||
enum object_type type)
|
||||
{
|
||||
const struct git_hash_algo *algo =
|
||||
oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
|
||||
struct object_id real_oid;
|
||||
|
||||
hash_object_file(r->hash_algo, buf, size, type, &real_oid);
|
||||
hash_object_file(algo, buf, size, type, &real_oid);
|
||||
|
||||
return !oideq(oid, &real_oid) ? -1 : 0;
|
||||
}
|
||||
@@ -1652,10 +1656,101 @@ static int do_oid_object_info_extended(struct repository *r,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oid_object_info_convert(struct repository *r,
|
||||
const struct object_id *input_oid,
|
||||
struct object_info *input_oi, unsigned flags)
|
||||
{
|
||||
const struct git_hash_algo *input_algo = &hash_algos[input_oid->algo];
|
||||
int do_die = flags & OBJECT_INFO_DIE_IF_CORRUPT;
|
||||
struct strbuf type_name = STRBUF_INIT;
|
||||
struct object_id oid, delta_base_oid;
|
||||
struct object_info new_oi, *oi;
|
||||
unsigned long size;
|
||||
void *content;
|
||||
int ret;
|
||||
|
||||
if (repo_oid_to_algop(r, input_oid, the_hash_algo, &oid)) {
|
||||
if (do_die)
|
||||
die(_("missing mapping of %s to %s"),
|
||||
oid_to_hex(input_oid), the_hash_algo->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is new_oi needed? */
|
||||
oi = input_oi;
|
||||
if (input_oi && (input_oi->delta_base_oid || input_oi->sizep ||
|
||||
input_oi->contentp)) {
|
||||
new_oi = *input_oi;
|
||||
/* Does delta_base_oid need to be converted? */
|
||||
if (input_oi->delta_base_oid)
|
||||
new_oi.delta_base_oid = &delta_base_oid;
|
||||
/* Will the attributes differ when converted? */
|
||||
if (input_oi->sizep || input_oi->contentp) {
|
||||
new_oi.contentp = &content;
|
||||
new_oi.sizep = &size;
|
||||
new_oi.type_name = &type_name;
|
||||
}
|
||||
oi = &new_oi;
|
||||
}
|
||||
|
||||
ret = oid_object_info_extended(r, &oid, oi, flags);
|
||||
if (ret)
|
||||
return -1;
|
||||
if (oi == input_oi)
|
||||
return ret;
|
||||
|
||||
if (new_oi.contentp) {
|
||||
struct strbuf outbuf = STRBUF_INIT;
|
||||
enum object_type type;
|
||||
|
||||
type = type_from_string_gently(type_name.buf, type_name.len,
|
||||
!do_die);
|
||||
if (type == -1)
|
||||
return -1;
|
||||
if (type != OBJ_BLOB) {
|
||||
ret = convert_object_file(&outbuf,
|
||||
the_hash_algo, input_algo,
|
||||
content, size, type, !do_die);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
free(content);
|
||||
size = outbuf.len;
|
||||
content = strbuf_detach(&outbuf, NULL);
|
||||
}
|
||||
if (input_oi->sizep)
|
||||
*input_oi->sizep = size;
|
||||
if (input_oi->contentp)
|
||||
*input_oi->contentp = content;
|
||||
else
|
||||
free(content);
|
||||
if (input_oi->type_name)
|
||||
*input_oi->type_name = type_name;
|
||||
else
|
||||
strbuf_release(&type_name);
|
||||
}
|
||||
if (new_oi.delta_base_oid == &delta_base_oid) {
|
||||
if (repo_oid_to_algop(r, &delta_base_oid, input_algo,
|
||||
input_oi->delta_base_oid)) {
|
||||
if (do_die)
|
||||
die(_("missing mapping of %s to %s"),
|
||||
oid_to_hex(&delta_base_oid),
|
||||
input_algo->name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
input_oi->whence = new_oi.whence;
|
||||
input_oi->u = new_oi.u;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int oid_object_info_extended(struct repository *r, const struct object_id *oid,
|
||||
struct object_info *oi, unsigned flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (oid->algo && (hash_algo_by_ptr(r->hash_algo) != oid->algo))
|
||||
return oid_object_info_convert(r, oid, oi, flags);
|
||||
|
||||
obj_read_lock();
|
||||
ret = do_oid_object_info_extended(r, oid, oi, flags);
|
||||
obj_read_unlock();
|
||||
@@ -1944,9 +2039,12 @@ static int start_loose_object_common(struct strbuf *tmp_file,
|
||||
const char *filename, unsigned flags,
|
||||
git_zstream *stream,
|
||||
unsigned char *buf, size_t buflen,
|
||||
git_hash_ctx *c,
|
||||
git_hash_ctx *c, git_hash_ctx *compat_c,
|
||||
char *hdr, int hdrlen)
|
||||
{
|
||||
struct repository *repo = the_repository;
|
||||
const struct git_hash_algo *algo = repo->hash_algo;
|
||||
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||
int fd;
|
||||
|
||||
fd = create_tmpfile(tmp_file, filename);
|
||||
@@ -1966,14 +2064,18 @@ static int start_loose_object_common(struct strbuf *tmp_file,
|
||||
git_deflate_init(stream, zlib_compression_level);
|
||||
stream->next_out = buf;
|
||||
stream->avail_out = buflen;
|
||||
the_hash_algo->init_fn(c);
|
||||
algo->init_fn(c);
|
||||
if (compat && compat_c)
|
||||
compat->init_fn(compat_c);
|
||||
|
||||
/* Start to feed header to zlib stream */
|
||||
stream->next_in = (unsigned char *)hdr;
|
||||
stream->avail_in = hdrlen;
|
||||
while (git_deflate(stream, 0) == Z_OK)
|
||||
; /* nothing */
|
||||
the_hash_algo->update_fn(c, hdr, hdrlen);
|
||||
algo->update_fn(c, hdr, hdrlen);
|
||||
if (compat && compat_c)
|
||||
compat->update_fn(compat_c, hdr, hdrlen);
|
||||
|
||||
return fd;
|
||||
}
|
||||
@@ -1982,16 +2084,21 @@ static int start_loose_object_common(struct strbuf *tmp_file,
|
||||
* Common steps for the inner git_deflate() loop for writing loose
|
||||
* objects. Returns what git_deflate() returns.
|
||||
*/
|
||||
static int write_loose_object_common(git_hash_ctx *c,
|
||||
static int write_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
|
||||
git_zstream *stream, const int flush,
|
||||
unsigned char *in0, const int fd,
|
||||
unsigned char *compressed,
|
||||
const size_t compressed_len)
|
||||
{
|
||||
struct repository *repo = the_repository;
|
||||
const struct git_hash_algo *algo = repo->hash_algo;
|
||||
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||
int ret;
|
||||
|
||||
ret = git_deflate(stream, flush ? Z_FINISH : 0);
|
||||
the_hash_algo->update_fn(c, in0, stream->next_in - in0);
|
||||
algo->update_fn(c, in0, stream->next_in - in0);
|
||||
if (compat && compat_c)
|
||||
compat->update_fn(compat_c, in0, stream->next_in - in0);
|
||||
if (write_in_full(fd, compressed, stream->next_out - compressed) < 0)
|
||||
die_errno(_("unable to write loose object file"));
|
||||
stream->next_out = compressed;
|
||||
@@ -2006,15 +2113,21 @@ static int write_loose_object_common(git_hash_ctx *c,
|
||||
* - End the compression of zlib stream.
|
||||
* - Get the calculated oid to "oid".
|
||||
*/
|
||||
static int end_loose_object_common(git_hash_ctx *c, git_zstream *stream,
|
||||
struct object_id *oid)
|
||||
static int end_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
|
||||
git_zstream *stream, struct object_id *oid,
|
||||
struct object_id *compat_oid)
|
||||
{
|
||||
struct repository *repo = the_repository;
|
||||
const struct git_hash_algo *algo = repo->hash_algo;
|
||||
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||
int ret;
|
||||
|
||||
ret = git_deflate_end_gently(stream);
|
||||
if (ret != Z_OK)
|
||||
return ret;
|
||||
the_hash_algo->final_oid_fn(oid, c);
|
||||
algo->final_oid_fn(oid, c);
|
||||
if (compat && compat_c)
|
||||
compat->final_oid_fn(compat_oid, compat_c);
|
||||
|
||||
return Z_OK;
|
||||
}
|
||||
@@ -2038,7 +2151,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
|
||||
|
||||
fd = start_loose_object_common(&tmp_file, filename.buf, flags,
|
||||
&stream, compressed, sizeof(compressed),
|
||||
&c, hdr, hdrlen);
|
||||
&c, NULL, hdr, hdrlen);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
@@ -2048,14 +2161,14 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
|
||||
do {
|
||||
unsigned char *in0 = stream.next_in;
|
||||
|
||||
ret = write_loose_object_common(&c, &stream, 1, in0, fd,
|
||||
ret = write_loose_object_common(&c, NULL, &stream, 1, in0, fd,
|
||||
compressed, sizeof(compressed));
|
||||
} while (ret == Z_OK);
|
||||
|
||||
if (ret != Z_STREAM_END)
|
||||
die(_("unable to deflate new object %s (%d)"), oid_to_hex(oid),
|
||||
ret);
|
||||
ret = end_loose_object_common(&c, &stream, ¶no_oid);
|
||||
ret = end_loose_object_common(&c, NULL, &stream, ¶no_oid, NULL);
|
||||
if (ret != Z_OK)
|
||||
die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
|
||||
ret);
|
||||
@@ -2100,10 +2213,12 @@ static int freshen_packed_object(const struct object_id *oid)
|
||||
int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||
struct object_id *oid)
|
||||
{
|
||||
const struct git_hash_algo *compat = the_repository->compat_hash_algo;
|
||||
struct object_id compat_oid;
|
||||
int fd, ret, err = 0, flush = 0;
|
||||
unsigned char compressed[4096];
|
||||
git_zstream stream;
|
||||
git_hash_ctx c;
|
||||
git_hash_ctx c, compat_c;
|
||||
struct strbuf tmp_file = STRBUF_INIT;
|
||||
struct strbuf filename = STRBUF_INIT;
|
||||
int dirlen;
|
||||
@@ -2127,7 +2242,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||
*/
|
||||
fd = start_loose_object_common(&tmp_file, filename.buf, 0,
|
||||
&stream, compressed, sizeof(compressed),
|
||||
&c, hdr, hdrlen);
|
||||
&c, &compat_c, hdr, hdrlen);
|
||||
if (fd < 0) {
|
||||
err = -1;
|
||||
goto cleanup;
|
||||
@@ -2145,7 +2260,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||
if (in_stream->is_finished)
|
||||
flush = 1;
|
||||
}
|
||||
ret = write_loose_object_common(&c, &stream, flush, in0, fd,
|
||||
ret = write_loose_object_common(&c, &compat_c, &stream, flush, in0, fd,
|
||||
compressed, sizeof(compressed));
|
||||
/*
|
||||
* Unlike write_loose_object(), we do not have the entire
|
||||
@@ -2168,7 +2283,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||
*/
|
||||
if (ret != Z_STREAM_END)
|
||||
die(_("unable to stream deflate new object (%d)"), ret);
|
||||
ret = end_loose_object_common(&c, &stream, oid);
|
||||
ret = end_loose_object_common(&c, &compat_c, &stream, oid, &compat_oid);
|
||||
if (ret != Z_OK)
|
||||
die(_("deflateEnd on stream object failed (%d)"), ret);
|
||||
close_loose_object(fd, tmp_file.buf);
|
||||
@@ -2195,6 +2310,8 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
|
||||
}
|
||||
|
||||
err = finalize_object_file(tmp_file.buf, filename.buf);
|
||||
if (!err && compat)
|
||||
err = repo_add_loose_object_map(the_repository, oid, &compat_oid);
|
||||
cleanup:
|
||||
strbuf_release(&tmp_file);
|
||||
strbuf_release(&filename);
|
||||
@@ -2203,19 +2320,42 @@ cleanup:
|
||||
|
||||
int write_object_file_flags(const void *buf, unsigned long len,
|
||||
enum object_type type, struct object_id *oid,
|
||||
unsigned flags)
|
||||
struct object_id *compat_oid_in, unsigned flags)
|
||||
{
|
||||
struct repository *repo = the_repository;
|
||||
const struct git_hash_algo *algo = repo->hash_algo;
|
||||
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||
struct object_id compat_oid;
|
||||
char hdr[MAX_HEADER_LEN];
|
||||
int hdrlen = sizeof(hdr);
|
||||
|
||||
/* Generate compat_oid */
|
||||
if (compat) {
|
||||
if (compat_oid_in)
|
||||
oidcpy(&compat_oid, compat_oid_in);
|
||||
else if (type == OBJ_BLOB)
|
||||
hash_object_file(compat, buf, len, type, &compat_oid);
|
||||
else {
|
||||
struct strbuf converted = STRBUF_INIT;
|
||||
convert_object_file(&converted, algo, compat,
|
||||
buf, len, type, 0);
|
||||
hash_object_file(compat, converted.buf, converted.len,
|
||||
type, &compat_oid);
|
||||
strbuf_release(&converted);
|
||||
}
|
||||
}
|
||||
|
||||
/* Normally if we have it in the pack then we do not bother writing
|
||||
* it out into .git/objects/??/?{38} file.
|
||||
*/
|
||||
write_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr,
|
||||
&hdrlen);
|
||||
write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
|
||||
if (freshen_packed_object(oid) || freshen_loose_object(oid))
|
||||
return 0;
|
||||
return write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags);
|
||||
if (write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags))
|
||||
return -1;
|
||||
if (compat)
|
||||
return repo_add_loose_object_map(repo, oid, &compat_oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_object_file_literally(const void *buf, unsigned long len,
|
||||
@@ -2223,7 +2363,27 @@ int write_object_file_literally(const void *buf, unsigned long len,
|
||||
unsigned flags)
|
||||
{
|
||||
char *header;
|
||||
struct repository *repo = the_repository;
|
||||
const struct git_hash_algo *algo = repo->hash_algo;
|
||||
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||
struct object_id compat_oid;
|
||||
int hdrlen, status = 0;
|
||||
int compat_type = -1;
|
||||
|
||||
if (compat) {
|
||||
compat_type = type_from_string_gently(type, -1, 1);
|
||||
if (compat_type == OBJ_BLOB)
|
||||
hash_object_file(compat, buf, len, compat_type,
|
||||
&compat_oid);
|
||||
else if (compat_type != -1) {
|
||||
struct strbuf converted = STRBUF_INIT;
|
||||
convert_object_file(&converted, algo, compat,
|
||||
buf, len, compat_type, 0);
|
||||
hash_object_file(compat, converted.buf, converted.len,
|
||||
compat_type, &compat_oid);
|
||||
strbuf_release(&converted);
|
||||
}
|
||||
}
|
||||
|
||||
/* type string, SP, %lu of the length plus NUL must fit this */
|
||||
hdrlen = strlen(type) + MAX_HEADER_LEN;
|
||||
@@ -2236,6 +2396,8 @@ int write_object_file_literally(const void *buf, unsigned long len,
|
||||
if (freshen_packed_object(oid) || freshen_loose_object(oid))
|
||||
goto cleanup;
|
||||
status = write_loose_object(oid, header, hdrlen, buf, len, 0, 0);
|
||||
if (compat_type != -1)
|
||||
return repo_add_loose_object_map(repo, oid, &compat_oid);
|
||||
|
||||
cleanup:
|
||||
free(header);
|
||||
@@ -2244,9 +2406,12 @@ cleanup:
|
||||
|
||||
int force_object_loose(const struct object_id *oid, time_t mtime)
|
||||
{
|
||||
struct repository *repo = the_repository;
|
||||
const struct git_hash_algo *compat = repo->compat_hash_algo;
|
||||
void *buf;
|
||||
unsigned long len;
|
||||
struct object_info oi = OBJECT_INFO_INIT;
|
||||
struct object_id compat_oid;
|
||||
enum object_type type;
|
||||
char hdr[MAX_HEADER_LEN];
|
||||
int hdrlen;
|
||||
@@ -2259,8 +2424,15 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
|
||||
oi.contentp = &buf;
|
||||
if (oid_object_info_extended(the_repository, oid, &oi, 0))
|
||||
return error(_("cannot read object for %s"), oid_to_hex(oid));
|
||||
if (compat) {
|
||||
if (repo_oid_to_algop(repo, oid, compat, &compat_oid))
|
||||
return error(_("cannot map object %s to %s"),
|
||||
oid_to_hex(oid), compat->name);
|
||||
}
|
||||
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
|
||||
ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
|
||||
if (!ret && compat)
|
||||
ret = repo_add_loose_object_map(the_repository, oid, &compat_oid);
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user