1
+#include "git-compat-util.h"
2
+#include "gettext.h"
3
+#include "hex.h"
4
+#include "pkt-line.h"
5
+#include "connect.h"
6
+#include "oid-array.h"
7
+#include "odb.h"
8
+#include "fetch-object-info.h"
9
+#include "string-list.h"
10
+
11
+/* Sends object-info command and its arguments into the request buffer. */
12
+static void send_object_info_request(const int fd_out, struct object_info_args *args)
13
+{
14
+ struct strbuf req_buf = STRBUF_INIT;
15
+
16
+ write_command_and_capabilities(&req_buf, "object-info", args->server_options);
17
+
18
+ if (unsorted_string_list_has_string(args->object_info_options, "size"))
19
+ packet_buf_write(&req_buf, "size");
20
+ else
21
+ BUG("only size should be in object_info_options");
22
+
23
+ if (args->oids)
24
+ for (size_t i = 0; i < args->oids->nr; i++)
25
+ packet_buf_write(&req_buf, "oid %s", oid_to_hex(&args->oids->oid[i]));
26
+
27
+ packet_buf_flush(&req_buf);
28
+ if (write_in_full(fd_out, req_buf.buf, req_buf.len) < 0)
29
+ die_errno(_("unable to write request to remote"));
30
+
31
+ strbuf_release(&req_buf);
32
+}
33
+
34
+static size_t parse_object_size(const char *s, size_t *res)
35
+{
36
+ uintmax_t uim;
37
+
38
+ if (!s[0] || s[strspn(s, "0123456789")])
39
+ return -1;
40
+ errno = 0;
41
+ uim = strtoumax(s, NULL, 10);
42
+ if (errno || uim > SIZE_MAX)
43
+ return -1;
44
+ *res = uim;
45
+ return 0;
46
+}
47
+
48
+int fetch_object_info(const enum protocol_version version, struct object_info_args *args,
49
+ struct packet_reader *reader, struct object_info *object_info_data,
50
+ const int stateless_rpc, const int fd_out)
51
+{
52
+ int size_index = -1;
53
+
54
+ switch (version) {
55
+ case protocol_v2:
56
+ if (!server_supports_v2("object-info"))
57
+ die(_("object-info capability is not enabled on the server"));
58
+ send_object_info_request(fd_out, args);
59
+ break;
60
+ case protocol_v1:
61
+ case protocol_v0:
62
+ die(_("unsupported protocol version. expected v2"));
63
+ case protocol_unknown_version:
64
+ BUG("unknown protocol version");
65
+ }
66
+
67
+ for (size_t i = 0; i < args->object_info_options->nr; i++) {
68
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL) {
69
+ check_stateless_delimiter(stateless_rpc, reader,
70
+ "stateless delimiter expected");
71
+ return -1;
72
+ }
73
+
74
+ if (!string_list_has_string(args->object_info_options, reader->line))
75
+ return -1;
76
+
77
+ if (!strcmp(reader->line, "size")) {
78
+ size_index = i;
79
+ for (size_t j = 0; j < args->oids->nr; j++)
80
+ object_info_data[j].sizep = xcalloc(1, sizeof(*object_info_data[j].sizep));
81
+ } else {
82
+ BUG("only size is supported");
83
+ }
84
+ }
85
+
86
+ for (size_t i = 0; packet_reader_read(reader) == PACKET_READ_NORMAL && i < args->oids->nr; i++) {
87
+ struct string_list object_info_values = STRING_LIST_INIT_DUP;
88
+
89
+ string_list_split(&object_info_values, reader->line, " ", -1);
90
+ if (size_index >= 0) {
91
+ if (!strcmp(object_info_values.items[1 + size_index].string, "")) {
92
+ FREE_AND_NULL(object_info_data[i].sizep);
93
+ string_list_clear(&object_info_values, 0);
94
+ continue;
95
+ }
96
+
97
+ if (parse_object_size(object_info_values.items[1 + size_index].string,
98
+ object_info_data[i].sizep))
99
+ die("object-info: ref %s has invalid size %s",
100
+ object_info_values.items[0].string,
101
+ object_info_values.items[1 + size_index].string);
102
+ }
103
+
104
+ string_list_clear(&object_info_values, 0);
105
+ }
106
+ check_stateless_delimiter(stateless_rpc, reader, "stateless delimiter expected");
107
+
108
+ return 0;
109
+}