Raw
1 #include "git-compat-util.h"
2 #include "protocol-caps.h"
3 #include "gettext.h"
4 #include "hex.h"
5 #include "pkt-line.h"
6 #include "hash.h"
7 #include "object.h"
8 #include "odb.h"
9 #include "repository.h"
10 #include "string-list.h"
11 #include "strbuf.h"
12
13 struct requested_info {
14 unsigned size:1;
15 unsigned type:1;
16 };
17
18 /*
19 * Parses oids from the given line and collects them in the given
20 * oid_str_list. Returns 1 if parsing was successful and 0 otherwise.
21 */
22 static int parse_oid(const char *line, struct string_list *oid_str_list)
23 {
24 const char *arg;
25
26 if (!skip_prefix(line, "oid ", &arg))
27 return 0;
28
29 string_list_append(oid_str_list, arg);
30
31 return 1;
32 }
33
34 /*
35 * odb_read_object_info_extended() wrapper. Similar to odb_read_object_info()
36 * but uses the flags:
37 *
38 * - OBJECT_INFO_SKIP_FETCH_OBJECT so a server won't fetch an object when a
39 * object-info request asks for an OID that it doesn't have.
40 *
41 * - OBJECT_INFO_QUICK to avoid re-scanning packs when the object is not found.
42 */
43 static enum object_type get_object_info(struct object_database *odb,
44 const struct object_id *oid,
45 size_t *sizep)
46 {
47 enum object_type type;
48 struct object_info oi = OBJECT_INFO_INIT;
49
50 oi.typep = &type;
51 oi.sizep = sizep;
52 if (odb_read_object_info_extended(odb, oid, &oi,
53 OBJECT_INFO_LOOKUP_REPLACE |
54 OBJECT_INFO_SKIP_FETCH_OBJECT |
55 OBJECT_INFO_QUICK) < 0)
56 return OBJ_BAD;
57 return type;
58 }
59
60 /*
61 * Validates and send requested info back to the client. Any errors detected
62 * are returned as they are detected.
63 */
64 static void send_info(struct repository *r, struct packet_writer *writer,
65 struct string_list *oid_str_list,
66 struct requested_info *info)
67 {
68 struct string_list_item *item;
69 struct strbuf send_buffer = STRBUF_INIT;
70
71 if (!oid_str_list->nr)
72 return;
73
74 if (info->size)
75 packet_writer_write(writer, "size");
76
77 if (info->type)
78 packet_writer_write(writer, "type");
79
80 for_each_string_list_item (item, oid_str_list) {
81 const char *oid_str = item->string;
82 enum object_type object_type;
83 struct object_id oid;
84 size_t object_size;
85
86 if (get_oid_hex_algop(oid_str, &oid, r->hash_algo) < 0) {
87 packet_writer_error(
88 writer,
89 "object-info: protocol error, expected to get "
90 "oid, not '%s'",
91 oid_str);
92 continue;
93 }
94
95 strbuf_addstr(&send_buffer, oid_str);
96
97 /*
98 * Check the existence of the object first.
99 * If an object is not recognized by the server append SP to
100 * the response.
101 */
102 object_type = get_object_info(r->objects, &oid, &object_size);
103 if (object_type <= OBJ_NONE) {
104 strbuf_addstr(&send_buffer, " ");
105 goto write;
106 }
107
108 if (info->size) {
109 strbuf_addf(&send_buffer, " %"PRIuMAX,
110 (uintmax_t)object_size);
111 }
112
113 if (info->type)
114 strbuf_addf(&send_buffer, " %s", type_name(object_type));
115
116 write:
117 packet_writer_write(writer, "%s", send_buffer.buf);
118 strbuf_reset(&send_buffer);
119 }
120 strbuf_release(&send_buffer);
121 }
122
123 int cap_object_info(struct repository *r, struct packet_reader *request)
124 {
125 struct requested_info info = { 0 };
126 struct packet_writer writer;
127 struct string_list oid_str_list = STRING_LIST_INIT_DUP;
128
129 packet_writer_init(&writer, 1);
130
131 while (packet_reader_read(request) == PACKET_READ_NORMAL) {
132 if (!strcmp("size", request->line)) {
133 info.size = 1;
134 continue;
135 }
136
137 if (!strcmp("type", request->line)) {
138 info.type = 1;
139 continue;
140 }
141
142 if (parse_oid(request->line, &oid_str_list))
143 continue;
144
145 packet_writer_error(&writer,
146 "object-info: unexpected line: '%s'",
147 request->line);
148 }
149
150 if (request->status != PACKET_READ_FLUSH) {
151 packet_writer_error(
152 &writer, "object-info: expected flush after arguments");
153 die(_("object-info: expected flush after arguments"));
154 }
155
156 send_info(r, &writer, &oid_str_list, &info);
157
158 string_list_clear(&oid_str_list, 1);
159
160 packet_flush(1);
161
162 return 0;
163 }