Skip to content

Commit 63a6745

Browse files
ebiedermgitster
authored andcommitted
object-file: update the loose object map when writing loose objects
To implement SHA1 compatibility on SHA256 repositories the loose object map needs to be updated whenver a loose object is written. Updating the loose object map this way allows git to support the old hash algorithm in constant time. The functions write_loose_object, and stream_loose_object are the only two functions that write to the loose object store. Update stream_loose_object to compute the compatibiilty hash, update the loose object, and then call repo_add_loose_object_map to update the loose object map. Update write_object_file_flags to convert the object into it's compatibility encoding, hash the compatibility encoding, write the object, and then update the loose object map. Update force_object_loose to lookup the hash of the compatibility encoding, write the loose object, and then update the loose object map. Update write_object_file_literally to convert the object into it's compatibility hash encoding, hash the compatibility enconding, write the object, and then update the loose object map, when the type string is a known type. For objects with an unknown type this results in a partially broken repository, as the objects are not mapped. The point of write_object_file_literally is to generate a partially broken repository for testing. For testing skipping writing the loose object map is much more useful than refusing to write the broken object at all. Except that the loose objects are updated before the loose object map I have not done any analysis to see how robust this scheme is in the event of failure. Signed-off-by: "Eric W. Biederman" <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a2d923f commit 63a6745

File tree

1 file changed

+95
-18
lines changed

1 file changed

+95
-18
lines changed

object-file.c

Lines changed: 95 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#include "setup.h"
4444
#include "submodule.h"
4545
#include "fsck.h"
46+
#include "loose.h"
47+
#include "object-file-convert.h"
4648

4749
/* The maximum size for an object header. */
4850
#define MAX_HEADER_LEN 32
@@ -1952,9 +1954,12 @@ static int start_loose_object_common(struct strbuf *tmp_file,
19521954
const char *filename, unsigned flags,
19531955
git_zstream *stream,
19541956
unsigned char *buf, size_t buflen,
1955-
git_hash_ctx *c,
1957+
git_hash_ctx *c, git_hash_ctx *compat_c,
19561958
char *hdr, int hdrlen)
19571959
{
1960+
struct repository *repo = the_repository;
1961+
const struct git_hash_algo *algo = repo->hash_algo;
1962+
const struct git_hash_algo *compat = repo->compat_hash_algo;
19581963
int fd;
19591964

19601965
fd = create_tmpfile(tmp_file, filename);
@@ -1974,14 +1979,18 @@ static int start_loose_object_common(struct strbuf *tmp_file,
19741979
git_deflate_init(stream, zlib_compression_level);
19751980
stream->next_out = buf;
19761981
stream->avail_out = buflen;
1977-
the_hash_algo->init_fn(c);
1982+
algo->init_fn(c);
1983+
if (compat && compat_c)
1984+
compat->init_fn(compat_c);
19781985

19791986
/* Start to feed header to zlib stream */
19801987
stream->next_in = (unsigned char *)hdr;
19811988
stream->avail_in = hdrlen;
19821989
while (git_deflate(stream, 0) == Z_OK)
19831990
; /* nothing */
1984-
the_hash_algo->update_fn(c, hdr, hdrlen);
1991+
algo->update_fn(c, hdr, hdrlen);
1992+
if (compat && compat_c)
1993+
compat->update_fn(compat_c, hdr, hdrlen);
19851994

19861995
return fd;
19871996
}
@@ -1990,16 +1999,21 @@ static int start_loose_object_common(struct strbuf *tmp_file,
19901999
* Common steps for the inner git_deflate() loop for writing loose
19912000
* objects. Returns what git_deflate() returns.
19922001
*/
1993-
static int write_loose_object_common(git_hash_ctx *c,
2002+
static int write_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
19942003
git_zstream *stream, const int flush,
19952004
unsigned char *in0, const int fd,
19962005
unsigned char *compressed,
19972006
const size_t compressed_len)
19982007
{
2008+
struct repository *repo = the_repository;
2009+
const struct git_hash_algo *algo = repo->hash_algo;
2010+
const struct git_hash_algo *compat = repo->compat_hash_algo;
19992011
int ret;
20002012

20012013
ret = git_deflate(stream, flush ? Z_FINISH : 0);
2002-
the_hash_algo->update_fn(c, in0, stream->next_in - in0);
2014+
algo->update_fn(c, in0, stream->next_in - in0);
2015+
if (compat && compat_c)
2016+
compat->update_fn(compat_c, in0, stream->next_in - in0);
20032017
if (write_in_full(fd, compressed, stream->next_out - compressed) < 0)
20042018
die_errno(_("unable to write loose object file"));
20052019
stream->next_out = compressed;
@@ -2014,15 +2028,21 @@ static int write_loose_object_common(git_hash_ctx *c,
20142028
* - End the compression of zlib stream.
20152029
* - Get the calculated oid to "oid".
20162030
*/
2017-
static int end_loose_object_common(git_hash_ctx *c, git_zstream *stream,
2018-
struct object_id *oid)
2031+
static int end_loose_object_common(git_hash_ctx *c, git_hash_ctx *compat_c,
2032+
git_zstream *stream, struct object_id *oid,
2033+
struct object_id *compat_oid)
20192034
{
2035+
struct repository *repo = the_repository;
2036+
const struct git_hash_algo *algo = repo->hash_algo;
2037+
const struct git_hash_algo *compat = repo->compat_hash_algo;
20202038
int ret;
20212039

20222040
ret = git_deflate_end_gently(stream);
20232041
if (ret != Z_OK)
20242042
return ret;
2025-
the_hash_algo->final_oid_fn(oid, c);
2043+
algo->final_oid_fn(oid, c);
2044+
if (compat && compat_c)
2045+
compat->final_oid_fn(compat_oid, compat_c);
20262046

20272047
return Z_OK;
20282048
}
@@ -2046,7 +2066,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
20462066

20472067
fd = start_loose_object_common(&tmp_file, filename.buf, flags,
20482068
&stream, compressed, sizeof(compressed),
2049-
&c, hdr, hdrlen);
2069+
&c, NULL, hdr, hdrlen);
20502070
if (fd < 0)
20512071
return -1;
20522072

@@ -2056,14 +2076,14 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
20562076
do {
20572077
unsigned char *in0 = stream.next_in;
20582078

2059-
ret = write_loose_object_common(&c, &stream, 1, in0, fd,
2079+
ret = write_loose_object_common(&c, NULL, &stream, 1, in0, fd,
20602080
compressed, sizeof(compressed));
20612081
} while (ret == Z_OK);
20622082

20632083
if (ret != Z_STREAM_END)
20642084
die(_("unable to deflate new object %s (%d)"), oid_to_hex(oid),
20652085
ret);
2066-
ret = end_loose_object_common(&c, &stream, &parano_oid);
2086+
ret = end_loose_object_common(&c, NULL, &stream, &parano_oid, NULL);
20672087
if (ret != Z_OK)
20682088
die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
20692089
ret);
@@ -2108,10 +2128,12 @@ static int freshen_packed_object(const struct object_id *oid)
21082128
int stream_loose_object(struct input_stream *in_stream, size_t len,
21092129
struct object_id *oid)
21102130
{
2131+
const struct git_hash_algo *compat = the_repository->compat_hash_algo;
2132+
struct object_id compat_oid;
21112133
int fd, ret, err = 0, flush = 0;
21122134
unsigned char compressed[4096];
21132135
git_zstream stream;
2114-
git_hash_ctx c;
2136+
git_hash_ctx c, compat_c;
21152137
struct strbuf tmp_file = STRBUF_INIT;
21162138
struct strbuf filename = STRBUF_INIT;
21172139
int dirlen;
@@ -2135,7 +2157,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
21352157
*/
21362158
fd = start_loose_object_common(&tmp_file, filename.buf, 0,
21372159
&stream, compressed, sizeof(compressed),
2138-
&c, hdr, hdrlen);
2160+
&c, &compat_c, hdr, hdrlen);
21392161
if (fd < 0) {
21402162
err = -1;
21412163
goto cleanup;
@@ -2153,7 +2175,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
21532175
if (in_stream->is_finished)
21542176
flush = 1;
21552177
}
2156-
ret = write_loose_object_common(&c, &stream, flush, in0, fd,
2178+
ret = write_loose_object_common(&c, &compat_c, &stream, flush, in0, fd,
21572179
compressed, sizeof(compressed));
21582180
/*
21592181
* Unlike write_loose_object(), we do not have the entire
@@ -2176,7 +2198,7 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
21762198
*/
21772199
if (ret != Z_STREAM_END)
21782200
die(_("unable to stream deflate new object (%d)"), ret);
2179-
ret = end_loose_object_common(&c, &stream, oid);
2201+
ret = end_loose_object_common(&c, &compat_c, &stream, oid, &compat_oid);
21802202
if (ret != Z_OK)
21812203
die(_("deflateEnd on stream object failed (%d)"), ret);
21822204
close_loose_object(fd, tmp_file.buf);
@@ -2203,6 +2225,8 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
22032225
}
22042226

22052227
err = finalize_object_file(tmp_file.buf, filename.buf);
2228+
if (!err && compat)
2229+
err = repo_add_loose_object_map(the_repository, oid, &compat_oid);
22062230
cleanup:
22072231
strbuf_release(&tmp_file);
22082232
strbuf_release(&filename);
@@ -2213,25 +2237,66 @@ int write_object_file_flags(const void *buf, unsigned long len,
22132237
enum object_type type, struct object_id *oid,
22142238
unsigned flags)
22152239
{
2240+
struct repository *repo = the_repository;
2241+
const struct git_hash_algo *algo = repo->hash_algo;
2242+
const struct git_hash_algo *compat = repo->compat_hash_algo;
2243+
struct object_id compat_oid;
22162244
char hdr[MAX_HEADER_LEN];
22172245
int hdrlen = sizeof(hdr);
22182246

2247+
/* Generate compat_oid */
2248+
if (compat) {
2249+
if (type == OBJ_BLOB)
2250+
hash_object_file(compat, buf, len, type, &compat_oid);
2251+
else {
2252+
struct strbuf converted = STRBUF_INIT;
2253+
convert_object_file(&converted, algo, compat,
2254+
buf, len, type, 0);
2255+
hash_object_file(compat, converted.buf, converted.len,
2256+
type, &compat_oid);
2257+
strbuf_release(&converted);
2258+
}
2259+
}
2260+
22192261
/* Normally if we have it in the pack then we do not bother writing
22202262
* it out into .git/objects/??/?{38} file.
22212263
*/
2222-
write_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr,
2223-
&hdrlen);
2264+
write_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);
22242265
if (freshen_packed_object(oid) || freshen_loose_object(oid))
22252266
return 0;
2226-
return write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags);
2267+
if (write_loose_object(oid, hdr, hdrlen, buf, len, 0, flags))
2268+
return -1;
2269+
if (compat)
2270+
return repo_add_loose_object_map(repo, oid, &compat_oid);
2271+
return 0;
22272272
}
22282273

22292274
int write_object_file_literally(const void *buf, unsigned long len,
22302275
const char *type, struct object_id *oid,
22312276
unsigned flags)
22322277
{
22332278
char *header;
2279+
struct repository *repo = the_repository;
2280+
const struct git_hash_algo *algo = repo->hash_algo;
2281+
const struct git_hash_algo *compat = repo->compat_hash_algo;
2282+
struct object_id compat_oid;
22342283
int hdrlen, status = 0;
2284+
int compat_type = -1;
2285+
2286+
if (compat) {
2287+
compat_type = type_from_string_gently(type, -1, 1);
2288+
if (compat_type == OBJ_BLOB)
2289+
hash_object_file(compat, buf, len, compat_type,
2290+
&compat_oid);
2291+
else if (compat_type != -1) {
2292+
struct strbuf converted = STRBUF_INIT;
2293+
convert_object_file(&converted, algo, compat,
2294+
buf, len, compat_type, 0);
2295+
hash_object_file(compat, converted.buf, converted.len,
2296+
compat_type, &compat_oid);
2297+
strbuf_release(&converted);
2298+
}
2299+
}
22352300

22362301
/* type string, SP, %lu of the length plus NUL must fit this */
22372302
hdrlen = strlen(type) + MAX_HEADER_LEN;
@@ -2244,6 +2309,8 @@ int write_object_file_literally(const void *buf, unsigned long len,
22442309
if (freshen_packed_object(oid) || freshen_loose_object(oid))
22452310
goto cleanup;
22462311
status = write_loose_object(oid, header, hdrlen, buf, len, 0, 0);
2312+
if (compat_type != -1)
2313+
return repo_add_loose_object_map(repo, oid, &compat_oid);
22472314

22482315
cleanup:
22492316
free(header);
@@ -2252,9 +2319,12 @@ int write_object_file_literally(const void *buf, unsigned long len,
22522319

22532320
int force_object_loose(const struct object_id *oid, time_t mtime)
22542321
{
2322+
struct repository *repo = the_repository;
2323+
const struct git_hash_algo *compat = repo->compat_hash_algo;
22552324
void *buf;
22562325
unsigned long len;
22572326
struct object_info oi = OBJECT_INFO_INIT;
2327+
struct object_id compat_oid;
22582328
enum object_type type;
22592329
char hdr[MAX_HEADER_LEN];
22602330
int hdrlen;
@@ -2267,8 +2337,15 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
22672337
oi.contentp = &buf;
22682338
if (oid_object_info_extended(the_repository, oid, &oi, 0))
22692339
return error(_("cannot read object for %s"), oid_to_hex(oid));
2340+
if (compat) {
2341+
if (repo_oid_to_algop(repo, oid, compat, &compat_oid))
2342+
return error(_("cannot map object %s to %s"),
2343+
oid_to_hex(oid), compat->name);
2344+
}
22702345
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
22712346
ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
2347+
if (!ret && compat)
2348+
ret = repo_add_loose_object_map(the_repository, oid, &compat_oid);
22722349
free(buf);
22732350

22742351
return ret;

0 commit comments

Comments
 (0)