Files
git/object-file.h
Patrick Steinhardt 810f8b2033 object-file: move logic to write loose objects
The logic to write loose objects is split up across "object-file.c" and
"odb/source-loose.c". This split is somewhat weird, but it is the result
of two things:

  - `force_object_loose()` used to reach into internals of how exactly
    we write objects.

  - The logic of writing objects is intertwined with potentially
    starting a transaction.

We have refactored `force_object_loose()` over preceding commits to work
via generic interfaces now, so this reason doesn't exist anymore. But
the second reason still does, as our management of "files" transactions
and their ad-hoc creation is still very messy. This area definitely
requires further work, and that work is indeed ongoing.

That being said, we can already move the writing logic into the "loose"
backend rather easily. All we have to do is to expose two functions that
relate to the transactions.

Expose these two functions and move the writing logic into the "loose"
backend accordingly so that it becomes more self-contained. Note that
this requires us to drop a reference to `the_repository` in favor of
using the source's repository in `start_loose_object_common()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-18 19:03:49 -07:00

185 lines
5.8 KiB
C

#ifndef OBJECT_FILE_H
#define OBJECT_FILE_H
#include "git-zlib.h"
#include "object.h"
#include "odb.h"
#include "odb/source-loose.h"
#include "odb/transaction.h"
/* The maximum size for an object header. */
#define MAX_HEADER_LEN 32
struct index_state;
enum {
INDEX_WRITE_OBJECT = (1 << 0),
INDEX_FORMAT_CHECK = (1 << 1),
INDEX_RENORMALIZE = (1 << 2),
};
int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
struct object_info;
struct odb_source;
/*
* Put in `buf` the name of the file in the local object database that
* would be used to store a loose object with the specified oid.
*/
const char *odb_loose_path(struct odb_source_loose *source,
struct strbuf *buf,
const struct object_id *oid);
/*
* Iterate over the files in the loose-object parts of the object
* directory "path", triggering the following callbacks:
*
* - loose_object is called for each loose object we find.
*
* - loose_cruft is called for any files that do not appear to be
* loose objects. Note that we only look in the loose object
* directories "objects/[0-9a-f]{2}/", so we will not report
* "objects/foobar" as cruft.
*
* - loose_subdir is called for each top-level hashed subdirectory
* of the object directory (e.g., "$OBJDIR/f0"). It is called
* after the objects in the directory are processed.
*
* Any callback that is NULL will be ignored. Callbacks returning non-zero
* will end the iteration.
*
* In the "buf" variant, "path" is a strbuf which will also be used as a
* scratch buffer, but restored to its original contents before
* the function returns.
*/
typedef int each_loose_object_fn(const struct object_id *oid,
const char *path,
void *data);
typedef int each_loose_cruft_fn(const char *basename,
const char *path,
void *data);
typedef int each_loose_subdir_fn(unsigned int nr,
const char *path,
void *data);
int for_each_loose_file_in_source(struct odb_source *source,
each_loose_object_fn obj_cb,
each_loose_cruft_fn cruft_cb,
each_loose_subdir_fn subdir_cb,
void *data);
int for_each_file_in_obj_subdir(unsigned int subdir_nr,
struct strbuf *path,
const struct git_hash_algo *algop,
each_loose_object_fn obj_cb,
each_loose_cruft_fn cruft_cb,
each_loose_subdir_fn subdir_cb,
void *data);
/**
* format_object_header() is a thin wrapper around s xsnprintf() that
* writes the initial "<type> <obj-len>" part of the loose object
* header. It returns the size that snprintf() returns + 1.
*/
int format_object_header(char *str, size_t size, enum object_type type,
size_t objsize);
/**
* With in-core object data in "buf", rehash it to make sure the
* object name actually matches "oid" to detect object corruption.
*
* A negative value indicates an error, usually that the OID is not
* what we expected, but it might also indicate another error.
*/
int check_object_signature(struct repository *r, const struct object_id *oid,
void *map, unsigned long size,
enum object_type type);
/**
* A streaming version of check_object_signature().
* Try reading the object named with "oid" using
* the streaming interface and rehash it to do the same.
*/
int stream_object_signature(struct repository *r,
struct odb_read_stream *stream,
const struct object_id *oid);
enum finalize_object_file_flags {
FOF_SKIP_COLLISION_CHECK = 1,
};
int finalize_object_file(struct repository *repo,
const char *tmpfile, const char *filename);
int finalize_object_file_flags(struct repository *repo,
const char *tmpfile, const char *filename,
enum finalize_object_file_flags flags);
void hash_object_file(const struct git_hash_algo *algo, const void *buf,
size_t len, enum object_type type,
struct object_id *oid);
/* Helper to check and "touch" a file */
int check_and_freshen_file(const char *fn, int freshen,
const time_t *mtime);
/*
* Open the loose object at path, check its hash, and return the contents,
* use the "oi" argument to assert things about the object, or e.g. populate its
* type, and size. If the object is a blob, then "contents" may return NULL,
* to allow streaming of large blobs.
*
* Returns 0 on success, negative on error (details may be written to stderr).
*/
int read_loose_object(struct repository *repo,
const char *path,
const struct object_id *expected_oid,
struct object_id *real_oid,
void **contents,
struct object_info *oi);
enum unpack_loose_header_result {
ULHR_OK,
ULHR_BAD,
ULHR_TOO_LONG,
};
/**
* unpack_loose_header() initializes the data stream needed to unpack
* a loose object header.
*
* Returns:
*
* - ULHR_OK on success
* - ULHR_BAD on error
* - ULHR_TOO_LONG if the header was too long
*
* It will only parse up to MAX_HEADER_LEN bytes.
*/
enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
unsigned char *map,
unsigned long mapsize,
void *buffer,
unsigned long bufsiz);
void *unpack_loose_rest(git_zstream *stream,
void *buffer, unsigned long size,
const struct object_id *oid);
int parse_loose_header(const char *hdr, struct object_info *oi);
struct odb_transaction;
/*
* Tell the object database to optimize for adding
* multiple objects. odb_transaction_files_commit must be called
* to make new objects visible.
*/
int odb_transaction_files_begin(struct odb_source *source,
struct odb_transaction **out,
enum odb_transaction_flags flags);
int odb_transaction_files_prepare(struct odb_transaction *base);
void odb_transaction_files_fsync(struct odb_transaction *base,
int fd, const char *filename);
#endif /* OBJECT_FILE_H */