Line | Count | Source |
1 | | #include "git-compat-util.h" |
2 | | #include "hash.h" |
3 | | #include "hex.h" |
4 | | |
5 | | static const struct object_id empty_tree_oid = { |
6 | | .hash = { |
7 | | 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, |
8 | | 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 |
9 | | }, |
10 | | .algo = GIT_HASH_SHA1, |
11 | | }; |
12 | | static const struct object_id empty_blob_oid = { |
13 | | .hash = { |
14 | | 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b, |
15 | | 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91 |
16 | | }, |
17 | | .algo = GIT_HASH_SHA1, |
18 | | }; |
19 | | static const struct object_id null_oid_sha1 = { |
20 | | .hash = {0}, |
21 | | .algo = GIT_HASH_SHA1, |
22 | | }; |
23 | | static const struct object_id empty_tree_oid_sha256 = { |
24 | | .hash = { |
25 | | 0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1, |
26 | | 0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5, |
27 | | 0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc, |
28 | | 0x53, 0x21 |
29 | | }, |
30 | | .algo = GIT_HASH_SHA256, |
31 | | }; |
32 | | static const struct object_id empty_blob_oid_sha256 = { |
33 | | .hash = { |
34 | | 0x47, 0x3a, 0x0f, 0x4c, 0x3b, 0xe8, 0xa9, 0x36, 0x81, 0xa2, |
35 | | 0x67, 0xe3, 0xb1, 0xe9, 0xa7, 0xdc, 0xda, 0x11, 0x85, 0x43, |
36 | | 0x6f, 0xe1, 0x41, 0xf7, 0x74, 0x91, 0x20, 0xa3, 0x03, 0x72, |
37 | | 0x18, 0x13 |
38 | | }, |
39 | | .algo = GIT_HASH_SHA256, |
40 | | }; |
41 | | static const struct object_id null_oid_sha256 = { |
42 | | .hash = {0}, |
43 | | .algo = GIT_HASH_SHA256, |
44 | | }; |
45 | | |
46 | | static void git_hash_sha1_init(struct git_hash_ctx *ctx) |
47 | 0 | { |
48 | 0 | ctx->algop = &hash_algos[GIT_HASH_SHA1]; |
49 | 0 | git_SHA1_Init(&ctx->state.sha1); |
50 | 0 | } |
51 | | |
52 | | static void git_hash_sha1_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src) |
53 | 0 | { |
54 | 0 | dst->algop = src->algop; |
55 | 0 | git_SHA1_Clone(&dst->state.sha1, &src->state.sha1); |
56 | 0 | } |
57 | | |
58 | | static void git_hash_sha1_update(struct git_hash_ctx *ctx, const void *data, size_t len) |
59 | 0 | { |
60 | 0 | git_SHA1_Update(&ctx->state.sha1, data, len); |
61 | 0 | } |
62 | | |
63 | | static void git_hash_sha1_final(unsigned char *hash, struct git_hash_ctx *ctx) |
64 | 0 | { |
65 | 0 | git_SHA1_Final(hash, &ctx->state.sha1); |
66 | 0 | } |
67 | | |
68 | | static void git_hash_sha1_final_oid(struct object_id *oid, struct git_hash_ctx *ctx) |
69 | 0 | { |
70 | 0 | git_SHA1_Final(oid->hash, &ctx->state.sha1); |
71 | 0 | memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ); |
72 | 0 | oid->algo = GIT_HASH_SHA1; |
73 | 0 | } |
74 | | |
75 | | static void git_hash_sha1_discard(struct git_hash_ctx *ctx) |
76 | 0 | { |
77 | 0 | git_SHA1_Discard(&ctx->state.sha1); |
78 | 0 | } |
79 | | |
80 | | static void git_hash_sha1_init_unsafe(struct git_hash_ctx *ctx) |
81 | 0 | { |
82 | 0 | ctx->algop = unsafe_hash_algo(&hash_algos[GIT_HASH_SHA1]); |
83 | 0 | git_SHA1_Init_unsafe(&ctx->state.sha1_unsafe); |
84 | 0 | } |
85 | | |
86 | | static void git_hash_sha1_clone_unsafe(struct git_hash_ctx *dst, const struct git_hash_ctx *src) |
87 | 0 | { |
88 | 0 | dst->algop = src->algop; |
89 | 0 | git_SHA1_Clone_unsafe(&dst->state.sha1_unsafe, &src->state.sha1_unsafe); |
90 | 0 | } |
91 | | |
92 | | static void git_hash_sha1_update_unsafe(struct git_hash_ctx *ctx, const void *data, |
93 | | size_t len) |
94 | 0 | { |
95 | 0 | git_SHA1_Update_unsafe(&ctx->state.sha1_unsafe, data, len); |
96 | 0 | } |
97 | | |
98 | | static void git_hash_sha1_final_unsafe(unsigned char *hash, struct git_hash_ctx *ctx) |
99 | 0 | { |
100 | 0 | git_SHA1_Final_unsafe(hash, &ctx->state.sha1_unsafe); |
101 | 0 | } |
102 | | |
103 | | static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, struct git_hash_ctx *ctx) |
104 | 0 | { |
105 | 0 | git_SHA1_Final_unsafe(oid->hash, &ctx->state.sha1_unsafe); |
106 | 0 | memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ); |
107 | 0 | oid->algo = GIT_HASH_SHA1; |
108 | 0 | } |
109 | | |
110 | | static void git_hash_sha1_discard_unsafe(struct git_hash_ctx *ctx) |
111 | 0 | { |
112 | 0 | git_SHA1_Discard_unsafe(&ctx->state.sha1_unsafe); |
113 | 0 | } |
114 | | |
115 | | static void git_hash_sha256_init(struct git_hash_ctx *ctx) |
116 | 0 | { |
117 | 0 | ctx->algop = unsafe_hash_algo(&hash_algos[GIT_HASH_SHA256]); |
118 | 0 | git_SHA256_Init(&ctx->state.sha256); |
119 | 0 | } |
120 | | |
121 | | static void git_hash_sha256_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src) |
122 | 0 | { |
123 | 0 | dst->algop = src->algop; |
124 | 0 | git_SHA256_Clone(&dst->state.sha256, &src->state.sha256); |
125 | 0 | } |
126 | | |
127 | | static void git_hash_sha256_update(struct git_hash_ctx *ctx, const void *data, size_t len) |
128 | 0 | { |
129 | 0 | git_SHA256_Update(&ctx->state.sha256, data, len); |
130 | 0 | } |
131 | | |
132 | | static void git_hash_sha256_final(unsigned char *hash, struct git_hash_ctx *ctx) |
133 | 0 | { |
134 | 0 | git_SHA256_Final(hash, &ctx->state.sha256); |
135 | 0 | } |
136 | | |
137 | | static void git_hash_sha256_final_oid(struct object_id *oid, struct git_hash_ctx *ctx) |
138 | 0 | { |
139 | 0 | git_SHA256_Final(oid->hash, &ctx->state.sha256); |
140 | | /* |
141 | | * This currently does nothing, so the compiler should optimize it out, |
142 | | * but keep it in case we extend the hash size again. |
143 | | */ |
144 | 0 | memset(oid->hash + GIT_SHA256_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA256_RAWSZ); |
145 | 0 | oid->algo = GIT_HASH_SHA256; |
146 | 0 | } |
147 | | |
148 | | static void git_hash_sha256_discard(struct git_hash_ctx *ctx) |
149 | 0 | { |
150 | 0 | git_SHA256_Discard(&ctx->state.sha256); |
151 | 0 | } |
152 | | |
153 | | static void git_hash_unknown_init(struct git_hash_ctx *ctx UNUSED) |
154 | 0 | { |
155 | 0 | BUG("trying to init unknown hash"); |
156 | 0 | } |
157 | | |
158 | | static void git_hash_unknown_clone(struct git_hash_ctx *dst UNUSED, |
159 | | const struct git_hash_ctx *src UNUSED) |
160 | 0 | { |
161 | 0 | BUG("trying to clone unknown hash"); |
162 | 0 | } |
163 | | |
164 | | static void git_hash_unknown_update(struct git_hash_ctx *ctx UNUSED, |
165 | | const void *data UNUSED, |
166 | | size_t len UNUSED) |
167 | 0 | { |
168 | 0 | BUG("trying to update unknown hash"); |
169 | 0 | } |
170 | | |
171 | | static void git_hash_unknown_final(unsigned char *hash UNUSED, |
172 | | struct git_hash_ctx *ctx UNUSED) |
173 | 0 | { |
174 | 0 | BUG("trying to finalize unknown hash"); |
175 | 0 | } |
176 | | |
177 | | static void git_hash_unknown_final_oid(struct object_id *oid UNUSED, |
178 | | struct git_hash_ctx *ctx UNUSED) |
179 | 0 | { |
180 | 0 | BUG("trying to finalize unknown hash"); |
181 | 0 | } |
182 | | |
183 | | static void git_hash_unknown_discard(struct git_hash_ctx *ctx UNUSED) |
184 | 0 | { |
185 | 0 | BUG("trying to discard unknown hash"); |
186 | 0 | } |
187 | | |
188 | | static const struct git_hash_algo sha1_unsafe_algo = { |
189 | | .name = "sha1", |
190 | | .format_id = GIT_SHA1_FORMAT_ID, |
191 | | .rawsz = GIT_SHA1_RAWSZ, |
192 | | .hexsz = GIT_SHA1_HEXSZ, |
193 | | .blksz = GIT_SHA1_BLKSZ, |
194 | | .init_fn = git_hash_sha1_init_unsafe, |
195 | | .clone_fn = git_hash_sha1_clone_unsafe, |
196 | | .update_fn = git_hash_sha1_update_unsafe, |
197 | | .final_fn = git_hash_sha1_final_unsafe, |
198 | | .final_oid_fn = git_hash_sha1_final_oid_unsafe, |
199 | | .discard_fn = git_hash_sha1_discard_unsafe, |
200 | | .empty_tree = &empty_tree_oid, |
201 | | .empty_blob = &empty_blob_oid, |
202 | | .null_oid = &null_oid_sha1, |
203 | | }; |
204 | | |
205 | | const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { |
206 | | { |
207 | | .name = NULL, |
208 | | .format_id = 0x00000000, |
209 | | .rawsz = 0, |
210 | | .hexsz = 0, |
211 | | .blksz = 0, |
212 | | .init_fn = git_hash_unknown_init, |
213 | | .clone_fn = git_hash_unknown_clone, |
214 | | .update_fn = git_hash_unknown_update, |
215 | | .final_fn = git_hash_unknown_final, |
216 | | .final_oid_fn = git_hash_unknown_final_oid, |
217 | | .discard_fn = git_hash_unknown_discard, |
218 | | .empty_tree = NULL, |
219 | | .empty_blob = NULL, |
220 | | .null_oid = NULL, |
221 | | }, |
222 | | { |
223 | | .name = "sha1", |
224 | | .format_id = GIT_SHA1_FORMAT_ID, |
225 | | .rawsz = GIT_SHA1_RAWSZ, |
226 | | .hexsz = GIT_SHA1_HEXSZ, |
227 | | .blksz = GIT_SHA1_BLKSZ, |
228 | | .init_fn = git_hash_sha1_init, |
229 | | .clone_fn = git_hash_sha1_clone, |
230 | | .update_fn = git_hash_sha1_update, |
231 | | .final_fn = git_hash_sha1_final, |
232 | | .final_oid_fn = git_hash_sha1_final_oid, |
233 | | .discard_fn = git_hash_sha1_discard, |
234 | | .unsafe = &sha1_unsafe_algo, |
235 | | .empty_tree = &empty_tree_oid, |
236 | | .empty_blob = &empty_blob_oid, |
237 | | .null_oid = &null_oid_sha1, |
238 | | }, |
239 | | { |
240 | | .name = "sha256", |
241 | | .format_id = GIT_SHA256_FORMAT_ID, |
242 | | .rawsz = GIT_SHA256_RAWSZ, |
243 | | .hexsz = GIT_SHA256_HEXSZ, |
244 | | .blksz = GIT_SHA256_BLKSZ, |
245 | | .init_fn = git_hash_sha256_init, |
246 | | .clone_fn = git_hash_sha256_clone, |
247 | | .update_fn = git_hash_sha256_update, |
248 | | .final_fn = git_hash_sha256_final, |
249 | | .final_oid_fn = git_hash_sha256_final_oid, |
250 | | .discard_fn = git_hash_sha256_discard, |
251 | | .empty_tree = &empty_tree_oid_sha256, |
252 | | .empty_blob = &empty_blob_oid_sha256, |
253 | | .null_oid = &null_oid_sha256, |
254 | | } |
255 | | }; |
256 | | |
257 | | const struct object_id *null_oid(const struct git_hash_algo *algop) |
258 | 0 | { |
259 | 0 | return algop->null_oid; |
260 | 0 | } |
261 | | |
262 | | const char *empty_tree_oid_hex(const struct git_hash_algo *algop) |
263 | 0 | { |
264 | 0 | static char buf[GIT_MAX_HEXSZ + 1]; |
265 | 0 | return oid_to_hex_r(buf, algop->empty_tree); |
266 | 0 | } |
267 | | |
268 | | const struct git_hash_algo *hash_algo_ptr_by_number(uint32_t algo) |
269 | 0 | { |
270 | 0 | if (algo >= GIT_HASH_NALGOS) |
271 | 0 | return NULL; |
272 | 0 | return &hash_algos[algo]; |
273 | 0 | } |
274 | | |
275 | | struct git_hash_ctx *git_hash_alloc(void) |
276 | 0 | { |
277 | 0 | return xmalloc(sizeof(struct git_hash_ctx)); |
278 | 0 | } |
279 | | |
280 | | void git_hash_free(struct git_hash_ctx *ctx) |
281 | 0 | { |
282 | 0 | free(ctx); |
283 | 0 | } |
284 | | |
285 | | void git_hash_init(struct git_hash_ctx *ctx, const struct git_hash_algo *algop) |
286 | 0 | { |
287 | 0 | algop->init_fn(ctx); |
288 | 0 | ctx->active = true; |
289 | 0 | } |
290 | | |
291 | | void git_hash_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src) |
292 | 0 | { |
293 | 0 | if (!src->active) |
294 | 0 | BUG("attempt to copy from an inactive hash context"); |
295 | 0 | if (!dst->active) |
296 | 0 | BUG("attempt to copy to an inactive hash context"); |
297 | 0 | src->algop->clone_fn(dst, src); |
298 | 0 | } |
299 | | |
300 | | void git_hash_update(struct git_hash_ctx *ctx, const void *in, size_t len) |
301 | 0 | { |
302 | 0 | if (!ctx->active) |
303 | 0 | BUG("attempt to update an inactive hash context"); |
304 | 0 | ctx->algop->update_fn(ctx, in, len); |
305 | 0 | } |
306 | | |
307 | | void git_hash_final(unsigned char *hash, struct git_hash_ctx *ctx) |
308 | 0 | { |
309 | 0 | if (!ctx->active) |
310 | 0 | BUG("attempt to finalize an inactive hash context"); |
311 | 0 | ctx->algop->final_fn(hash, ctx); |
312 | 0 | ctx->active = false; |
313 | 0 | } |
314 | | |
315 | | void git_hash_final_oid(struct object_id *oid, struct git_hash_ctx *ctx) |
316 | 0 | { |
317 | 0 | if (!ctx->active) |
318 | 0 | BUG("attempt to finalize an inactive hash context"); |
319 | 0 | ctx->algop->final_oid_fn(oid, ctx); |
320 | 0 | ctx->active = false; |
321 | 0 | } |
322 | | |
323 | | void git_hash_discard(struct git_hash_ctx *ctx) |
324 | 0 | { |
325 | 0 | if (!ctx->active) |
326 | 0 | return; |
327 | 0 | ctx->algop->discard_fn(ctx); |
328 | 0 | ctx->active = false; |
329 | 0 | } |
330 | | |
331 | | uint32_t hash_algo_by_name(const char *name) |
332 | 0 | { |
333 | 0 | if (!name) |
334 | 0 | return GIT_HASH_UNKNOWN; |
335 | 0 | for (size_t i = 1; i < GIT_HASH_NALGOS; i++) |
336 | 0 | if (!strcmp(name, hash_algos[i].name)) |
337 | 0 | return i; |
338 | 0 | return GIT_HASH_UNKNOWN; |
339 | 0 | } |
340 | | |
341 | | uint32_t hash_algo_by_id(uint32_t format_id) |
342 | 0 | { |
343 | 0 | for (size_t i = 1; i < GIT_HASH_NALGOS; i++) |
344 | 0 | if (format_id == hash_algos[i].format_id) |
345 | 0 | return i; |
346 | 0 | return GIT_HASH_UNKNOWN; |
347 | 0 | } |
348 | | |
349 | | uint32_t hash_algo_by_length(size_t len) |
350 | 0 | { |
351 | 0 | for (size_t i = 1; i < GIT_HASH_NALGOS; i++) |
352 | 0 | if (len == hash_algos[i].rawsz) |
353 | 0 | return i; |
354 | 0 | return GIT_HASH_UNKNOWN; |
355 | 0 | } |
356 | | |
357 | | const struct git_hash_algo *unsafe_hash_algo(const struct git_hash_algo *algop) |
358 | 0 | { |
359 | | /* If we have a faster "unsafe" implementation, use that. */ |
360 | 0 | if (algop->unsafe) |
361 | 0 | return algop->unsafe; |
362 | | /* Otherwise use the default one. */ |
363 | 0 | return algop; |
364 | 0 | } |
365 | | |
366 | | unsigned oid_common_prefix_hexlen(const struct object_id *a, |
367 | | const struct object_id *b) |
368 | 0 | { |
369 | 0 | unsigned rawsz = hash_algos[a->algo].rawsz; |
370 | |
|
371 | 0 | for (unsigned i = 0; i < rawsz; i++) { |
372 | 0 | if (a->hash[i] == b->hash[i]) |
373 | 0 | continue; |
374 | | |
375 | 0 | if ((a->hash[i] ^ b->hash[i]) & 0xf0) |
376 | 0 | return i * 2; |
377 | 0 | else |
378 | 0 | return i * 2 + 1; |
379 | 0 | } |
380 | | |
381 | 0 | return rawsz * 2; |
382 | 0 | } |