Files
git/lib/fetch-object-info.c
Junio C Hamano faff5b2eb1 Merge branch 'ps/libgit-in-subdir' into seen
The source files for libgit.a have been moved into a new "lib/"
directory to clean up the top-level directory and clearly separate
library code.

* ps/libgit-in-subdir:
  Move libgit.a sources into separate "lib/" directory
  t/helper: prepare "test-example-tap.c" for introduction of "lib/"
2026-06-25 19:51:57 -07:00

111 lines
3.6 KiB
C

#include "git-compat-util.h"
#include "gettext.h"
#include "hex.h"
#include "pkt-line.h"
#include "connect.h"
#include "oid-array.h"
#include "odb.h"
#include "fetch-object-info.h"
#include "string-list.h"
/* Sends git-cat-file object-info command and its arguments into the request buffer. */
static void send_object_info_request(const int fd_out, struct object_info_args *args)
{
struct strbuf req_buf = STRBUF_INIT;
write_command_and_capabilities(&req_buf, "object-info", args->server_options);
if (unsorted_string_list_has_string(args->object_info_options, "size"))
packet_buf_write(&req_buf, "size");
if (args->oids)
for (size_t i = 0; i < args->oids->nr; i++)
packet_buf_write(&req_buf, "oid %s", oid_to_hex(&args->oids->oid[i]));
packet_buf_flush(&req_buf);
if (write_in_full(fd_out, req_buf.buf, req_buf.len) < 0)
die_errno(_("unable to write request to remote"));
strbuf_release(&req_buf);
}
int fetch_object_info(const enum protocol_version version, struct object_info_args *args,
struct packet_reader *reader, struct object_info *object_info_data,
const int stateless_rpc, const int fd_out)
{
int size_index = -1;
switch (version) {
case protocol_v2:
if (!server_supports_v2("object-info"))
die(_("object-info capability is not enabled on the server"));
/*
* When removing an element from the list it gets swapped by the
* last element, iterate backwards to prevent elements skipping
* evaluation.
*
* object_info_options->nr can be safely casted without overflow
* beacuse the number of options is a small known number (the
* supported placeholders which currently are size and type).
*/
for (int i = (int)args->object_info_options->nr - 1; i >= 0; i--)
if (!server_supports_feature("object-info",
args->object_info_options->items[i].string, 0))
unsorted_string_list_delete_item(args->object_info_options, i, 0);
/*
* If no options are left after the filtering, avoid unnecessary
* request to the server.
*/
if (!args->object_info_options->nr)
return 0;
send_object_info_request(fd_out, args);
break;
case protocol_v1:
case protocol_v0:
die(_("unsupported protocol version. expected v2"));
case protocol_unknown_version:
BUG("unknown protocol version");
}
for (size_t i = 0; i < args->object_info_options->nr; i++) {
if (packet_reader_read(reader) != PACKET_READ_NORMAL) {
check_stateless_delimiter(stateless_rpc, reader,
"stateless delimiter expected");
return -1;
}
if (!string_list_has_string(args->object_info_options, reader->line))
return -1;
if (!strcmp(reader->line, "size")) {
size_index = i;
for (size_t j = 0; j < args->oids->nr; j++)
object_info_data[j].sizep = xcalloc(1, sizeof(*object_info_data[j].sizep));
}
}
for (size_t i = 0; packet_reader_read(reader) == PACKET_READ_NORMAL && i < args->oids->nr; i++) {
struct string_list object_info_values = STRING_LIST_INIT_DUP;
string_list_split(&object_info_values, reader->line, " ", -1);
if (0 <= size_index) {
if (!strcmp(object_info_values.items[1 + size_index].string, "")) {
FREE_AND_NULL(object_info_data[i].sizep);
string_list_clear(&object_info_values, 0);
continue;
}
if (strtoul_szt(object_info_values.items[1 + size_index].string,
10, object_info_data[i].sizep))
die("object-info: ref %s has invalid size %s",
object_info_values.items[0].string,
object_info_values.items[1 + size_index].string);
}
string_list_clear(&object_info_values, 0);
}
check_stateless_delimiter(stateless_rpc, reader, "stateless delimiter expected");
return 0;
}