8000 odb_loose: SHA256 support for loose object storage · libgit2/libgit2@af87971 · GitHub
[go: up one dir, main page]

Skip to content

Commit af87971

Browse files
committed
odb_loose: SHA256 support for loose object storage
Teach the loose object database how to cope with SHA256 objects.
1 parent 4ffc6b4 commit af87971

File tree

5 files changed

+515
-70
lines changed

5 files changed

+515
-70
lines changed

include/git2/odb_backend.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,19 @@ typedef struct {
5959

6060
/** Permissi 8000 ons to use creating a file or 0 for defaults */
6161
unsigned int file_mode;
62+
63+
/**
64+
* Type of object IDs to use for this object database, or
65+
* 0 for default (currently SHA1).
66+
*/
67+
git_oid_t oid_type;
6268
} git_odb_backend_loose_options;
6369

6470
/* The current version of the diff options structure */
6571
#define GIT_ODB_BACKEND_LOOSE_OPTIONS_VERSION 1
6672

67-
/* Stack initializer for diff options. Alternatively use
68-
* `git_diff_options_init` programmatic initialization.
73+
/* Stack initializer for odb loose backend options. Alternatively use
74+
* `git_odb_backend_loose_options_init` programmatic initialization.
6975
*/
7076
#define GIT_ODB_BACKEND_LOOSE_OPTIONS_INIT \
7177
{ GIT_ODB_BACKEND_LOOSE_OPTIONS_VERSION, 0, -1 }

src/odb.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,8 @@ int git_odb__add_default_backends(
663663
if (db->do_fsync)
664664
loose_opts.flags |= GIT_ODB_BACKEND_LOOSE_FSYNC;
665665

666+
loose_opts.oid_type = db->options.oid_type;
667+
666668
/* add the loose object backend */
667669
if (git_odb_backend_loose(&loose, objects_dir, &loose_opts) < 0 ||
668670
add_backend_internal(db, loose, git_odb__loose_priority, as_alternates, inode) < 0)

src/odb_loose.c

Lines changed: 57 additions & 44 deletions
< 6377 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ typedef struct loose_backend {
4747
git_odb_backend parent;
4848

4949
git_odb_backend_loose_options options;
50+
size_t oid_hexsize;
5051

5152
size_t objects_dirlen;
5253
char objects_dir[GIT_FLEX_ARRAY];
@@ -56,13 +57,19 @@ typedef struct loose_backend {
5657
* in order to locate objects matching a short oid.
5758
*/
5859
typedef struct {
60+
loose_backend *backend;
61+
5962
size_t dir_len;
60-
unsigned char short_oid[GIT_OID_SHA1_HEXSIZE]; /* hex formatted oid to match */
63+
64+
/* Hex formatted oid to match (and its length) */
65+
unsigned char short_oid[GIT_OID_MAX_HEXSIZE];
6166
size_t short_oid_len;
62-
int found; /* number of matching
63-
* objects already found */
64-
unsigned char res_oid[GIT_OID_SHA1_HEXSIZE]; /* hex formatted oid of
65-
* the object found */
67+
68+
/* Number of matching objects found so far */
69+
int found;
70+
71+
/* Hex formatted oid of the object found */
72+
unsigned char res_oid[GIT_OID_MAX_HEXSIZE];
6673
} loose_locate_object_state;
6774

6875

@@ -75,20 +82,17 @@ typedef struct {
7582
static int object_file_name(
7683
git_str *name, const loose_backend *be, const git_oid *id)
7784
{
78-
size_t alloclen;
79-
80-
/* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */
81-
GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, be->objects_dirlen, GIT_OID_SHA1_HEXSIZE);
82-
GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 3);
83-
if (git_str_grow(name, alloclen) < 0)
84-
return -1;
85+
/* append loose object filename: aa/aaa... (41 bytes plus NUL) */
86+
size_t path_size = be->oid_hexsize + 1;
8587

8688
git_str_set(name, be->objects_dir, be->objects_dirlen);
8789
git_fs_path_to_dir(name);
8890

89-
/* loose object filename: aa/aaa... (41 bytes) */
91+
if (git_str_grow_by(name, path_size + 1) < 0)
92+
return -1;
93+
9094
git_oid_pathfmt(name->ptr + name->size, id);
91-
name->size += GIT_OID_SHA1_HEXSIZE + 1;
95+
name->size += path_size;
9296
name->ptr[name->size] = '\0';
9397

9498
return 0;
@@ -460,8 +464,9 @@ static int locate_object(
460464
/* Explore an entry of a directory and see if it matches a short oid */
461465
static int fn_locate_object_short_oid(void *state, git_str *pathbuf) {
462466
loose_locate_object_state *sstate = (loose_locate_object_state *)state;
467+
size_t hex_size = sstate->backend->oid_hexsize;
463468

464-
if (git_str_len(pathbuf) - sstate->dir_len != GIT_OID_SHA1_HEXSIZE - 2) {
469+
if (git_str_len(pathbuf) - sstate->dir_len != hex_size - 2) {
465470
/* Entry cannot be an object. Continue to next entry */
466471
return 0;
467472
}
@@ -476,7 +481,9 @@ static int fn_locate_object_short_oid(void *state, git_str *pathbuf) {
476481
if (!sstate->found) {
477482
sstate->res_oid[0] = sstate->short_oid[0];
478483
sstate->res_oid[1] = sstate->short_oid[1];
479-
memcpy(sstate->res_oid+2, pathbuf->ptr+sstate->dir_len, GIT_OID_SHA1_HEXSIZE-2);
484+
memcpy(sstate->res_oid + 2,
485+
pathbuf->ptr+sstate->dir_len,
486+
hex_size - 2);
480487
}
481488
sstate->found++;
482489
}
@@ -502,7 +509,7 @@ static int locate_object_short_oid(
502509
int error;
503510

504511
/* prealloc memory for OBJ_DIR/xx/xx..38x..xx */
505-
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_SHA1_HEXSIZE);
512+
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, dir_len, backend->oid_hexsize);
506513
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 3);
507514
if (git_str_grow(object_location, alloc_len) < 0)
508515
return -1;
@@ -526,6 +533,7 @@ static int locate_object_short_oid(
526533
return git_odb__error_notfound("no matching loose object for prefix",
527534
short_oid, len);
528535

536+
state.backend = backend;
529537
state.dir_len = git_str_len(object_location);
530538
state.short_oid_len = len;
531539
state.found = 0;
@@ -544,12 +552,12 @@ static int locate_object_short_oid(
544552
return git_odb__error_ambiguous("multiple matches in loose objects");
545553

546554
/* Convert obtained hex formatted oid to raw */
547-
error = git_oid_fromstr(res_oid, (char *)state.res_oid, GIT_OID_SHA1);
555+
error = git_oid_fromstr(res_oid, (char *)state.res_oid, backend->options.oid_type);
548556
if (error)
549557
return error;
550558

551559
/* Update the location according to the oid obtained */
552-
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_SHA1_HEXSIZE);
560+
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, dir_len, backend->oid_hexsize);
553561
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
554562

555563
git_str_truncate(object_location, dir_len);
@@ -558,20 +566,12 @@ static int locate_object_short_oid(
558566

559567
git_oid_pathfmt(object_location->ptr + dir_len, res_oid);
560568

561-
object_location->size += GIT_OID_SHA1_HEXSIZE + 1;
569+
object_location->size += backend->oid_hexsize + 1;
562570
object_location->ptr[object_location->size] = '\0';
563571

564572
return 0;
565573
}
566574

567-
568-
569-
570-
571-
572-
573-
574-
575575
/***********************************************************
576576
*
577577
* LOOSE BACKEND PUBLIC API
@@ -594,7 +594,7 @@ static int loose_backend__read_header(size_t *len_p, git_object_t *type_p, git_o
594594

595595
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) {
596596
error = git_odb__error_notfound("no matching loose object",
597-
oid, GIT_OID_SHA1_HEXSIZE);
597+
oid, ((struct loose_backend *)backend)->oid_hexsize);
598598
} else if ((error = read_header_loose(&raw, &object_path)) == 0) {
599599
*len_p = raw.len;
600600
*type_p = raw.type;
@@ -616,7 +616,7 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_object_t *typ
616616

617617
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) {
618618
error = git_odb__error_notfound("no matching loose object",
619-
oid, GIT_OID_SHA1_HEXSIZE);
619+
oid, ((struct loose_backend *)backend)->oid_hexsize);
620620
} else if ((error = read_loose(&raw, &object_path)) == 0) {
621621
*buffer_p = raw.data;
622622
*len_p = raw.len;
@@ -633,17 +633,19 @@ static int loose_backend__read_prefix(
633633
void **buffer_p,
634634
size_t *len_p,
635635
git_object_t *type_p,
636-
git_odb_backend *backend,
636+
git_odb_backend *_backend,
637637
const git_oid *short_oid,
638638
size_t len)
639639
{
640+
struct loose_backend *backend = (struct loose_backend *)_backend;
640641
int error = 0;
641642

642-
GIT_ASSERT_ARG(len >= GIT_OID_MINPREFIXLEN && len <= GIT_OID_SHA1_HEXSIZE);
643+
GIT_ASSERT_ARG(len >= GIT_OID_MINPREFIXLEN &&
644+
len <= backend->oid_hexsize);
643645

644-
if (len == GIT_OID_SHA1_HEXSIZE) {
646+
if (len == backend->oid_hexsize) {
645647
/* We can fall back to regular read method */
646-
error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
648+
error = loose_backend__read(buffer_p, len_p, type_p, _backend, short_oid);
647649
if (!error)
648650
git_oid_cpy(out_oid, short_oid);
649651
} else {
@@ -702,15 +704,18 @@ static int loose_backend__exists_prefix(
702704
}
703705

704706
struct foreach_state {
707+
struct loose_backend *backend;
705708
size_t dir_len;
706709
git_odb_foreach_cb cb;
707710
void *data;
708711
};
709712

710-
GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr)
713+
GIT_INLINE(int) filename_to_oid(struct loose_backend *backend, git_oid *oid, const char *ptr)
711714
{
712-
int v, i = 0;
713-
if (strlen(ptr) != GIT_OID_SHA1_HEXSIZE+1)
715+
int v;
716+
size_t i = 0;
717+
718+
if (strlen(ptr) != backend->oid_hexsize + 1)
714719
return -1;
715720

716721
if (ptr[2] != '/') {
@@ -724,15 +729,15 @@ GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr)
724729
oid->id[0] = (unsigned char) v;
725730

726731
ptr += 3;
727-
for (i = 0; i < 38; i += 2) {
732+
for (i = 0; i < backend->oid_hexsize - 2; i += 2) {
728733
v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i + 1]);
729734
if (v < 0)
730735
return -1;
731736

732737
oid->id[1 + i/2] = (unsigned char) v;
733738
}
734739

735-
oid->type = GIT_OID_SHA1;
740+
oid->type = backend->options.oid_type;
736741

737742
return 0;
738743
}
@@ -742,7 +747,7 @@ static int foreach_object_dir_cb(void *_state, git_str *path)
742747
git_oid oid;
743748
struct foreach_state *state = (struct foreach_state *) _state;
744749

745-
if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0)
750+
if (filename_to_oid(state->backend, &oid, path->ptr + state->dir_len) < 0)
746751
return 0;
747752

748753
return git_error_set_after_callback_function(
@@ -779,6 +784,7 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb
779784
return -1;
780785

781786
memset(&state, 0, sizeof(state));
787+
state.backend = backend;
782788
state.cb = cb;
783789
state.data = data;
784790
state.dir_len = git_str_len(&buf);
@@ -999,6 +1005,7 @@ static int loose_backend__readstream(
9991005
loose_readstream *stream = NULL;
10001006
git_hash_ctx *hash_ctx = NULL;
10011007
git_str object_path = GIT_STR_INIT;
1008+
git_hash_algorithm_t algorithm;
10021009
obj_hdr hdr;
10031010
int error = 0;
10041011

@@ -1015,7 +1022,7 @@ static int loose_backend__readstream(
10151022

10161023
if (locate_object(&object_path, backend, oid) < 0) {
10171024
error = git_odb__error_notfound("no matching loose object",
1018-
oid, GIT_OID_SHA1_HEXSIZE);
1025+
oid, backend->oid_hexsize);
10191026
goto done;
10201027
}
10211028

@@ -1025,9 +1032,11 @@ static int loose_backend__readstream(
10251032
hash_ctx = git__malloc(sizeof(git_hash_ctx));
10261033
GIT_ERROR_CHECK_ALLOC(hash_ctx);
10271034

1028-
if ((error = git_hash_ctx_init(hash_ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
1029-
(error = git_futils_mmap_ro_file(&stream->map, object_path.ptr)) < 0 ||
1030-
(error = git_zstream_init(&stream->zstream, GIT_ZSTREAM_INFLATE)) < 0)
1035+
algorithm = git_oid_algorithm(backend->options.oid_type);
1036+
1037+
if ((error = git_hash_ctx_init(hash_ctx, algorithm)) < 0 ||
1038+
(error = git_futils_mmap_ro_file(&stream->map, object_path.ptr)) < 0 ||
1039+
(error = git_zstream_init(&stream->zstream, GIT_ZSTREAM_INFLATE)) < 0)
10311040
goto done;
10321041

10331042
/* check for a packlike loose object */
@@ -1145,6 +1154,9 @@ static void normalize_options(
11451154

11461155
if (opts->file_mode == 0)
11471156
opts->file_mode = GIT_OBJECT_FILE_MODE;
1157+
1158+
if (opts->oid_type == 0)
1159+
opts->oid_type = GIT_OID_DEFAULT;
11481160
}
11491161

11501162
int git_odb_backend_loose(
@@ -1173,6 +1185,7 @@ int git_odb_backend_loose(
11731185
backend->objects_dir[backend->objects_dirlen++] = '/';
11741186

11751187
normalize_options(&backend->options, opts);
1188+
backend->oid_hexsize = git_oid_hexsize(backend->options.oid_type);
11761189

11771190
backend->parent.read = &loose_backend__read;
11781191
backend->parent.write = &loose_backend__write;

0 commit comments

Comments
 (0)
0