12
static void send_object_info_request(const int fd_out,
13
const struct string_list *server_options,
14
struct oid_array *oids,
15
- struct string_list *object_info_options)
15
+ unsigned ask_size,
16
+ unsigned ask_type)
17
{
18
struct strbuf req_buf = STRBUF_INIT;
19
20
write_command_and_capabilities(&req_buf, "object-info", server_options);
21
21
- if (unsorted_string_list_has_string(object_info_options, "size"))
22
+ if (ask_size)
23
packet_buf_write(&req_buf, "size");
23
- else if (object_info_options->nr)
24
- BUG("only size should be in object_info_options");
24
+
25
+ if (ask_type)
26
+ packet_buf_write(&req_buf, "type");
27
28
if (oids)
29
for (size_t i = 0; i < oids->nr; i++)
54
int fetch_object_info(const enum protocol_version version,
55
const struct string_list *server_options,
56
struct oid_array *oids,
55
- struct string_list *object_info_options,
57
struct packet_reader *reader,
57
- struct object_info *object_info_data,
58
- const int stateless_rpc, const int fd_out)
58
+ struct fetch_object_info_results *results,
59
+ const int stateless_rpc,
60
+ const int fd_out)
61
{
60
- size_t i;
62
+ unsigned ask_size = 0;
63
+ unsigned ask_type = 0;
64
int size_index = -1;
65
+ size_t wanted;
66
+ size_t i;
67
+
68
+ results->nr = oids->nr;
69
+ CALLOC_ARRAY(results->unrecognized, results->nr);
70
71
switch (version) {
72
case protocol_v2:
73
if (!server_supports_v2("object-info"))
74
die(_("object-info capability is not enabled on the server"));
67
- /*
68
- * When removing an element from the list it gets swapped by the
69
- * last element, iterate backwards to prevent elements skipping
70
- * evaluation.
71
- *
72
- * object_info_options->nr can be safely casted without overflow
73
- * because the number of options is a small known number (the
74
- * supported placeholders which currently are size and type).
75
- */
76
- for (int i = (int)object_info_options->nr - 1; i >= 0; i--)
77
- if (!server_supports_feature("object-info",
78
- object_info_options->items[i].string, 0))
79
- unsorted_string_list_delete_item(object_info_options, i, 0);
75
+
76
+ if (results->wants_size &&
77
+ server_supports_feature("object-info", "size", 0))
78
+ ask_size = 1;
79
+
80
+ if (results->wants_type &&
81
+ server_supports_feature("object-info", "type", 0))
82
+ ask_type = 1;
83
84
/*
85
* Even if no options are left, we still send the oid so we get
86
* at least an existence check.
87
*/
85
- send_object_info_request(fd_out, server_options, oids,
86
- object_info_options);
88
+ send_object_info_request(fd_out, server_options, oids, ask_size,
89
+ ask_type);
90
break;
91
case protocol_v1:
92
case protocol_v0:
94
case protocol_unknown_version:
95
BUG("unknown protocol version");
96
}
97
+ wanted = ask_size + ask_type;
98
95
- for (i = 0; i < object_info_options->nr; i++) {
99
+ for (i = 0; i < wanted; i++) {
100
if (packet_reader_read(reader) != PACKET_READ_NORMAL) {
101
check_stateless_delimiter(stateless_rpc, reader,
102
"stateless delimiter expected");
103
return -1;
104
}
105
102
- if (!unsorted_string_list_has_string(object_info_options, reader->line))
103
- return -1;
104
-
106
if (!strcmp(reader->line, "size")) {
106
- /*
107
- * i is the number of supported options which currently
108
- * is only size. No risk of overflow.
109
- */
107
+ if (!ask_size)
108
+ die(_("object-info: unrequested 'size' attribute"));
109
+ if (results->sizes)
110
+ die(_("object-info: duplicate 'size' attribute"));
111
size_index = (int)i;
111
- for (size_t j = 0; j < oids->nr; j++)
112
- object_info_data[j].sizep =
113
- xcalloc(1, sizeof(*object_info_data[j].sizep));
112
+ CALLOC_ARRAY(results->sizes, results->nr);
113
} else {
114
BUG("only size is supported");
115
}
136
*/
137
if (object_info_values.nr >= 2 &&
138
!strcmp(object_info_values.items[1].string, "")) {
140
- object_info_data[i].unrecognized = 1;
139
+ results->unrecognized[i] = 1;
140
string_list_clear(&object_info_values, 0);
141
continue;
142
}
143
144
/*
146
- * Because we filter the options to be only the supported by
147
- * the server we expect the server to answer with the same
148
- * number of attributes requested.
145
+ * Because we only ask for attributes the server said it
146
+ * supports, we expect the answer to have one value per
147
+ * requested attribute, plus the OID.
148
*/
150
- if (object_info_options->nr + 1 != object_info_values.nr)
149
+ if (wanted + 1 != object_info_values.nr)
150
die("object-info: unexpected number of attributes: %s",
151
reader->line);
152
154
- if (size_index >= 0 &&
153
+ if (results->sizes &&
154
parse_object_size(object_info_values.items[size_index + 1].string,
156
- object_info_data[i].sizep))
157
- die("object-info: ref %s has invalid size %s",
155
+ &results->sizes[i]))
156
+ die("object-info: object %s has invalid size %s",
157
object_info_values.items[0].string,
158
object_info_values.items[size_index + 1].string);
159
168
169
return 0;
170
}
171
+
172
+void free_fetch_object_info_results(struct fetch_object_info_results *results)
173
+{
174
+ free(results->sizes);
175
+ free(results->unrecognized);
176
+ memset(results, 0, sizeof(*results));
177
+}