mirror of
https://github.com/git-for-windows/git.git
synced 2026-04-10 08:22:54 -05:00
Stub out remaining functions that we either don't need or that are basically no-ops. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
379 lines
10 KiB
C
379 lines
10 KiB
C
#include "git-compat-util.h"
|
|
#include "object-file.h"
|
|
#include "odb.h"
|
|
#include "odb/source-inmemory.h"
|
|
#include "odb/streaming.h"
|
|
#include "oidtree.h"
|
|
#include "repository.h"
|
|
|
|
struct inmemory_object {
|
|
enum object_type type;
|
|
const void *buf;
|
|
unsigned long size;
|
|
};
|
|
|
|
static const struct inmemory_object *find_cached_object(struct odb_source_inmemory *source,
|
|
const struct object_id *oid)
|
|
{
|
|
static const struct inmemory_object empty_tree = {
|
|
.type = OBJ_TREE,
|
|
.buf = "",
|
|
};
|
|
const struct inmemory_object *object;
|
|
|
|
if (source->objects) {
|
|
object = oidtree_get(source->objects, oid);
|
|
if (object)
|
|
return object;
|
|
}
|
|
|
|
if (oid->algo && oideq(oid, hash_algos[oid->algo].empty_tree))
|
|
return &empty_tree;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void populate_object_info(struct odb_source_inmemory *source,
|
|
struct object_info *oi,
|
|
const struct inmemory_object *object)
|
|
{
|
|
if (!oi)
|
|
return;
|
|
|
|
if (oi->typep)
|
|
*(oi->typep) = object->type;
|
|
if (oi->sizep)
|
|
*(oi->sizep) = object->size;
|
|
if (oi->disk_sizep)
|
|
*(oi->disk_sizep) = 0;
|
|
if (oi->delta_base_oid)
|
|
oidclr(oi->delta_base_oid, source->base.odb->repo->hash_algo);
|
|
if (oi->contentp)
|
|
*oi->contentp = xmemdupz(object->buf, object->size);
|
|
if (oi->mtimep)
|
|
*oi->mtimep = 0;
|
|
oi->whence = OI_CACHED;
|
|
}
|
|
|
|
static int odb_source_inmemory_read_object_info(struct odb_source *source,
|
|
const struct object_id *oid,
|
|
struct object_info *oi,
|
|
enum object_info_flags flags UNUSED)
|
|
{
|
|
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
|
|
const struct inmemory_object *object;
|
|
|
|
object = find_cached_object(inmemory, oid);
|
|
if (!object)
|
|
return -1;
|
|
|
|
populate_object_info(inmemory, oi, object);
|
|
return 0;
|
|
}
|
|
|
|
struct odb_read_stream_inmemory {
|
|
struct odb_read_stream base;
|
|
const void *buf;
|
|
size_t offset;
|
|
};
|
|
|
|
static ssize_t odb_read_stream_inmemory_read(struct odb_read_stream *stream,
|
|
char *buf, size_t buf_len)
|
|
{
|
|
struct odb_read_stream_inmemory *inmemory =
|
|
container_of(stream, struct odb_read_stream_inmemory, base);
|
|
size_t bytes = buf_len;
|
|
|
|
if (buf_len > inmemory->base.size - inmemory->offset)
|
|
bytes = inmemory->base.size - inmemory->offset;
|
|
memcpy(buf, inmemory->buf, bytes);
|
|
|
|
return bytes;
|
|
}
|
|
|
|
static int odb_read_stream_inmemory_close(struct odb_read_stream *stream UNUSED)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int odb_source_inmemory_read_object_stream(struct odb_read_stream **out,
|
|
struct odb_source *source,
|
|
const struct object_id *oid)
|
|
{
|
|
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
|
|
struct odb_read_stream_inmemory *stream;
|
|
const struct inmemory_object *object;
|
|
|
|
object = find_cached_object(inmemory, oid);
|
|
if (!object)
|
|
return -1;
|
|
|
|
CALLOC_ARRAY(stream, 1);
|
|
stream->base.read = odb_read_stream_inmemory_read;
|
|
stream->base.close = odb_read_stream_inmemory_close;
|
|
stream->base.size = object->size;
|
|
stream->base.type = object->type;
|
|
stream->buf = object->buf;
|
|
|
|
*out = &stream->base;
|
|
return 0;
|
|
}
|
|
|
|
struct odb_source_inmemory_for_each_object_data {
|
|
struct odb_source_inmemory *inmemory;
|
|
const struct object_info *request;
|
|
odb_for_each_object_cb cb;
|
|
void *cb_data;
|
|
};
|
|
|
|
static int odb_source_inmemory_for_each_object_cb(const struct object_id *oid,
|
|
void *node_data, void *cb_data)
|
|
{
|
|
struct odb_source_inmemory_for_each_object_data *data = cb_data;
|
|
struct inmemory_object *object = node_data;
|
|
|
|
if (data->request) {
|
|
struct object_info oi = *data->request;
|
|
populate_object_info(data->inmemory, &oi, object);
|
|
return data->cb(oid, &oi, data->cb_data);
|
|
} else {
|
|
return data->cb(oid, NULL, data->cb_data);
|
|
}
|
|
}
|
|
|
|
static int odb_source_inmemory_for_each_object(struct odb_source *source,
|
|
const struct object_info *request,
|
|
odb_for_each_object_cb cb,
|
|
void *cb_data,
|
|
const struct odb_for_each_object_options *opts)
|
|
{
|
|
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
|
|
struct odb_source_inmemory_for_each_object_data payload = {
|
|
.inmemory = inmemory,
|
|
.request = request,
|
|
.cb = cb,
|
|
.cb_data = cb_data,
|
|
};
|
|
struct object_id null_oid = { 0 };
|
|
|
|
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) ||
|
|
(opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local))
|
|
return 0;
|
|
|
|
return oidtree_each(inmemory->objects,
|
|
opts->prefix ? opts->prefix : &null_oid, opts->prefix_hex_len,
|
|
odb_source_inmemory_for_each_object_cb, &payload);
|
|
}
|
|
|
|
struct find_abbrev_len_data {
|
|
const struct object_id *oid;
|
|
unsigned len;
|
|
};
|
|
|
|
static int find_abbrev_len_cb(const struct object_id *oid,
|
|
struct object_info *oi UNUSED,
|
|
void *cb_data)
|
|
{
|
|
struct find_abbrev_len_data *data = cb_data;
|
|
unsigned len = oid_common_prefix_hexlen(oid, data->oid);
|
|
if (len != hash_algos[oid->algo].hexsz && len >= data->len)
|
|
data->len = len + 1;
|
|
return 0;
|
|
}
|
|
|
|
static int odb_source_inmemory_find_abbrev_len(struct odb_source *source,
|
|
const struct object_id *oid,
|
|
unsigned min_len,
|
|
unsigned *out)
|
|
{
|
|
struct odb_for_each_object_options opts = {
|
|
.prefix = oid,
|
|
.prefix_hex_len = min_len,
|
|
};
|
|
struct find_abbrev_len_data data = {
|
|
.oid = oid,
|
|
.len = min_len,
|
|
};
|
|
int ret;
|
|
|
|
ret = odb_source_inmemory_for_each_object(source, NULL, find_abbrev_len_cb,
|
|
&data, &opts);
|
|
*out = data.len;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int count_objects_cb(const struct object_id *oid UNUSED,
|
|
struct object_info *oi UNUSED,
|
|
void *cb_data)
|
|
{
|
|
unsigned long *counter = cb_data;
|
|
(*counter)++;
|
|
return 0;
|
|
}
|
|
|
|
static int odb_source_inmemory_count_objects(struct odb_source *source,
|
|
enum odb_count_objects_flags flags UNUSED,
|
|
unsigned long *out)
|
|
{
|
|
struct odb_for_each_object_options opts = { 0 };
|
|
*out = 0;
|
|
return odb_source_inmemory_for_each_object(source, NULL, count_objects_cb,
|
|
out, &opts);
|
|
}
|
|
|
|
static int odb_source_inmemory_write_object(struct odb_source *source,
|
|
const void *buf, unsigned long len,
|
|
enum object_type type,
|
|
struct object_id *oid,
|
|
struct object_id *compat_oid UNUSED,
|
|
enum odb_write_object_flags flags UNUSED)
|
|
{
|
|
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
|
|
struct inmemory_object *object;
|
|
|
|
hash_object_file(source->odb->repo->hash_algo, buf, len, type, oid);
|
|
|
|
if (!inmemory->objects) {
|
|
CALLOC_ARRAY(inmemory->objects, 1);
|
|
oidtree_init(inmemory->objects);
|
|
} else if (oidtree_contains(inmemory->objects, oid)) {
|
|
return 0;
|
|
}
|
|
|
|
CALLOC_ARRAY(object, 1);
|
|
object->size = len;
|
|
object->type = type;
|
|
object->buf = xmemdupz(buf, len);
|
|
|
|
oidtree_insert(inmemory->objects, oid, object);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int odb_source_inmemory_write_object_stream(struct odb_source *source,
|
|
struct odb_write_stream *stream,
|
|
size_t len,
|
|
struct object_id *oid)
|
|
{
|
|
char buf[16384];
|
|
size_t total_read = 0;
|
|
char *data;
|
|
int ret;
|
|
|
|
CALLOC_ARRAY(data, len);
|
|
while (!stream->is_finished) {
|
|
ssize_t bytes_read;
|
|
|
|
bytes_read = odb_write_stream_read(stream, buf, sizeof(buf));
|
|
if (total_read + bytes_read > len) {
|
|
ret = error("object stream yielded more bytes than expected");
|
|
goto out;
|
|
}
|
|
|
|
memcpy(data, buf, bytes_read);
|
|
total_read += bytes_read;
|
|
}
|
|
|
|
if (total_read != len) {
|
|
ret = error("object stream yielded less bytes than expected");
|
|
goto out;
|
|
}
|
|
|
|
ret = odb_source_inmemory_write_object(source, data, len, OBJ_BLOB, oid,
|
|
NULL, 0);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
out:
|
|
free(data);
|
|
return ret;
|
|
}
|
|
|
|
static int odb_source_inmemory_freshen_object(struct odb_source *source,
|
|
const struct object_id *oid)
|
|
{
|
|
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
|
|
if (find_cached_object(inmemory, oid))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int odb_source_inmemory_begin_transaction(struct odb_source *source UNUSED,
|
|
struct odb_transaction **out UNUSED)
|
|
{
|
|
return error("inmemory source does not support transactions");
|
|
}
|
|
|
|
static int odb_source_inmemory_read_alternates(struct odb_source *source UNUSED,
|
|
struct strvec *out UNUSED)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int odb_source_inmemory_write_alternate(struct odb_source *source UNUSED,
|
|
const char *alternate UNUSED)
|
|
{
|
|
return error("inmemory source does not support alternates");
|
|
}
|
|
|
|
static void odb_source_inmemory_close(struct odb_source *source UNUSED)
|
|
{
|
|
}
|
|
|
|
static void odb_source_inmemory_reprepare(struct odb_source *source UNUSED)
|
|
{
|
|
}
|
|
|
|
static int inmemory_object_free(const struct object_id *oid UNUSED,
|
|
void *node_data,
|
|
void *cb_data UNUSED)
|
|
{
|
|
struct inmemory_object *object = node_data;
|
|
free((void *) object->buf);
|
|
free(object);
|
|
return 0;
|
|
}
|
|
|
|
static void odb_source_inmemory_free(struct odb_source *source)
|
|
{
|
|
struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
|
|
|
|
if (inmemory->objects) {
|
|
struct object_id null_oid = { 0 };
|
|
|
|
oidtree_each(inmemory->objects, &null_oid, 0,
|
|
inmemory_object_free, NULL);
|
|
oidtree_clear(inmemory->objects);
|
|
free(inmemory->objects);
|
|
}
|
|
|
|
free(inmemory->base.path);
|
|
free(inmemory);
|
|
}
|
|
|
|
struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)
|
|
{
|
|
struct odb_source_inmemory *source;
|
|
|
|
CALLOC_ARRAY(source, 1);
|
|
odb_source_init(&source->base, odb, ODB_SOURCE_INMEMORY, "source", false);
|
|
|
|
source->base.free = odb_source_inmemory_free;
|
|
source->base.close = odb_source_inmemory_close;
|
|
source->base.reprepare = odb_source_inmemory_reprepare;
|
|
source->base.read_object_info = odb_source_inmemory_read_object_info;
|
|
source->base.read_object_stream = odb_source_inmemory_read_object_stream;
|
|
source->base.for_each_object = odb_source_inmemory_for_each_object;
|
|
source->base.find_abbrev_len = odb_source_inmemory_find_abbrev_len;
|
|
source->base.count_objects = odb_source_inmemory_count_objects;
|
|
source->base.write_object = odb_source_inmemory_write_object;
|
|
source->base.write_object_stream = odb_source_inmemory_write_object_stream;
|
|
source->base.freshen_object = odb_source_inmemory_freshen_object;
|
|
source->base.begin_transaction = odb_source_inmemory_begin_transaction;
|
|
source->base.read_alternates = odb_source_inmemory_read_alternates;
|
|
source->base.write_alternate = odb_source_inmemory_write_alternate;
|
|
|
|
return source;
|
|
}
|