mirror of
https://github.com/git-for-windows/git.git
synced 2026-06-27 11:47:49 -05:00
The Git project is not exactly the easiest project to get started in: it's written in C and POSIX shell, with bits of Perl, Rust and other languages sprinkled into it. On top of that, the project has grown somewhat organically over time, making the codebase hard to navigate. These are problems that we're aware of, and there have been and still are efforts to clean up some of the technical debt that is natural to exist an a project that is more than 20 years old. Furthermore, we provide resources to newcomers that help them out like our coding guidelines, code of conduct or "MyFirstContribution.adoc". But there is a rather practical problem: finding your way around in our project's tree is not easy. Doing a directory listing in the top-level directory will present you with more than 550 files, which makes it extremely hard for a newcomer to figure out what files they are even supposed to look at. This makes the onboarding experience somewhat harder than it really needs to be. This isn't only a problem for newcomers though, as I myself struggle to find the files I am looking for because of the sheer number of files. Besides the problem of discoverability it also creates a problem of structure. It is not obvious at all which files are part of "libgit.a" and which files are only linked into our final executables. So while we have this split in our build systems, that split is not evident at all in our tree. Introduce a new "lib/" directory and move all of our sources for "libgit.a" into it to fix these issues. It makes the split we have evident and reduces the number of files in our top-level tree from 550 files to ~80 files. This is still a lot of files, but it's significantly easier to navigate already. Furthermore, we can further iterate after this step and think about introducing a better structure for remaining files, as well. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
216 lines
4.8 KiB
C
216 lines
4.8 KiB
C
#define USE_THE_REPOSITORY_VARIABLE
|
|
#define DISABLE_SIGN_COMPARE_WARNINGS
|
|
|
|
#include "git-compat-util.h"
|
|
#include "chunk-format.h"
|
|
#include "csum-file.h"
|
|
#include "gettext.h"
|
|
#include "hash.h"
|
|
#include "trace2.h"
|
|
|
|
/*
|
|
* When writing a chunk-based file format, collect the chunks in
|
|
* an array of chunk_info structs. The size stores the _expected_
|
|
* amount of data that will be written by write_fn.
|
|
*/
|
|
struct chunk_info {
|
|
uint32_t id;
|
|
uint64_t size;
|
|
chunk_write_fn write_fn;
|
|
|
|
const void *start;
|
|
};
|
|
|
|
struct chunkfile {
|
|
struct hashfile *f;
|
|
|
|
struct chunk_info *chunks;
|
|
size_t chunks_nr;
|
|
size_t chunks_alloc;
|
|
};
|
|
|
|
struct chunkfile *init_chunkfile(struct hashfile *f)
|
|
{
|
|
struct chunkfile *cf = xcalloc(1, sizeof(*cf));
|
|
cf->f = f;
|
|
return cf;
|
|
}
|
|
|
|
void free_chunkfile(struct chunkfile *cf)
|
|
{
|
|
if (!cf)
|
|
return;
|
|
free(cf->chunks);
|
|
free(cf);
|
|
}
|
|
|
|
int get_num_chunks(struct chunkfile *cf)
|
|
{
|
|
return cf->chunks_nr;
|
|
}
|
|
|
|
void add_chunk(struct chunkfile *cf,
|
|
uint32_t id,
|
|
size_t size,
|
|
chunk_write_fn fn)
|
|
{
|
|
ALLOC_GROW(cf->chunks, cf->chunks_nr + 1, cf->chunks_alloc);
|
|
|
|
cf->chunks[cf->chunks_nr].id = id;
|
|
cf->chunks[cf->chunks_nr].write_fn = fn;
|
|
cf->chunks[cf->chunks_nr].size = size;
|
|
cf->chunks_nr++;
|
|
}
|
|
|
|
int write_chunkfile(struct chunkfile *cf, void *data)
|
|
{
|
|
int i, result = 0;
|
|
uint64_t cur_offset = hashfile_total(cf->f);
|
|
|
|
trace2_region_enter("chunkfile", "write", the_repository);
|
|
|
|
/* Add the table of contents to the current offset */
|
|
cur_offset += (cf->chunks_nr + 1) * CHUNK_TOC_ENTRY_SIZE;
|
|
|
|
for (i = 0; i < cf->chunks_nr; i++) {
|
|
hashwrite_be32(cf->f, cf->chunks[i].id);
|
|
hashwrite_be64(cf->f, cur_offset);
|
|
|
|
cur_offset += cf->chunks[i].size;
|
|
}
|
|
|
|
/* Trailing entry marks the end of the chunks */
|
|
hashwrite_be32(cf->f, 0);
|
|
hashwrite_be64(cf->f, cur_offset);
|
|
|
|
for (i = 0; i < cf->chunks_nr; i++) {
|
|
off_t start_offset = hashfile_total(cf->f);
|
|
result = cf->chunks[i].write_fn(cf->f, data);
|
|
|
|
if (result)
|
|
goto cleanup;
|
|
|
|
if (hashfile_total(cf->f) - start_offset != cf->chunks[i].size)
|
|
BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
|
|
cf->chunks[i].size, cf->chunks[i].id,
|
|
hashfile_total(cf->f) - start_offset);
|
|
}
|
|
|
|
cleanup:
|
|
trace2_region_leave("chunkfile", "write", the_repository);
|
|
return result;
|
|
}
|
|
|
|
int read_table_of_contents(struct chunkfile *cf,
|
|
const unsigned char *mfile,
|
|
size_t mfile_size,
|
|
uint64_t toc_offset,
|
|
int toc_length,
|
|
unsigned expected_alignment)
|
|
{
|
|
int i;
|
|
uint32_t chunk_id;
|
|
const unsigned char *table_of_contents = mfile + toc_offset;
|
|
|
|
ALLOC_GROW(cf->chunks, toc_length, cf->chunks_alloc);
|
|
|
|
while (toc_length--) {
|
|
uint64_t chunk_offset, next_chunk_offset;
|
|
|
|
chunk_id = get_be32(table_of_contents);
|
|
chunk_offset = get_be64(table_of_contents + 4);
|
|
|
|
if (!chunk_id) {
|
|
error(_("terminating chunk id appears earlier than expected"));
|
|
return 1;
|
|
}
|
|
if (chunk_offset % expected_alignment != 0) {
|
|
error(_("chunk id %"PRIx32" not %d-byte aligned"),
|
|
chunk_id, expected_alignment);
|
|
return 1;
|
|
}
|
|
|
|
table_of_contents += CHUNK_TOC_ENTRY_SIZE;
|
|
next_chunk_offset = get_be64(table_of_contents + 4);
|
|
|
|
if (next_chunk_offset < chunk_offset ||
|
|
next_chunk_offset > mfile_size - the_hash_algo->rawsz) {
|
|
error(_("improper chunk offset(s) %"PRIx64" and %"PRIx64""),
|
|
chunk_offset, next_chunk_offset);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < cf->chunks_nr; i++) {
|
|
if (cf->chunks[i].id == chunk_id) {
|
|
error(_("duplicate chunk ID %"PRIx32" found"),
|
|
chunk_id);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
cf->chunks[cf->chunks_nr].id = chunk_id;
|
|
cf->chunks[cf->chunks_nr].start = mfile + chunk_offset;
|
|
cf->chunks[cf->chunks_nr].size = next_chunk_offset - chunk_offset;
|
|
cf->chunks_nr++;
|
|
}
|
|
|
|
chunk_id = get_be32(table_of_contents);
|
|
if (chunk_id) {
|
|
error(_("final chunk has non-zero id %"PRIx32""), chunk_id);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct pair_chunk_data {
|
|
const unsigned char **p;
|
|
size_t *size;
|
|
};
|
|
|
|
static int pair_chunk_fn(const unsigned char *chunk_start,
|
|
size_t chunk_size,
|
|
void *data)
|
|
{
|
|
struct pair_chunk_data *pcd = data;
|
|
*pcd->p = chunk_start;
|
|
*pcd->size = chunk_size;
|
|
return 0;
|
|
}
|
|
|
|
int pair_chunk(struct chunkfile *cf,
|
|
uint32_t chunk_id,
|
|
const unsigned char **p,
|
|
size_t *size)
|
|
{
|
|
struct pair_chunk_data pcd = { .p = p, .size = size };
|
|
return read_chunk(cf, chunk_id, pair_chunk_fn, &pcd);
|
|
}
|
|
|
|
int read_chunk(struct chunkfile *cf,
|
|
uint32_t chunk_id,
|
|
chunk_read_fn fn,
|
|
void *data)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < cf->chunks_nr; i++) {
|
|
if (cf->chunks[i].id == chunk_id)
|
|
return fn(cf->chunks[i].start, cf->chunks[i].size, data);
|
|
}
|
|
|
|
return CHUNK_NOT_FOUND;
|
|
}
|
|
|
|
uint8_t oid_version(const struct git_hash_algo *algop)
|
|
{
|
|
switch (hash_algo_by_ptr(algop)) {
|
|
case GIT_HASH_SHA1:
|
|
return 1;
|
|
case GIT_HASH_SHA256:
|
|
return 2;
|
|
default:
|
|
die(_("invalid hash version"));
|
|
}
|
|
}
|