mirror of
https://github.com/git/git.git
synced 2026-08-09 09:34:14 +00:00
Currently, send_info() only checks for existence when the attribute 'size' is also requested. Requesting a bare OID, without attributes only echoes back the OID. Extract the existence check to be done regardless of the number of attributes requested. While at it, introduce a wrapper called get_object_info() similar to odb_read_object_info() that returns OBJ_BAD on fail and adds OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK flags. OBJECT_INFO_SKIP_FETCH_OBJECT is so a server with a partial clone doesn't trigger fetching objects when it gets an object-info request with an OID that is not available locally. A server should only report what it has locally. Tighten the condition used to determine whether an object is recognized. get_object_info() returns OBJ_BAD for unknown objects, but OBJ_NONE (0) can also mean "not found". Change the check from '< 0' to '<= OBJ_NONE' to cover both as unrecognized. With this patch, a bare OID has two possible responses: 1. Recognized OID: the server answers with "<OID>" 2. Unrecognized OID: the server answers with "<OID> SP" Update the object-info section in 'gitprotocol-v2.adoc': - Require full obj-oid explicitly. - Fix parentheses. - Define obj-size explicitly. - Make obj-size optional in obj-info and document the behavior for unrecognized object IDs. - Describe the attr header as zero or more pkt-lines, one per attribute, matching what the server implements. A request with no attributes gets no header. Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
149 lines
3.5 KiB
C
149 lines
3.5 KiB
C
#include "git-compat-util.h"
|
|
#include "protocol-caps.h"
|
|
#include "gettext.h"
|
|
#include "hex.h"
|
|
#include "pkt-line.h"
|
|
#include "hash.h"
|
|
#include "object.h"
|
|
#include "odb.h"
|
|
#include "repository.h"
|
|
#include "string-list.h"
|
|
#include "strbuf.h"
|
|
|
|
struct requested_info {
|
|
unsigned size : 1;
|
|
};
|
|
|
|
/*
|
|
* Parses oids from the given line and collects them in the given
|
|
* oid_str_list. Returns 1 if parsing was successful and 0 otherwise.
|
|
*/
|
|
static int parse_oid(const char *line, struct string_list *oid_str_list)
|
|
{
|
|
const char *arg;
|
|
|
|
if (!skip_prefix(line, "oid ", &arg))
|
|
return 0;
|
|
|
|
string_list_append(oid_str_list, arg);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* odb_read_object_info_extended() wrapper. Similar to odb_read_object_info()
|
|
* but uses the flags:
|
|
*
|
|
* - OBJECT_INFO_SKIP_FETCH_OBJECT so a server won't fetch an object when a
|
|
* object-info request asks for an OID that it doesn't have.
|
|
*
|
|
* - OBJECT_INFO_QUICK to avoid re-scanning packs when the object is not found.
|
|
*/
|
|
static enum object_type get_object_info(struct object_database *odb,
|
|
const struct object_id *oid,
|
|
size_t *sizep)
|
|
{
|
|
enum object_type type;
|
|
struct object_info oi = OBJECT_INFO_INIT;
|
|
|
|
oi.typep = &type;
|
|
oi.sizep = sizep;
|
|
if (odb_read_object_info_extended(odb, oid, &oi,
|
|
OBJECT_INFO_LOOKUP_REPLACE |
|
|
OBJECT_INFO_SKIP_FETCH_OBJECT |
|
|
OBJECT_INFO_QUICK) < 0)
|
|
return OBJ_BAD;
|
|
return type;
|
|
}
|
|
|
|
/*
|
|
* Validates and send requested info back to the client. Any errors detected
|
|
* are returned as they are detected.
|
|
*/
|
|
static void send_info(struct repository *r, struct packet_writer *writer,
|
|
struct string_list *oid_str_list,
|
|
struct requested_info *info)
|
|
{
|
|
struct string_list_item *item;
|
|
struct strbuf send_buffer = STRBUF_INIT;
|
|
|
|
if (!oid_str_list->nr)
|
|
return;
|
|
|
|
if (info->size)
|
|
packet_writer_write(writer, "size");
|
|
|
|
for_each_string_list_item (item, oid_str_list) {
|
|
const char *oid_str = item->string;
|
|
struct object_id oid;
|
|
size_t object_size;
|
|
|
|
if (get_oid_hex_algop(oid_str, &oid, r->hash_algo) < 0) {
|
|
packet_writer_error(
|
|
writer,
|
|
"object-info: protocol error, expected to get oid, not '%s'",
|
|
oid_str);
|
|
continue;
|
|
}
|
|
|
|
strbuf_addstr(&send_buffer, oid_str);
|
|
|
|
/*
|
|
* Check the existence of the object first.
|
|
* If an object is not recognized by the server append SP to
|
|
* the response.
|
|
*/
|
|
if (get_object_info(r->objects, &oid, &object_size) <= OBJ_NONE) {
|
|
strbuf_addstr(&send_buffer, " ");
|
|
goto write;
|
|
}
|
|
|
|
if (info->size) {
|
|
strbuf_addf(&send_buffer, " %"PRIuMAX,
|
|
(uintmax_t)object_size);
|
|
}
|
|
|
|
write:
|
|
packet_writer_write(writer, "%s", send_buffer.buf);
|
|
strbuf_reset(&send_buffer);
|
|
}
|
|
strbuf_release(&send_buffer);
|
|
}
|
|
|
|
int cap_object_info(struct repository *r, struct packet_reader *request)
|
|
{
|
|
struct requested_info info = { 0 };
|
|
struct packet_writer writer;
|
|
struct string_list oid_str_list = STRING_LIST_INIT_DUP;
|
|
|
|
packet_writer_init(&writer, 1);
|
|
|
|
while (packet_reader_read(request) == PACKET_READ_NORMAL) {
|
|
if (!strcmp("size", request->line)) {
|
|
info.size = 1;
|
|
continue;
|
|
}
|
|
|
|
if (parse_oid(request->line, &oid_str_list))
|
|
continue;
|
|
|
|
packet_writer_error(&writer,
|
|
"object-info: unexpected line: '%s'",
|
|
request->line);
|
|
}
|
|
|
|
if (request->status != PACKET_READ_FLUSH) {
|
|
packet_writer_error(
|
|
&writer, "object-info: expected flush after arguments");
|
|
die(_("object-info: expected flush after arguments"));
|
|
}
|
|
|
|
send_info(r, &writer, &oid_str_list, &info);
|
|
|
|
string_list_clear(&oid_str_list, 1);
|
|
|
|
packet_flush(1);
|
|
|
|
return 0;
|
|
}
|