Line | Count | Source |
1 | | #include "git-compat-util.h" |
2 | | #include "abspath.h" |
3 | | #include "commit-graph.h" |
4 | | #include "config.h" |
5 | | #include "environment.h" |
6 | | #include "gettext.h" |
7 | | #include "hashmap.h" |
8 | | #include "hex.h" |
9 | | #include "lockfile.h" |
10 | | #include "loose.h" |
11 | | #include "midx.h" |
12 | | #include "object-file-convert.h" |
13 | | #include "object-file.h" |
14 | | #include "object-name.h" |
15 | | #include "odb.h" |
16 | | #include "odb/source-files.h" |
17 | | #include "odb/source-inmemory.h" |
18 | | #include "path.h" |
19 | | #include "promisor-remote.h" |
20 | | #include "replace-object.h" |
21 | | #include "run-command.h" |
22 | | #include "setup.h" |
23 | | #include "strbuf.h" |
24 | | #include "strvec.h" |
25 | | #include "submodule.h" |
26 | | #include "tmp-objdir.h" |
27 | | #include "trace2.h" |
28 | | #include "write-or-die.h" |
29 | | |
30 | | static const char * const object_storage_name_by_format[] = { |
31 | | [OBJECT_STORAGE_FORMAT_UNKNOWN] = "unknown", |
32 | | [OBJECT_STORAGE_FORMAT_FILES] = "files", |
33 | | }; |
34 | | |
35 | | enum object_storage_format object_storage_format_by_name(const char *name) |
36 | 0 | { |
37 | 0 | for (size_t i = 0; i < ARRAY_SIZE(object_storage_name_by_format); i++) |
38 | 0 | if (!strcmp(object_storage_name_by_format[i], name)) |
39 | 0 | return i; |
40 | 0 | return OBJECT_STORAGE_FORMAT_UNKNOWN; |
41 | 0 | } |
42 | | |
43 | | const char *object_storage_format_to_name(enum object_storage_format format) |
44 | 0 | { |
45 | 0 | if (format < 0 || format >= ARRAY_SIZE(object_storage_name_by_format)) |
46 | 0 | format = OBJECT_STORAGE_FORMAT_UNKNOWN; |
47 | 0 | return object_storage_name_by_format[format]; |
48 | 0 | } |
49 | | |
50 | | enum object_storage_format object_storage_format_by_uri(const char *uri, char **payload) |
51 | 0 | { |
52 | 0 | enum object_storage_format format; |
53 | 0 | const char *schema_end; |
54 | 0 | char *name; |
55 | |
|
56 | 0 | schema_end = strstr(uri, "://"); |
57 | 0 | if (!schema_end) { |
58 | 0 | name = xstrdup(uri); |
59 | 0 | if (payload) |
60 | 0 | *payload = NULL; |
61 | 0 | } else { |
62 | 0 | name = xstrndup(uri, schema_end - uri); |
63 | 0 | if (payload) |
64 | 0 | *payload = *(schema_end + 3) ? xstrdup(schema_end + 3) : NULL; |
65 | 0 | } |
66 | |
|
67 | 0 | format = object_storage_format_by_name(name); |
68 | |
|
69 | 0 | free(name); |
70 | 0 | return format; |
71 | 0 | } |
72 | | |
73 | | int odb_mkstemp(struct object_database *odb, |
74 | | struct strbuf *temp_filename, const char *pattern) |
75 | 0 | { |
76 | 0 | int fd; |
77 | | /* |
78 | | * we let the umask do its job, don't try to be more |
79 | | * restrictive except to remove write permission. |
80 | | */ |
81 | 0 | int mode = 0444; |
82 | 0 | repo_git_path_replace(odb->repo, temp_filename, "objects/%s", pattern); |
83 | 0 | fd = git_mkstemp_mode(temp_filename->buf, mode); |
84 | 0 | if (0 <= fd) |
85 | 0 | return fd; |
86 | | |
87 | | /* slow path */ |
88 | | /* some mkstemp implementations erase temp_filename on failure */ |
89 | 0 | repo_git_path_replace(odb->repo, temp_filename, "objects/%s", pattern); |
90 | 0 | safe_create_leading_directories(odb->repo, temp_filename->buf); |
91 | 0 | return xmkstemp_mode(temp_filename->buf, mode); |
92 | 0 | } |
93 | | |
94 | | char *compute_alternate_path(const char *path, struct strbuf *err) |
95 | 0 | { |
96 | 0 | char *ref_git = NULL; |
97 | 0 | const char *repo; |
98 | 0 | int seen_error = 0; |
99 | |
|
100 | 0 | ref_git = real_pathdup(path, 0); |
101 | 0 | if (!ref_git) { |
102 | 0 | seen_error = 1; |
103 | 0 | strbuf_addf(err, _("path '%s' does not exist"), path); |
104 | 0 | goto out; |
105 | 0 | } |
106 | | |
107 | 0 | repo = read_gitfile(ref_git); |
108 | 0 | if (!repo) |
109 | 0 | repo = read_gitfile(mkpath("%s/.git", ref_git)); |
110 | 0 | if (repo) { |
111 | 0 | free(ref_git); |
112 | 0 | ref_git = xstrdup(repo); |
113 | 0 | } |
114 | |
|
115 | 0 | if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) { |
116 | 0 | char *ref_git_git = mkpathdup("%s/.git", ref_git); |
117 | 0 | free(ref_git); |
118 | 0 | ref_git = ref_git_git; |
119 | 0 | } else if (!is_directory(mkpath("%s/objects", ref_git))) { |
120 | 0 | struct strbuf sb = STRBUF_INIT; |
121 | 0 | seen_error = 1; |
122 | 0 | if (get_common_dir(&sb, ref_git)) { |
123 | 0 | strbuf_addf(err, |
124 | 0 | _("reference repository '%s' as a linked " |
125 | 0 | "checkout is not supported yet."), |
126 | 0 | path); |
127 | 0 | goto out; |
128 | 0 | } |
129 | | |
130 | 0 | strbuf_addf(err, _("reference repository '%s' is not a " |
131 | 0 | "local repository."), path); |
132 | 0 | goto out; |
133 | 0 | } |
134 | | |
135 | 0 | if (!access(mkpath("%s/shallow", ref_git), F_OK)) { |
136 | 0 | strbuf_addf(err, _("reference repository '%s' is shallow"), |
137 | 0 | path); |
138 | 0 | seen_error = 1; |
139 | 0 | goto out; |
140 | 0 | } |
141 | | |
142 | 0 | if (!access(mkpath("%s/info/grafts", ref_git), F_OK)) { |
143 | 0 | strbuf_addf(err, |
144 | 0 | _("reference repository '%s' is grafted"), |
145 | 0 | path); |
146 | 0 | seen_error = 1; |
147 | 0 | goto out; |
148 | 0 | } |
149 | | |
150 | 0 | out: |
151 | 0 | if (seen_error) { |
152 | 0 | FREE_AND_NULL(ref_git); |
153 | 0 | } |
154 | |
|
155 | 0 | return ref_git; |
156 | 0 | } |
157 | | |
158 | | static void fill_alternate_refs_command(struct repository *repo, |
159 | | struct child_process *cmd, |
160 | | const char *repo_path) |
161 | 0 | { |
162 | 0 | const char *value; |
163 | |
|
164 | 0 | if (!repo_config_get_value(repo, "core.alternateRefsCommand", &value)) { |
165 | 0 | cmd->use_shell = 1; |
166 | |
|
167 | 0 | strvec_push(&cmd->args, value); |
168 | 0 | strvec_push(&cmd->args, repo_path); |
169 | 0 | } else { |
170 | 0 | cmd->git_cmd = 1; |
171 | |
|
172 | 0 | strvec_pushf(&cmd->args, "--git-dir=%s", repo_path); |
173 | 0 | strvec_push(&cmd->args, "for-each-ref"); |
174 | 0 | strvec_push(&cmd->args, "--format=%(objectname)"); |
175 | |
|
176 | 0 | if (!repo_config_get_value(repo, "core.alternateRefsPrefixes", &value)) { |
177 | 0 | strvec_push(&cmd->args, "--"); |
178 | 0 | strvec_split(&cmd->args, value); |
179 | 0 | } |
180 | 0 | } |
181 | |
|
182 | 0 | strvec_pushv(&cmd->env, (const char **)local_repo_env); |
183 | 0 | cmd->out = -1; |
184 | 0 | } |
185 | | |
186 | | static void read_alternate_refs(struct repository *repo, |
187 | | const char *path, |
188 | | odb_for_each_alternate_ref_fn *cb, |
189 | | void *payload) |
190 | 0 | { |
191 | 0 | struct child_process cmd = CHILD_PROCESS_INIT; |
192 | 0 | struct strbuf line = STRBUF_INIT; |
193 | 0 | FILE *fh; |
194 | |
|
195 | 0 | fill_alternate_refs_command(repo, &cmd, path); |
196 | |
|
197 | 0 | if (start_command(&cmd)) |
198 | 0 | return; |
199 | | |
200 | 0 | fh = xfdopen(cmd.out, "r"); |
201 | 0 | while (strbuf_getline_lf(&line, fh) != EOF) { |
202 | 0 | struct object_id oid; |
203 | 0 | const char *p; |
204 | |
|
205 | 0 | if (parse_oid_hex_algop(line.buf, &oid, &p, repo->hash_algo) || *p) { |
206 | 0 | warning(_("invalid line while parsing alternate refs: %s"), |
207 | 0 | line.buf); |
208 | 0 | break; |
209 | 0 | } |
210 | | |
211 | 0 | cb(&oid, payload); |
212 | 0 | } |
213 | |
|
214 | 0 | fclose(fh); |
215 | 0 | finish_command(&cmd); |
216 | 0 | strbuf_release(&line); |
217 | 0 | } |
218 | | |
219 | | struct alternate_refs_data { |
220 | | struct repository *repo; |
221 | | odb_for_each_alternate_ref_fn *fn; |
222 | | void *payload; |
223 | | }; |
224 | | |
225 | | static int refs_from_alternate_cb(struct odb_files_dir *alternate, |
226 | | void *payload) |
227 | 0 | { |
228 | 0 | struct strbuf path = STRBUF_INIT; |
229 | 0 | size_t base_len; |
230 | 0 | struct alternate_refs_data *cb = payload; |
231 | |
|
232 | 0 | if (!strbuf_realpath(&path, alternate->abspath, 0)) |
233 | 0 | goto out; |
234 | 0 | if (!strbuf_strip_suffix(&path, "/objects")) |
235 | 0 | goto out; |
236 | 0 | base_len = path.len; |
237 | | |
238 | | /* Is this a git repository with refs? */ |
239 | 0 | strbuf_addstr(&path, "/refs"); |
240 | 0 | if (!is_directory(path.buf)) |
241 | 0 | goto out; |
242 | 0 | strbuf_setlen(&path, base_len); |
243 | | |
244 | | /* A shallow or grafted repository may lack the history behind its refs. */ |
245 | 0 | strbuf_addstr(&path, "/shallow"); |
246 | 0 | if (!access(path.buf, F_OK)) |
247 | 0 | goto out; |
248 | 0 | strbuf_setlen(&path, base_len); |
249 | |
|
250 | 0 | strbuf_addstr(&path, "/info/grafts"); |
251 | 0 | if (!access(path.buf, F_OK)) |
252 | 0 | goto out; |
253 | 0 | strbuf_setlen(&path, base_len); |
254 | |
|
255 | 0 | read_alternate_refs(cb->repo, path.buf, cb->fn, cb->payload); |
256 | |
|
257 | 0 | out: |
258 | 0 | strbuf_release(&path); |
259 | 0 | return 0; |
260 | 0 | } |
261 | | |
262 | | void odb_for_each_alternate_ref(struct object_database *odb, |
263 | | odb_for_each_alternate_ref_fn cb, void *payload) |
264 | 0 | { |
265 | 0 | struct alternate_refs_data data = { |
266 | 0 | .fn = cb, |
267 | 0 | .payload = payload, |
268 | 0 | .repo = odb->repo, |
269 | 0 | }; |
270 | 0 | odb_for_each_alternate(odb, refs_from_alternate_cb, &data); |
271 | 0 | } |
272 | | |
273 | | int odb_for_each_alternate(struct object_database *odb, |
274 | | odb_for_each_alternate_fn cb, void *payload) |
275 | 0 | { |
276 | 0 | struct odb_source_files *files = odb_source_files_downcast(odb->source); |
277 | 0 | int r = 0; |
278 | |
|
279 | 0 | for (struct odb_files_dir *dir = files->dirs->next; dir; dir = dir->next) { |
280 | 0 | r = cb(dir, payload); |
281 | 0 | if (r) |
282 | 0 | break; |
283 | 0 | } |
284 | 0 | return r; |
285 | 0 | } |
286 | | |
287 | | int odb_has_alternates(struct object_database *odb) |
288 | 0 | { |
289 | 0 | if (odb->source->type != ODB_SOURCE_FILES) |
290 | 0 | return 0; |
291 | 0 | return !!odb_source_files_downcast(odb->source)->dirs->next; |
292 | 0 | } |
293 | | |
294 | | int obj_read_use_lock = 0; |
295 | | pthread_mutex_t obj_read_mutex; |
296 | | |
297 | | void enable_obj_read_lock(void) |
298 | 0 | { |
299 | 0 | if (obj_read_use_lock) |
300 | 0 | return; |
301 | | |
302 | 0 | obj_read_use_lock = 1; |
303 | 0 | init_recursive_mutex(&obj_read_mutex); |
304 | 0 | } |
305 | | |
306 | | void disable_obj_read_lock(void) |
307 | 0 | { |
308 | 0 | if (!obj_read_use_lock) |
309 | 0 | return; |
310 | | |
311 | 0 | obj_read_use_lock = 0; |
312 | 0 | pthread_mutex_destroy(&obj_read_mutex); |
313 | 0 | } |
314 | | |
315 | | static enum odb_read_status do_oid_object_info_extended(struct object_database *odb, |
316 | | const struct object_id *oid, |
317 | | struct object_info *oi, unsigned flags) |
318 | 0 | { |
319 | 0 | struct strbuf corrupt_err = STRBUF_INIT; |
320 | 0 | const struct object_id *real = oid; |
321 | 0 | enum odb_read_status ret; |
322 | |
|
323 | 0 | if (flags & OBJECT_INFO_LOOKUP_REPLACE) |
324 | 0 | real = lookup_replace_object(odb->repo, oid); |
325 | |
|
326 | 0 | if (is_null_oid(real)) |
327 | 0 | return -1; |
328 | | |
329 | 0 | if (!odb_source_read_object_info(odb->inmemory_objects, oid, oi, flags, NULL)) |
330 | 0 | return 0; |
331 | | |
332 | 0 | ret = odb_source_read_object_info(odb->source, real, oi, flags, |
333 | 0 | &corrupt_err); |
334 | 0 | if (ret == ODB_READ_NOT_FOUND && |
335 | 0 | odb->repo->fetch_if_missing && |
336 | 0 | !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT) && |
337 | 0 | repo_has_promisor_remote(odb->repo)) { |
338 | | /* Try to fetch the missing object from a promisor remote. */ |
339 | 0 | promisor_remote_get_direct(odb->repo, real, 1); |
340 | 0 | ret = odb_source_read_object_info(odb->source, real, oi, flags, |
341 | 0 | &corrupt_err); |
342 | 0 | } |
343 | |
|
344 | 0 | if (ret < 0 && (flags & OBJECT_INFO_DIE_IF_CORRUPT)) { |
345 | 0 | if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid)) |
346 | 0 | die(_("replacement %s not found for %s"), |
347 | 0 | oid_to_hex(real), oid_to_hex(oid)); |
348 | 0 | if (ret != ODB_READ_NOT_FOUND) { |
349 | 0 | if (corrupt_err.len) |
350 | 0 | die("%s", corrupt_err.buf); |
351 | 0 | die(_("object %s is corrupt"), oid_to_hex(real)); |
352 | 0 | } |
353 | 0 | } |
354 | | |
355 | 0 | strbuf_release(&corrupt_err); |
356 | 0 | return ret; |
357 | 0 | } |
358 | | |
359 | | static int oid_object_info_convert(struct repository *r, |
360 | | const struct object_id *input_oid, |
361 | | struct object_info *input_oi, unsigned flags) |
362 | 0 | { |
363 | 0 | const struct git_hash_algo *input_algo = &hash_algos[input_oid->algo]; |
364 | 0 | int do_die = flags & OBJECT_INFO_DIE_IF_CORRUPT; |
365 | 0 | enum object_type type; |
366 | 0 | struct object_id oid, delta_base_oid; |
367 | 0 | struct object_info new_oi, *oi; |
368 | 0 | size_t size; |
369 | 0 | void *content; |
370 | 0 | int ret; |
371 | |
|
372 | 0 | if (repo_oid_to_algop(r, input_oid, r->hash_algo, &oid)) { |
373 | 0 | if (do_die) |
374 | 0 | die(_("missing mapping of %s to %s"), |
375 | 0 | oid_to_hex(input_oid), r->hash_algo->name); |
376 | 0 | return -1; |
377 | 0 | } |
378 | | |
379 | | /* Is new_oi needed? */ |
380 | 0 | oi = input_oi; |
381 | 0 | if (input_oi && (input_oi->delta_base_oid || input_oi->sizep || |
382 | 0 | input_oi->contentp)) { |
383 | 0 | new_oi = *input_oi; |
384 | | /* Does delta_base_oid need to be converted? */ |
385 | 0 | if (input_oi->delta_base_oid) |
386 | 0 | new_oi.delta_base_oid = &delta_base_oid; |
387 | | /* Will the attributes differ when converted? */ |
388 | 0 | if (input_oi->sizep || input_oi->contentp) { |
389 | 0 | new_oi.contentp = &content; |
390 | 0 | new_oi.sizep = &size; |
391 | 0 | new_oi.typep = &type; |
392 | 0 | } |
393 | 0 | oi = &new_oi; |
394 | 0 | } |
395 | |
|
396 | 0 | ret = odb_read_object_info_extended(r->objects, &oid, oi, flags); |
397 | 0 | if (ret) |
398 | 0 | return -1; |
399 | 0 | if (oi == input_oi) |
400 | 0 | return ret; |
401 | | |
402 | 0 | if (new_oi.contentp) { |
403 | 0 | struct strbuf outbuf = STRBUF_INIT; |
404 | |
|
405 | 0 | if (type != OBJ_BLOB) { |
406 | 0 | ret = convert_object_file(r, &outbuf, |
407 | 0 | r->hash_algo, input_algo, |
408 | 0 | content, size, type, !do_die); |
409 | 0 | free(content); |
410 | 0 | if (ret == -1) |
411 | 0 | return -1; |
412 | 0 | size = outbuf.len; |
413 | 0 | content = strbuf_detach(&outbuf, NULL); |
414 | 0 | } |
415 | 0 | if (input_oi->sizep) |
416 | 0 | *input_oi->sizep = size; |
417 | 0 | if (input_oi->contentp) |
418 | 0 | *input_oi->contentp = content; |
419 | 0 | else |
420 | 0 | free(content); |
421 | 0 | if (input_oi->typep) |
422 | 0 | *input_oi->typep = type; |
423 | 0 | } |
424 | 0 | if (new_oi.delta_base_oid == &delta_base_oid) { |
425 | 0 | if (repo_oid_to_algop(r, &delta_base_oid, input_algo, |
426 | 0 | input_oi->delta_base_oid)) { |
427 | 0 | if (do_die) |
428 | 0 | die(_("missing mapping of %s to %s"), |
429 | 0 | oid_to_hex(&delta_base_oid), |
430 | 0 | input_algo->name); |
431 | 0 | return -1; |
432 | 0 | } |
433 | 0 | } |
434 | 0 | if (input_oi->source_infop) |
435 | 0 | *input_oi->source_infop = *new_oi.source_infop; |
436 | 0 | return ret; |
437 | 0 | } |
438 | | |
439 | | enum odb_read_status odb_read_object_info_extended(struct object_database *odb, |
440 | | const struct object_id *oid, |
441 | | struct object_info *oi, |
442 | | enum object_info_flags flags) |
443 | 0 | { |
444 | 0 | enum odb_read_status ret; |
445 | |
|
446 | 0 | if (oid->algo && (hash_algo_by_ptr(odb->repo->hash_algo) != oid->algo)) |
447 | 0 | return oid_object_info_convert(odb->repo, oid, oi, flags); |
448 | | |
449 | 0 | obj_read_lock(); |
450 | 0 | ret = do_oid_object_info_extended(odb, oid, oi, flags); |
451 | 0 | obj_read_unlock(); |
452 | 0 | return ret; |
453 | 0 | } |
454 | | |
455 | | |
456 | | /* returns enum object_type or negative */ |
457 | | int odb_read_object_info(struct object_database *odb, |
458 | | const struct object_id *oid, |
459 | | size_t *sizep) |
460 | 0 | { |
461 | 0 | enum object_type type; |
462 | 0 | struct object_info oi = OBJECT_INFO_INIT; |
463 | |
|
464 | 0 | oi.typep = &type; |
465 | 0 | oi.sizep = sizep; |
466 | 0 | if (odb_read_object_info_extended(odb, oid, &oi, |
467 | 0 | OBJECT_INFO_LOOKUP_REPLACE) < 0) |
468 | 0 | return -1; |
469 | 0 | return type; |
470 | 0 | } |
471 | | |
472 | | int odb_pretend_object(struct object_database *odb, |
473 | | void *buf, size_t len, enum object_type type, |
474 | | struct object_id *oid) |
475 | 0 | { |
476 | 0 | hash_object_file(odb->repo->hash_algo, buf, len, type, oid); |
477 | 0 | if (odb_has_object(odb, oid, 0)) |
478 | 0 | return 0; |
479 | | |
480 | 0 | return odb_source_write_object(odb->inmemory_objects, |
481 | 0 | buf, len, type, oid, NULL, NULL, 0); |
482 | 0 | } |
483 | | |
484 | | void *odb_read_object(struct object_database *odb, |
485 | | const struct object_id *oid, |
486 | | enum object_type *type, |
487 | | size_t *size) |
488 | 0 | { |
489 | 0 | struct object_info oi = OBJECT_INFO_INIT; |
490 | 0 | unsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_LOOKUP_REPLACE; |
491 | 0 | void *data; |
492 | |
|
493 | 0 | oi.typep = type; |
494 | 0 | oi.sizep = size; |
495 | 0 | oi.contentp = &data; |
496 | 0 | if (odb_read_object_info_extended(odb, oid, &oi, flags)) |
497 | 0 | return NULL; |
498 | | |
499 | 0 | return data; |
500 | 0 | } |
501 | | |
502 | | void *odb_read_object_peeled(struct object_database *odb, |
503 | | const struct object_id *oid, |
504 | | enum object_type required_type, |
505 | | size_t *size, |
506 | | struct object_id *actual_oid_return) |
507 | 0 | { |
508 | 0 | enum object_type type; |
509 | 0 | void *buffer; |
510 | 0 | size_t isize; |
511 | 0 | struct object_id actual_oid; |
512 | |
|
513 | 0 | oidcpy(&actual_oid, oid); |
514 | 0 | while (1) { |
515 | 0 | int ref_length = -1; |
516 | 0 | const char *ref_type = NULL; |
517 | |
|
518 | 0 | buffer = odb_read_object(odb, &actual_oid, &type, &isize); |
519 | 0 | if (!buffer) |
520 | 0 | return NULL; |
521 | 0 | if (type == required_type) { |
522 | 0 | *size = isize; |
523 | 0 | if (actual_oid_return) |
524 | 0 | oidcpy(actual_oid_return, &actual_oid); |
525 | 0 | return buffer; |
526 | 0 | } |
527 | | /* Handle references */ |
528 | 0 | else if (type == OBJ_COMMIT) |
529 | 0 | ref_type = "tree "; |
530 | 0 | else if (type == OBJ_TAG) |
531 | 0 | ref_type = "object "; |
532 | 0 | else { |
533 | 0 | free(buffer); |
534 | 0 | return NULL; |
535 | 0 | } |
536 | 0 | ref_length = strlen(ref_type); |
537 | |
|
538 | 0 | if (ref_length + odb->repo->hash_algo->hexsz > isize || |
539 | 0 | memcmp(buffer, ref_type, ref_length) || |
540 | 0 | get_oid_hex_algop((char *) buffer + ref_length, &actual_oid, |
541 | 0 | odb->repo->hash_algo)) { |
542 | 0 | free(buffer); |
543 | 0 | return NULL; |
544 | 0 | } |
545 | 0 | free(buffer); |
546 | | /* Now we have the ID of the referred-to object in |
547 | | * actual_oid. Check again. */ |
548 | 0 | } |
549 | 0 | } |
550 | | |
551 | | int odb_has_object(struct object_database *odb, const struct object_id *oid, |
552 | | enum odb_has_object_flags flags) |
553 | 0 | { |
554 | 0 | unsigned object_info_flags = 0; |
555 | |
|
556 | 0 | if (!startup_info->have_repository) |
557 | 0 | return 0; |
558 | 0 | if (!(flags & ODB_HAS_OBJECT_RECHECK_PACKED)) |
559 | 0 | object_info_flags |= OBJECT_INFO_QUICK; |
560 | 0 | if (!(flags & ODB_HAS_OBJECT_FETCH_PROMISOR)) |
561 | 0 | object_info_flags |= OBJECT_INFO_SKIP_FETCH_OBJECT; |
562 | |
|
563 | 0 | return odb_read_object_info_extended(odb, oid, NULL, object_info_flags) >= 0; |
564 | 0 | } |
565 | | |
566 | | int odb_freshen_object(struct object_database *odb, |
567 | | const struct object_id *oid) |
568 | 0 | { |
569 | 0 | return odb_source_freshen_object(odb->source, oid, NULL); |
570 | 0 | } |
571 | | |
572 | | int odb_for_each_object_ext(struct object_database *odb, |
573 | | const struct object_info *request, |
574 | | odb_for_each_object_cb cb, |
575 | | void *cb_data, |
576 | | const struct odb_for_each_object_options *opts) |
577 | 0 | { |
578 | 0 | return odb_source_for_each_object(odb->source, request, cb, cb_data, opts); |
579 | 0 | } |
580 | | |
581 | | int odb_for_each_object(struct object_database *odb, |
582 | | const struct object_info *request, |
583 | | odb_for_each_object_cb cb, |
584 | | void *cb_data, |
585 | | enum odb_for_each_object_flags flags) |
586 | 0 | { |
587 | 0 | struct odb_for_each_object_options opts = { |
588 | 0 | .flags = flags, |
589 | 0 | }; |
590 | 0 | return odb_for_each_object_ext(odb, request, cb, cb_data, &opts); |
591 | 0 | } |
592 | | |
593 | | int odb_count_objects(struct object_database *odb, |
594 | | enum odb_count_objects_flags flags, |
595 | | unsigned long *out) |
596 | 0 | { |
597 | 0 | unsigned long count = 0; |
598 | 0 | int ret; |
599 | |
|
600 | 0 | if (odb->object_count_valid && odb->object_count_flags == flags) { |
601 | 0 | *out = odb->object_count; |
602 | 0 | return 0; |
603 | 0 | } |
604 | | |
605 | 0 | ret = odb_source_count_objects(odb->source, flags, &count); |
606 | 0 | if (ret < 0) |
607 | 0 | goto out; |
608 | | |
609 | 0 | odb->object_count = count; |
610 | 0 | odb->object_count_valid = 1; |
611 | 0 | odb->object_count_flags = flags; |
612 | |
|
613 | 0 | *out = count; |
614 | 0 | ret = 0; |
615 | |
|
616 | 0 | out: |
617 | 0 | return ret; |
618 | 0 | } |
619 | | |
620 | | /* |
621 | | * Return the slot of the most-significant bit set in "val". There are various |
622 | | * ways to do this quickly with fls() or __builtin_clzl(), but speed is |
623 | | * probably not a big deal here. |
624 | | */ |
625 | | static unsigned msb(unsigned long val) |
626 | 0 | { |
627 | 0 | unsigned r = 0; |
628 | 0 | while (val >>= 1) |
629 | 0 | r++; |
630 | 0 | return r; |
631 | 0 | } |
632 | | |
633 | | int odb_find_abbrev_len(struct object_database *odb, |
634 | | const struct object_id *oid, |
635 | | int min_length, |
636 | | unsigned *out) |
637 | 0 | { |
638 | 0 | const struct git_hash_algo *algo = |
639 | 0 | oid->algo ? &hash_algos[oid->algo] : odb->repo->hash_algo; |
640 | 0 | const unsigned hexsz = algo->hexsz; |
641 | 0 | unsigned len; |
642 | 0 | int ret; |
643 | |
|
644 | 0 | if (min_length < 0) { |
645 | 0 | unsigned long count; |
646 | |
|
647 | 0 | if (odb_count_objects(odb, ODB_COUNT_OBJECTS_APPROXIMATE, &count) < 0) |
648 | 0 | count = 0; |
649 | | |
650 | | /* |
651 | | * Add one because the MSB only tells us the highest bit set, |
652 | | * not including the value of all the _other_ bits (so "15" |
653 | | * is only one off of 2^4, but the MSB is the 3rd bit. |
654 | | */ |
655 | 0 | len = msb(count) + 1; |
656 | | /* |
657 | | * We now know we have on the order of 2^len objects, which |
658 | | * expects a collision at 2^(len/2). But we also care about hex |
659 | | * chars, not bits, and there are 4 bits per hex. So all |
660 | | * together we need to divide by 2 and round up. |
661 | | */ |
662 | 0 | len = DIV_ROUND_UP(len, 2); |
663 | | /* |
664 | | * For very small repos, we stick with our regular fallback. |
665 | | */ |
666 | 0 | if (len < FALLBACK_DEFAULT_ABBREV) |
667 | 0 | len = FALLBACK_DEFAULT_ABBREV; |
668 | 0 | } else { |
669 | 0 | len = min_length; |
670 | 0 | } |
671 | |
|
672 | 0 | if (len >= hexsz || !len) { |
673 | 0 | *out = hexsz; |
674 | 0 | ret = 0; |
675 | 0 | goto out; |
676 | 0 | } |
677 | | |
678 | 0 | ret = odb_source_find_abbrev_len(odb->source, oid, len, &len); |
679 | 0 | *out = len; |
680 | |
|
681 | 0 | out: |
682 | 0 | return ret; |
683 | 0 | } |
684 | | |
685 | | void odb_assert_oid_type(struct object_database *odb, |
686 | | const struct object_id *oid, enum object_type expect) |
687 | 0 | { |
688 | 0 | enum object_type type = odb_read_object_info(odb, oid, NULL); |
689 | 0 | if (type < 0) |
690 | 0 | die(_("%s is not a valid object"), oid_to_hex(oid)); |
691 | 0 | if (type != expect) |
692 | 0 | die(_("%s is not a valid '%s' object"), oid_to_hex(oid), |
693 | 0 | type_name(expect)); |
694 | 0 | } |
695 | | |
696 | | int odb_write_object_ext(struct object_database *odb, |
697 | | const void *buf, unsigned long len, |
698 | | enum object_type type, |
699 | | struct object_id *oid, |
700 | | const struct object_id *compat_oid_in, |
701 | | enum odb_write_object_flags flags) |
702 | 0 | { |
703 | 0 | const struct git_hash_algo *compat = odb->repo->compat_hash_algo; |
704 | 0 | struct object_id compat_oid, *compat_oid_p = NULL; |
705 | |
|
706 | 0 | hash_object_file(odb->repo->hash_algo, buf, len, type, oid); |
707 | | |
708 | | /* |
709 | | * We can skip the write in case we already have the object available. |
710 | | * In that case, we only freshen its mtime. |
711 | | */ |
712 | 0 | if (odb_freshen_object(odb, oid)) |
713 | 0 | return 0; |
714 | | |
715 | 0 | if (compat) { |
716 | 0 | const struct git_hash_algo *algo = odb->repo->hash_algo; |
717 | |
|
718 | 0 | if (compat_oid_in) { |
719 | 0 | oidcpy(&compat_oid, compat_oid_in); |
720 | 0 | } else if (type == OBJ_BLOB) { |
721 | 0 | hash_object_file(compat, buf, len, type, &compat_oid); |
722 | 0 | } else { |
723 | 0 | struct strbuf converted = STRBUF_INIT; |
724 | 0 | convert_object_file(odb->repo, &converted, algo, compat, |
725 | 0 | buf, len, type, 0); |
726 | 0 | hash_object_file(compat, converted.buf, converted.len, |
727 | 0 | type, &compat_oid); |
728 | 0 | strbuf_release(&converted); |
729 | 0 | } |
730 | |
|
731 | 0 | compat_oid_p = &compat_oid; |
732 | 0 | } |
733 | |
|
734 | 0 | return odb_source_write_object(odb->source, buf, len, type, |
735 | 0 | oid, compat_oid_p, NULL, flags); |
736 | 0 | } |
737 | | |
738 | | int odb_write_object_stream(struct object_database *odb, |
739 | | struct odb_stream *stream, |
740 | | struct object_id *oid) |
741 | 0 | { |
742 | 0 | return odb_source_write_object_stream(odb->source, stream, oid); |
743 | 0 | } |
744 | | |
745 | | int odb_optimize(struct object_database *odb, |
746 | | const struct odb_optimize_options *opts) |
747 | 0 | { |
748 | 0 | return odb_source_optimize(odb->source, opts); |
749 | 0 | } |
750 | | |
751 | | bool odb_optimize_required(struct object_database *odb, |
752 | | const struct odb_optimize_options *opts) |
753 | 0 | { |
754 | 0 | return odb_source_optimize_required(odb->source, opts); |
755 | 0 | } |
756 | | |
757 | | void odb_generate_pack_options_release(struct odb_generate_pack_options *opts) |
758 | 0 | { |
759 | 0 | oid_array_clear(&opts->wants); |
760 | 0 | oid_array_clear(&opts->haves); |
761 | 0 | oid_array_clear(&opts->shallows); |
762 | 0 | } |
763 | | |
764 | | int odb_generate_pack(struct object_database *odb, |
765 | | struct odb_pack_generator **out, |
766 | | const struct odb_generate_pack_options *opts) |
767 | 0 | { |
768 | 0 | if (!odb->source->generate_pack) |
769 | 0 | return error(_("primary object source does not support generating packfiles")); |
770 | 0 | return odb_source_generate_pack(odb->source, out, opts); |
771 | 0 | } |
772 | | |
773 | | int odb_pack_generator_finish(struct odb_pack_generator *generator) |
774 | 0 | { |
775 | 0 | return generator->finish(generator); |
776 | 0 | } |
777 | | |
778 | | struct object_database *odb_new(struct repository *repo, |
779 | | enum odb_new_flags flags) |
780 | 0 | { |
781 | 0 | struct object_database *o; |
782 | |
|
783 | 0 | CALLOC_ARRAY(o, 1); |
784 | 0 | o->repo = repo; |
785 | 0 | pthread_mutex_init(&o->replace_mutex, NULL); |
786 | |
|
787 | 0 | o->source = odb_source_new(o, repo->object_storage_format, |
788 | 0 | repo->object_storage_payload, flags); |
789 | 0 | o->inmemory_objects = &odb_source_inmemory_new(o)->base; |
790 | |
|
791 | 0 | return o; |
792 | 0 | } |
793 | | |
794 | | void odb_close(struct object_database *o) |
795 | 0 | { |
796 | 0 | odb_source_close(o->source); |
797 | 0 | close_commit_graph(o); |
798 | 0 | } |
799 | | |
800 | | static void odb_free_sources(struct object_database *o) |
801 | 0 | { |
802 | 0 | odb_source_free(o->source); |
803 | 0 | odb_source_free(o->inmemory_objects); |
804 | 0 | o->inmemory_objects = NULL; |
805 | 0 | } |
806 | | |
807 | | void odb_free(struct object_database *o) |
808 | 566 | { |
809 | 566 | if (!o) |
810 | 566 | return; |
811 | | |
812 | 0 | oidmap_clear(&o->replace_map, 1); |
813 | 0 | pthread_mutex_destroy(&o->replace_mutex); |
814 | |
|
815 | 0 | odb_close(o); |
816 | 0 | odb_free_sources(o); |
817 | |
|
818 | 0 | free(o); |
819 | 0 | } |
820 | | |
821 | | void odb_prepare(struct object_database *o, enum odb_prepare_flags flags) |
822 | 0 | { |
823 | 0 | obj_read_lock(); |
824 | |
|
825 | 0 | if (flags & ODB_PREPARE_FLUSH_CACHES) |
826 | 0 | o->object_count_valid = 0; |
827 | |
|
828 | 0 | odb_source_prepare(o->source, flags); |
829 | |
|
830 | 0 | obj_read_unlock(); |
831 | 0 | } |
832 | | |
833 | | void odb_reprepare(struct object_database *o) |
834 | 0 | { |
835 | 0 | odb_prepare(o, ODB_PREPARE_FLUSH_CACHES); |
836 | 0 | } |
837 | | |
838 | | int odb_fsck(struct object_database *odb, struct odb_fsck_options *options) |
839 | 0 | { |
840 | 0 | return odb_source_fsck(odb->source, options); |
841 | 0 | } |