Line | Count | Source |
1 | | #include "git-compat-util.h" |
2 | | #include "abspath.h" |
3 | | #include "chdir-notify.h" |
4 | | #include "commit-graph.h" |
5 | | #include "config.h" |
6 | | #include "dir.h" |
7 | | #include "environment.h" |
8 | | #include "gettext.h" |
9 | | #include "hex.h" |
10 | | #include "khash.h" |
11 | | #include "lockfile.h" |
12 | | #include "loose.h" |
13 | | #include "midx.h" |
14 | | #include "object-file-convert.h" |
15 | | #include "object-file.h" |
16 | | #include "odb.h" |
17 | | #include "packfile.h" |
18 | | #include "path.h" |
19 | | #include "promisor-remote.h" |
20 | | #include "quote.h" |
21 | | #include "replace-object.h" |
22 | | #include "run-command.h" |
23 | | #include "setup.h" |
24 | | #include "strbuf.h" |
25 | | #include "strvec.h" |
26 | | #include "submodule.h" |
27 | | #include "tmp-objdir.h" |
28 | | #include "trace2.h" |
29 | | #include "write-or-die.h" |
30 | | |
31 | 0 | KHASH_INIT(odb_path_map, const char * /* key: odb_path */, |
32 | 0 | struct odb_source *, 1, fspathhash, fspatheq) |
33 | 0 |
|
34 | 0 | /* |
35 | 0 | * This is meant to hold a *small* number of objects that you would |
36 | 0 | * want odb_read_object() to be able to return, but yet you do not want |
37 | 0 | * to write them into the object store (e.g. a browse-only |
38 | 0 | * application). |
39 | 0 | */ |
40 | 0 | struct cached_object_entry { |
41 | 0 | struct object_id oid; |
42 | 0 | struct cached_object { |
43 | 0 | enum object_type type; |
44 | 0 | const void *buf; |
45 | 0 | unsigned long size; |
46 | 0 | } value; |
47 | 0 | }; |
48 | 0 |
|
49 | 0 | static const struct cached_object *find_cached_object(struct object_database *object_store, |
50 | 0 | const struct object_id *oid) |
51 | 0 | { |
52 | 0 | static const struct cached_object empty_tree = { |
53 | 0 | .type = OBJ_TREE, |
54 | 0 | .buf = "", |
55 | 0 | }; |
56 | 0 | const struct cached_object_entry *co = object_store->cached_objects; |
57 | |
|
58 | 0 | for (size_t i = 0; i < object_store->cached_object_nr; i++, co++) |
59 | 0 | if (oideq(&co->oid, oid)) |
60 | 0 | return &co->value; |
61 | | |
62 | 0 | if (oid->algo && oideq(oid, hash_algos[oid->algo].empty_tree)) |
63 | 0 | return &empty_tree; |
64 | | |
65 | 0 | return NULL; |
66 | 0 | } |
67 | | |
68 | | int odb_mkstemp(struct object_database *odb, |
69 | | struct strbuf *temp_filename, const char *pattern) |
70 | 0 | { |
71 | 0 | int fd; |
72 | | /* |
73 | | * we let the umask do its job, don't try to be more |
74 | | * restrictive except to remove write permission. |
75 | | */ |
76 | 0 | int mode = 0444; |
77 | 0 | repo_git_path_replace(odb->repo, temp_filename, "objects/%s", pattern); |
78 | 0 | fd = git_mkstemp_mode(temp_filename->buf, mode); |
79 | 0 | if (0 <= fd) |
80 | 0 | return fd; |
81 | | |
82 | | /* slow path */ |
83 | | /* some mkstemp implementations erase temp_filename on failure */ |
84 | 0 | repo_git_path_replace(odb->repo, temp_filename, "objects/%s", pattern); |
85 | 0 | safe_create_leading_directories(odb->repo, temp_filename->buf); |
86 | 0 | return xmkstemp_mode(temp_filename->buf, mode); |
87 | 0 | } |
88 | | |
89 | | /* |
90 | | * Return non-zero iff the path is usable as an alternate object database. |
91 | | */ |
92 | | static bool odb_is_source_usable(struct object_database *o, const char *path) |
93 | 0 | { |
94 | 0 | int r; |
95 | 0 | struct strbuf normalized_objdir = STRBUF_INIT; |
96 | 0 | bool usable = false; |
97 | |
|
98 | 0 | strbuf_realpath(&normalized_objdir, o->sources->path, 1); |
99 | | |
100 | | /* Detect cases where alternate disappeared */ |
101 | 0 | if (!is_directory(path)) { |
102 | 0 | error(_("object directory %s does not exist; " |
103 | 0 | "check .git/objects/info/alternates"), |
104 | 0 | path); |
105 | 0 | goto out; |
106 | 0 | } |
107 | | |
108 | | /* |
109 | | * Prevent the common mistake of listing the same |
110 | | * thing twice, or object directory itself. |
111 | | */ |
112 | 0 | if (!o->source_by_path) { |
113 | 0 | khiter_t p; |
114 | |
|
115 | 0 | o->source_by_path = kh_init_odb_path_map(); |
116 | 0 | assert(!o->sources->next); |
117 | 0 | p = kh_put_odb_path_map(o->source_by_path, o->sources->path, &r); |
118 | 0 | assert(r == 1); /* never used */ |
119 | 0 | kh_value(o->source_by_path, p) = o->sources; |
120 | 0 | } |
121 | |
|
122 | 0 | if (fspatheq(path, normalized_objdir.buf)) |
123 | 0 | goto out; |
124 | | |
125 | 0 | if (kh_get_odb_path_map(o->source_by_path, path) < kh_end(o->source_by_path)) |
126 | 0 | goto out; |
127 | | |
128 | 0 | usable = true; |
129 | |
|
130 | 0 | out: |
131 | 0 | strbuf_release(&normalized_objdir); |
132 | 0 | return usable; |
133 | 0 | } |
134 | | |
135 | | static void parse_alternates(const char *string, |
136 | | int sep, |
137 | | const char *relative_base, |
138 | | struct strvec *out) |
139 | 0 | { |
140 | 0 | struct strbuf pathbuf = STRBUF_INIT; |
141 | 0 | struct strbuf buf = STRBUF_INIT; |
142 | |
|
143 | 0 | if (!string || !*string) |
144 | 0 | return; |
145 | | |
146 | 0 | while (*string) { |
147 | 0 | const char *end; |
148 | |
|
149 | 0 | strbuf_reset(&buf); |
150 | 0 | strbuf_reset(&pathbuf); |
151 | |
|
152 | 0 | if (*string == '#') { |
153 | | /* comment; consume up to next separator */ |
154 | 0 | end = strchrnul(string, sep); |
155 | 0 | } else if (*string == '"' && !unquote_c_style(&buf, string, &end)) { |
156 | | /* |
157 | | * quoted path; unquote_c_style has copied the |
158 | | * data for us and set "end". Broken quoting (e.g., |
159 | | * an entry that doesn't end with a quote) falls |
160 | | * back to the unquoted case below. |
161 | | */ |
162 | 0 | } else { |
163 | | /* normal, unquoted path */ |
164 | 0 | end = strchrnul(string, sep); |
165 | 0 | strbuf_add(&buf, string, end - string); |
166 | 0 | } |
167 | |
|
168 | 0 | if (*end) |
169 | 0 | end++; |
170 | 0 | string = end; |
171 | |
|
172 | 0 | if (!buf.len) |
173 | 0 | continue; |
174 | | |
175 | 0 | if (!is_absolute_path(buf.buf) && relative_base) { |
176 | 0 | strbuf_realpath(&pathbuf, relative_base, 1); |
177 | 0 | strbuf_addch(&pathbuf, '/'); |
178 | 0 | } |
179 | 0 | strbuf_addbuf(&pathbuf, &buf); |
180 | |
|
181 | 0 | strbuf_reset(&buf); |
182 | 0 | if (!strbuf_realpath(&buf, pathbuf.buf, 0)) { |
183 | 0 | error(_("unable to normalize alternate object path: %s"), |
184 | 0 | pathbuf.buf); |
185 | 0 | continue; |
186 | 0 | } |
187 | | |
188 | | /* |
189 | | * The trailing slash after the directory name is given by |
190 | | * this function at the end. Remove duplicates. |
191 | | */ |
192 | 0 | while (buf.len && buf.buf[buf.len - 1] == '/') |
193 | 0 | strbuf_setlen(&buf, buf.len - 1); |
194 | |
|
195 | 0 | strvec_push(out, buf.buf); |
196 | 0 | } |
197 | |
|
198 | 0 | strbuf_release(&pathbuf); |
199 | 0 | strbuf_release(&buf); |
200 | 0 | } |
201 | | |
202 | | static void odb_source_read_alternates(struct odb_source *source, |
203 | | struct strvec *out) |
204 | 0 | { |
205 | 0 | struct strbuf buf = STRBUF_INIT; |
206 | 0 | char *path; |
207 | |
|
208 | 0 | path = xstrfmt("%s/info/alternates", source->path); |
209 | 0 | if (strbuf_read_file(&buf, path, 1024) < 0) { |
210 | 0 | warn_on_fopen_errors(path); |
211 | 0 | free(path); |
212 | 0 | return; |
213 | 0 | } |
214 | 0 | parse_alternates(buf.buf, '\n', source->path, out); |
215 | |
|
216 | 0 | strbuf_release(&buf); |
217 | 0 | free(path); |
218 | 0 | } |
219 | | |
220 | | |
221 | | static struct odb_source *odb_source_new(struct object_database *odb, |
222 | | const char *path, |
223 | | bool local) |
224 | 0 | { |
225 | 0 | struct odb_source *source; |
226 | |
|
227 | 0 | CALLOC_ARRAY(source, 1); |
228 | 0 | source->odb = odb; |
229 | 0 | source->local = local; |
230 | 0 | source->path = xstrdup(path); |
231 | 0 | source->loose = odb_source_loose_new(source); |
232 | |
|
233 | 0 | return source; |
234 | 0 | } |
235 | | |
236 | | static struct odb_source *odb_add_alternate_recursively(struct object_database *odb, |
237 | | const char *source, |
238 | | int depth) |
239 | 0 | { |
240 | 0 | struct odb_source *alternate = NULL; |
241 | 0 | struct strvec sources = STRVEC_INIT; |
242 | 0 | khiter_t pos; |
243 | 0 | int ret; |
244 | |
|
245 | 0 | if (!odb_is_source_usable(odb, source)) |
246 | 0 | goto error; |
247 | | |
248 | 0 | alternate = odb_source_new(odb, source, false); |
249 | | |
250 | | /* add the alternate entry */ |
251 | 0 | *odb->sources_tail = alternate; |
252 | 0 | odb->sources_tail = &(alternate->next); |
253 | |
|
254 | 0 | pos = kh_put_odb_path_map(odb->source_by_path, alternate->path, &ret); |
255 | 0 | if (!ret) |
256 | 0 | BUG("source must not yet exist"); |
257 | 0 | kh_value(odb->source_by_path, pos) = alternate; |
258 | | |
259 | | /* recursively add alternates */ |
260 | 0 | odb_source_read_alternates(alternate, &sources); |
261 | 0 | if (sources.nr && depth + 1 > 5) { |
262 | 0 | error(_("%s: ignoring alternate object stores, nesting too deep"), |
263 | 0 | source); |
264 | 0 | } else { |
265 | 0 | for (size_t i = 0; i < sources.nr; i++) |
266 | 0 | odb_add_alternate_recursively(odb, sources.v[i], depth + 1); |
267 | 0 | } |
268 | |
|
269 | 0 | error: |
270 | 0 | strvec_clear(&sources); |
271 | 0 | return alternate; |
272 | 0 | } |
273 | | |
274 | | static int odb_source_write_alternate(struct odb_source *source, |
275 | | const char *alternate) |
276 | 0 | { |
277 | 0 | struct lock_file lock = LOCK_INIT; |
278 | 0 | char *path = xstrfmt("%s/%s", source->path, "info/alternates"); |
279 | 0 | FILE *in, *out; |
280 | 0 | int found = 0; |
281 | 0 | int ret; |
282 | |
|
283 | 0 | hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR); |
284 | 0 | out = fdopen_lock_file(&lock, "w"); |
285 | 0 | if (!out) { |
286 | 0 | ret = error_errno(_("unable to fdopen alternates lockfile")); |
287 | 0 | goto out; |
288 | 0 | } |
289 | | |
290 | 0 | in = fopen(path, "r"); |
291 | 0 | if (in) { |
292 | 0 | struct strbuf line = STRBUF_INIT; |
293 | |
|
294 | 0 | while (strbuf_getline(&line, in) != EOF) { |
295 | 0 | if (!strcmp(alternate, line.buf)) { |
296 | 0 | found = 1; |
297 | 0 | break; |
298 | 0 | } |
299 | 0 | fprintf_or_die(out, "%s\n", line.buf); |
300 | 0 | } |
301 | |
|
302 | 0 | strbuf_release(&line); |
303 | 0 | fclose(in); |
304 | 0 | } else if (errno != ENOENT) { |
305 | 0 | ret = error_errno(_("unable to read alternates file")); |
306 | 0 | goto out; |
307 | 0 | } |
308 | | |
309 | 0 | if (found) { |
310 | 0 | rollback_lock_file(&lock); |
311 | 0 | } else { |
312 | 0 | fprintf_or_die(out, "%s\n", alternate); |
313 | 0 | if (commit_lock_file(&lock)) { |
314 | 0 | ret = error_errno(_("unable to move new alternates file into place")); |
315 | 0 | goto out; |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | 0 | ret = 0; |
320 | |
|
321 | 0 | out: |
322 | 0 | free(path); |
323 | 0 | return ret; |
324 | 0 | } |
325 | | |
326 | | void odb_add_to_alternates_file(struct object_database *odb, |
327 | | const char *dir) |
328 | 0 | { |
329 | 0 | int ret = odb_source_write_alternate(odb->sources, dir); |
330 | 0 | if (ret < 0) |
331 | 0 | die(NULL); |
332 | 0 | if (odb->loaded_alternates) |
333 | 0 | odb_add_alternate_recursively(odb, dir, 0); |
334 | 0 | } |
335 | | |
336 | | struct odb_source *odb_add_to_alternates_memory(struct object_database *odb, |
337 | | const char *dir) |
338 | 0 | { |
339 | | /* |
340 | | * Make sure alternates are initialized, or else our entry may be |
341 | | * overwritten when they are. |
342 | | */ |
343 | 0 | odb_prepare_alternates(odb); |
344 | 0 | return odb_add_alternate_recursively(odb, dir, 0); |
345 | 0 | } |
346 | | |
347 | | struct odb_source *odb_set_temporary_primary_source(struct object_database *odb, |
348 | | const char *dir, int will_destroy) |
349 | 0 | { |
350 | 0 | struct odb_source *source; |
351 | | |
352 | | /* |
353 | | * Make sure alternates are initialized, or else our entry may be |
354 | | * overwritten when they are. |
355 | | */ |
356 | 0 | odb_prepare_alternates(odb); |
357 | | |
358 | | /* |
359 | | * Make a new primary odb and link the old primary ODB in as an |
360 | | * alternate |
361 | | */ |
362 | 0 | source = odb_source_new(odb, dir, false); |
363 | | |
364 | | /* |
365 | | * Disable ref updates while a temporary odb is active, since |
366 | | * the objects in the database may roll back. |
367 | | */ |
368 | 0 | odb->repo->disable_ref_updates = true; |
369 | 0 | source->will_destroy = will_destroy; |
370 | 0 | source->next = odb->sources; |
371 | 0 | odb->sources = source; |
372 | 0 | return source->next; |
373 | 0 | } |
374 | | |
375 | | static void odb_source_free(struct odb_source *source) |
376 | 0 | { |
377 | 0 | free(source->path); |
378 | 0 | odb_source_loose_free(source->loose); |
379 | 0 | free(source); |
380 | 0 | } |
381 | | |
382 | | void odb_restore_primary_source(struct object_database *odb, |
383 | | struct odb_source *restore_source, |
384 | | const char *old_path) |
385 | 0 | { |
386 | 0 | struct odb_source *cur_source = odb->sources; |
387 | |
|
388 | 0 | if (strcmp(old_path, cur_source->path)) |
389 | 0 | BUG("expected %s as primary object store; found %s", |
390 | 0 | old_path, cur_source->path); |
391 | | |
392 | 0 | if (cur_source->next != restore_source) |
393 | 0 | BUG("we expect the old primary object store to be the first alternate"); |
394 | | |
395 | 0 | odb->repo->disable_ref_updates = false; |
396 | 0 | odb->sources = restore_source; |
397 | 0 | odb_source_free(cur_source); |
398 | 0 | } |
399 | | |
400 | | char *compute_alternate_path(const char *path, struct strbuf *err) |
401 | 0 | { |
402 | 0 | char *ref_git = NULL; |
403 | 0 | const char *repo; |
404 | 0 | int seen_error = 0; |
405 | |
|
406 | 0 | ref_git = real_pathdup(path, 0); |
407 | 0 | if (!ref_git) { |
408 | 0 | seen_error = 1; |
409 | 0 | strbuf_addf(err, _("path '%s' does not exist"), path); |
410 | 0 | goto out; |
411 | 0 | } |
412 | | |
413 | 0 | repo = read_gitfile(ref_git); |
414 | 0 | if (!repo) |
415 | 0 | repo = read_gitfile(mkpath("%s/.git", ref_git)); |
416 | 0 | if (repo) { |
417 | 0 | free(ref_git); |
418 | 0 | ref_git = xstrdup(repo); |
419 | 0 | } |
420 | |
|
421 | 0 | if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) { |
422 | 0 | char *ref_git_git = mkpathdup("%s/.git", ref_git); |
423 | 0 | free(ref_git); |
424 | 0 | ref_git = ref_git_git; |
425 | 0 | } else if (!is_directory(mkpath("%s/objects", ref_git))) { |
426 | 0 | struct strbuf sb = STRBUF_INIT; |
427 | 0 | seen_error = 1; |
428 | 0 | if (get_common_dir(&sb, ref_git)) { |
429 | 0 | strbuf_addf(err, |
430 | 0 | _("reference repository '%s' as a linked " |
431 | 0 | "checkout is not supported yet."), |
432 | 0 | path); |
433 | 0 | goto out; |
434 | 0 | } |
435 | | |
436 | 0 | strbuf_addf(err, _("reference repository '%s' is not a " |
437 | 0 | "local repository."), path); |
438 | 0 | goto out; |
439 | 0 | } |
440 | | |
441 | 0 | if (!access(mkpath("%s/shallow", ref_git), F_OK)) { |
442 | 0 | strbuf_addf(err, _("reference repository '%s' is shallow"), |
443 | 0 | path); |
444 | 0 | seen_error = 1; |
445 | 0 | goto out; |
446 | 0 | } |
447 | | |
448 | 0 | if (!access(mkpath("%s/info/grafts", ref_git), F_OK)) { |
449 | 0 | strbuf_addf(err, |
450 | 0 | _("reference repository '%s' is grafted"), |
451 | 0 | path); |
452 | 0 | seen_error = 1; |
453 | 0 | goto out; |
454 | 0 | } |
455 | | |
456 | 0 | out: |
457 | 0 | if (seen_error) { |
458 | 0 | FREE_AND_NULL(ref_git); |
459 | 0 | } |
460 | |
|
461 | 0 | return ref_git; |
462 | 0 | } |
463 | | |
464 | | struct odb_source *odb_find_source(struct object_database *odb, const char *obj_dir) |
465 | 0 | { |
466 | 0 | struct odb_source *source; |
467 | 0 | char *obj_dir_real = real_pathdup(obj_dir, 1); |
468 | 0 | struct strbuf odb_path_real = STRBUF_INIT; |
469 | |
|
470 | 0 | odb_prepare_alternates(odb); |
471 | 0 | for (source = odb->sources; source; source = source->next) { |
472 | 0 | strbuf_realpath(&odb_path_real, source->path, 1); |
473 | 0 | if (!strcmp(obj_dir_real, odb_path_real.buf)) |
474 | 0 | break; |
475 | 0 | } |
476 | |
|
477 | 0 | free(obj_dir_real); |
478 | 0 | strbuf_release(&odb_path_real); |
479 | |
|
480 | 0 | return source; |
481 | 0 | } |
482 | | |
483 | | struct odb_source *odb_find_source_or_die(struct object_database *odb, const char *obj_dir) |
484 | 0 | { |
485 | 0 | struct odb_source *source = odb_find_source(odb, obj_dir); |
486 | 0 | if (!source) |
487 | 0 | die(_("could not find object directory matching %s"), obj_dir); |
488 | 0 | return source; |
489 | 0 | } |
490 | | |
491 | | void odb_add_submodule_source_by_path(struct object_database *odb, |
492 | | const char *path) |
493 | 0 | { |
494 | 0 | string_list_insert(&odb->submodule_source_paths, path); |
495 | 0 | } |
496 | | |
497 | | static void fill_alternate_refs_command(struct repository *repo, |
498 | | struct child_process *cmd, |
499 | | const char *repo_path) |
500 | 0 | { |
501 | 0 | const char *value; |
502 | |
|
503 | 0 | if (!repo_config_get_value(repo, "core.alternateRefsCommand", &value)) { |
504 | 0 | cmd->use_shell = 1; |
505 | |
|
506 | 0 | strvec_push(&cmd->args, value); |
507 | 0 | strvec_push(&cmd->args, repo_path); |
508 | 0 | } else { |
509 | 0 | cmd->git_cmd = 1; |
510 | |
|
511 | 0 | strvec_pushf(&cmd->args, "--git-dir=%s", repo_path); |
512 | 0 | strvec_push(&cmd->args, "for-each-ref"); |
513 | 0 | strvec_push(&cmd->args, "--format=%(objectname)"); |
514 | |
|
515 | 0 | if (!repo_config_get_value(repo, "core.alternateRefsPrefixes", &value)) { |
516 | 0 | strvec_push(&cmd->args, "--"); |
517 | 0 | strvec_split(&cmd->args, value); |
518 | 0 | } |
519 | 0 | } |
520 | |
|
521 | 0 | strvec_pushv(&cmd->env, (const char **)local_repo_env); |
522 | 0 | cmd->out = -1; |
523 | 0 | } |
524 | | |
525 | | static void read_alternate_refs(struct repository *repo, |
526 | | const char *path, |
527 | | odb_for_each_alternate_ref_fn *cb, |
528 | | void *payload) |
529 | 0 | { |
530 | 0 | struct child_process cmd = CHILD_PROCESS_INIT; |
531 | 0 | struct strbuf line = STRBUF_INIT; |
532 | 0 | FILE *fh; |
533 | |
|
534 | 0 | fill_alternate_refs_command(repo, &cmd, path); |
535 | |
|
536 | 0 | if (start_command(&cmd)) |
537 | 0 | return; |
538 | | |
539 | 0 | fh = xfdopen(cmd.out, "r"); |
540 | 0 | while (strbuf_getline_lf(&line, fh) != EOF) { |
541 | 0 | struct object_id oid; |
542 | 0 | const char *p; |
543 | |
|
544 | 0 | if (parse_oid_hex_algop(line.buf, &oid, &p, repo->hash_algo) || *p) { |
545 | 0 | warning(_("invalid line while parsing alternate refs: %s"), |
546 | 0 | line.buf); |
547 | 0 | break; |
548 | 0 | } |
549 | | |
550 | 0 | cb(&oid, payload); |
551 | 0 | } |
552 | |
|
553 | 0 | fclose(fh); |
554 | 0 | finish_command(&cmd); |
555 | 0 | strbuf_release(&line); |
556 | 0 | } |
557 | | |
558 | | struct alternate_refs_data { |
559 | | odb_for_each_alternate_ref_fn *fn; |
560 | | void *payload; |
561 | | }; |
562 | | |
563 | | static int refs_from_alternate_cb(struct odb_source *alternate, |
564 | | void *payload) |
565 | 0 | { |
566 | 0 | struct strbuf path = STRBUF_INIT; |
567 | 0 | size_t base_len; |
568 | 0 | struct alternate_refs_data *cb = payload; |
569 | |
|
570 | 0 | if (!strbuf_realpath(&path, alternate->path, 0)) |
571 | 0 | goto out; |
572 | 0 | if (!strbuf_strip_suffix(&path, "/objects")) |
573 | 0 | goto out; |
574 | 0 | base_len = path.len; |
575 | | |
576 | | /* Is this a git repository with refs? */ |
577 | 0 | strbuf_addstr(&path, "/refs"); |
578 | 0 | if (!is_directory(path.buf)) |
579 | 0 | goto out; |
580 | 0 | strbuf_setlen(&path, base_len); |
581 | |
|
582 | 0 | read_alternate_refs(alternate->odb->repo, path.buf, cb->fn, cb->payload); |
583 | |
|
584 | 0 | out: |
585 | 0 | strbuf_release(&path); |
586 | 0 | return 0; |
587 | 0 | } |
588 | | |
589 | | void odb_for_each_alternate_ref(struct object_database *odb, |
590 | | odb_for_each_alternate_ref_fn cb, void *payload) |
591 | 0 | { |
592 | 0 | struct alternate_refs_data data; |
593 | 0 | data.fn = cb; |
594 | 0 | data.payload = payload; |
595 | 0 | odb_for_each_alternate(odb, refs_from_alternate_cb, &data); |
596 | 0 | } |
597 | | |
598 | | int odb_for_each_alternate(struct object_database *odb, |
599 | | odb_for_each_alternate_fn cb, void *payload) |
600 | 0 | { |
601 | 0 | struct odb_source *alternate; |
602 | 0 | int r = 0; |
603 | |
|
604 | 0 | odb_prepare_alternates(odb); |
605 | 0 | for (alternate = odb->sources->next; alternate; alternate = alternate->next) { |
606 | 0 | r = cb(alternate, payload); |
607 | 0 | if (r) |
608 | 0 | break; |
609 | 0 | } |
610 | 0 | return r; |
611 | 0 | } |
612 | | |
613 | | void odb_prepare_alternates(struct object_database *odb) |
614 | 0 | { |
615 | 0 | struct strvec sources = STRVEC_INIT; |
616 | |
|
617 | 0 | if (odb->loaded_alternates) |
618 | 0 | return; |
619 | | |
620 | 0 | parse_alternates(odb->alternate_db, PATH_SEP, NULL, &sources); |
621 | 0 | odb_source_read_alternates(odb->sources, &sources); |
622 | 0 | for (size_t i = 0; i < sources.nr; i++) |
623 | 0 | odb_add_alternate_recursively(odb, sources.v[i], 0); |
624 | |
|
625 | 0 | odb->loaded_alternates = 1; |
626 | |
|
627 | 0 | strvec_clear(&sources); |
628 | 0 | } |
629 | | |
630 | | int odb_has_alternates(struct object_database *odb) |
631 | 0 | { |
632 | 0 | odb_prepare_alternates(odb); |
633 | 0 | return !!odb->sources->next; |
634 | 0 | } |
635 | | |
636 | | int obj_read_use_lock = 0; |
637 | | pthread_mutex_t obj_read_mutex; |
638 | | |
639 | | void enable_obj_read_lock(void) |
640 | 0 | { |
641 | 0 | if (obj_read_use_lock) |
642 | 0 | return; |
643 | | |
644 | 0 | obj_read_use_lock = 1; |
645 | 0 | init_recursive_mutex(&obj_read_mutex); |
646 | 0 | } |
647 | | |
648 | | void disable_obj_read_lock(void) |
649 | 0 | { |
650 | 0 | if (!obj_read_use_lock) |
651 | 0 | return; |
652 | | |
653 | 0 | obj_read_use_lock = 0; |
654 | 0 | pthread_mutex_destroy(&obj_read_mutex); |
655 | 0 | } |
656 | | |
657 | | int fetch_if_missing = 1; |
658 | | |
659 | | static int register_all_submodule_sources(struct object_database *odb) |
660 | 0 | { |
661 | 0 | int ret = odb->submodule_source_paths.nr; |
662 | |
|
663 | 0 | for (size_t i = 0; i < odb->submodule_source_paths.nr; i++) |
664 | 0 | odb_add_to_alternates_memory(odb, |
665 | 0 | odb->submodule_source_paths.items[i].string); |
666 | 0 | if (ret) { |
667 | 0 | string_list_clear(&odb->submodule_source_paths, 0); |
668 | 0 | trace2_data_intmax("submodule", odb->repo, |
669 | 0 | "register_all_submodule_sources/registered", ret); |
670 | 0 | if (git_env_bool("GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB", 0)) |
671 | 0 | BUG("register_all_submodule_sources() called"); |
672 | 0 | } |
673 | 0 | return ret; |
674 | 0 | } |
675 | | |
676 | | static int do_oid_object_info_extended(struct object_database *odb, |
677 | | const struct object_id *oid, |
678 | | struct object_info *oi, unsigned flags) |
679 | 0 | { |
680 | 0 | const struct cached_object *co; |
681 | 0 | const struct object_id *real = oid; |
682 | 0 | int already_retried = 0; |
683 | |
|
684 | 0 | if (flags & OBJECT_INFO_LOOKUP_REPLACE) |
685 | 0 | real = lookup_replace_object(odb->repo, oid); |
686 | |
|
687 | 0 | if (is_null_oid(real)) |
688 | 0 | return -1; |
689 | | |
690 | 0 | co = find_cached_object(odb, real); |
691 | 0 | if (co) { |
692 | 0 | if (oi) { |
693 | 0 | if (oi->typep) |
694 | 0 | *(oi->typep) = co->type; |
695 | 0 | if (oi->sizep) |
696 | 0 | *(oi->sizep) = co->size; |
697 | 0 | if (oi->disk_sizep) |
698 | 0 | *(oi->disk_sizep) = 0; |
699 | 0 | if (oi->delta_base_oid) |
700 | 0 | oidclr(oi->delta_base_oid, odb->repo->hash_algo); |
701 | 0 | if (oi->contentp) |
702 | 0 | *oi->contentp = xmemdupz(co->buf, co->size); |
703 | 0 | oi->whence = OI_CACHED; |
704 | 0 | } |
705 | 0 | return 0; |
706 | 0 | } |
707 | | |
708 | 0 | odb_prepare_alternates(odb); |
709 | |
|
710 | 0 | while (1) { |
711 | 0 | struct odb_source *source; |
712 | |
|
713 | 0 | if (!packfile_store_read_object_info(odb->packfiles, real, oi, flags)) |
714 | 0 | return 0; |
715 | | |
716 | | /* Most likely it's a loose object. */ |
717 | 0 | for (source = odb->sources; source; source = source->next) |
718 | 0 | if (!odb_source_loose_read_object_info(source, real, oi, flags)) |
719 | 0 | return 0; |
720 | | |
721 | | /* Not a loose object; someone else may have just packed it. */ |
722 | 0 | if (!(flags & OBJECT_INFO_QUICK)) { |
723 | 0 | odb_reprepare(odb->repo->objects); |
724 | 0 | if (!packfile_store_read_object_info(odb->packfiles, real, oi, flags)) |
725 | 0 | return 0; |
726 | 0 | } |
727 | | |
728 | | /* |
729 | | * This might be an attempt at accessing a submodule object as |
730 | | * if it were in main object store (having called |
731 | | * `odb_add_submodule_source_by_path()` on that submodule's |
732 | | * ODB). If any such ODBs exist, register them and try again. |
733 | | */ |
734 | 0 | if (register_all_submodule_sources(odb)) |
735 | | /* We added some alternates; retry */ |
736 | 0 | continue; |
737 | | |
738 | | /* Check if it is a missing object */ |
739 | 0 | if (fetch_if_missing && repo_has_promisor_remote(odb->repo) && |
740 | 0 | !already_retried && |
741 | 0 | !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) { |
742 | 0 | promisor_remote_get_direct(odb->repo, real, 1); |
743 | 0 | already_retried = 1; |
744 | 0 | continue; |
745 | 0 | } |
746 | | |
747 | 0 | if (flags & OBJECT_INFO_DIE_IF_CORRUPT) { |
748 | 0 | const struct packed_git *p; |
749 | 0 | if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid)) |
750 | 0 | die(_("replacement %s not found for %s"), |
751 | 0 | oid_to_hex(real), oid_to_hex(oid)); |
752 | 0 | if ((p = has_packed_and_bad(odb->repo, real))) |
753 | 0 | die(_("packed object %s (stored in %s) is corrupt"), |
754 | 0 | oid_to_hex(real), p->pack_name); |
755 | 0 | } |
756 | 0 | return -1; |
757 | 0 | } |
758 | 0 | } |
759 | | |
760 | | static int oid_object_info_convert(struct repository *r, |
761 | | const struct object_id *input_oid, |
762 | | struct object_info *input_oi, unsigned flags) |
763 | 0 | { |
764 | 0 | const struct git_hash_algo *input_algo = &hash_algos[input_oid->algo]; |
765 | 0 | int do_die = flags & OBJECT_INFO_DIE_IF_CORRUPT; |
766 | 0 | enum object_type type; |
767 | 0 | struct object_id oid, delta_base_oid; |
768 | 0 | struct object_info new_oi, *oi; |
769 | 0 | unsigned long size; |
770 | 0 | void *content; |
771 | 0 | int ret; |
772 | |
|
773 | 0 | if (repo_oid_to_algop(r, input_oid, r->hash_algo, &oid)) { |
774 | 0 | if (do_die) |
775 | 0 | die(_("missing mapping of %s to %s"), |
776 | 0 | oid_to_hex(input_oid), r->hash_algo->name); |
777 | 0 | return -1; |
778 | 0 | } |
779 | | |
780 | | /* Is new_oi needed? */ |
781 | 0 | oi = input_oi; |
782 | 0 | if (input_oi && (input_oi->delta_base_oid || input_oi->sizep || |
783 | 0 | input_oi->contentp)) { |
784 | 0 | new_oi = *input_oi; |
785 | | /* Does delta_base_oid need to be converted? */ |
786 | 0 | if (input_oi->delta_base_oid) |
787 | 0 | new_oi.delta_base_oid = &delta_base_oid; |
788 | | /* Will the attributes differ when converted? */ |
789 | 0 | if (input_oi->sizep || input_oi->contentp) { |
790 | 0 | new_oi.contentp = &content; |
791 | 0 | new_oi.sizep = &size; |
792 | 0 | new_oi.typep = &type; |
793 | 0 | } |
794 | 0 | oi = &new_oi; |
795 | 0 | } |
796 | |
|
797 | 0 | ret = odb_read_object_info_extended(r->objects, &oid, oi, flags); |
798 | 0 | if (ret) |
799 | 0 | return -1; |
800 | 0 | if (oi == input_oi) |
801 | 0 | return ret; |
802 | | |
803 | 0 | if (new_oi.contentp) { |
804 | 0 | struct strbuf outbuf = STRBUF_INIT; |
805 | |
|
806 | 0 | if (type != OBJ_BLOB) { |
807 | 0 | ret = convert_object_file(r, &outbuf, |
808 | 0 | r->hash_algo, input_algo, |
809 | 0 | content, size, type, !do_die); |
810 | 0 | free(content); |
811 | 0 | if (ret == -1) |
812 | 0 | return -1; |
813 | 0 | size = outbuf.len; |
814 | 0 | content = strbuf_detach(&outbuf, NULL); |
815 | 0 | } |
816 | 0 | if (input_oi->sizep) |
817 | 0 | *input_oi->sizep = size; |
818 | 0 | if (input_oi->contentp) |
819 | 0 | *input_oi->contentp = content; |
820 | 0 | else |
821 | 0 | free(content); |
822 | 0 | if (input_oi->typep) |
823 | 0 | *input_oi->typep = type; |
824 | 0 | } |
825 | 0 | if (new_oi.delta_base_oid == &delta_base_oid) { |
826 | 0 | if (repo_oid_to_algop(r, &delta_base_oid, input_algo, |
827 | 0 | input_oi->delta_base_oid)) { |
828 | 0 | if (do_die) |
829 | 0 | die(_("missing mapping of %s to %s"), |
830 | 0 | oid_to_hex(&delta_base_oid), |
831 | 0 | input_algo->name); |
832 | 0 | return -1; |
833 | 0 | } |
834 | 0 | } |
835 | 0 | input_oi->whence = new_oi.whence; |
836 | 0 | input_oi->u = new_oi.u; |
837 | 0 | return ret; |
838 | 0 | } |
839 | | |
840 | | int odb_read_object_info_extended(struct object_database *odb, |
841 | | const struct object_id *oid, |
842 | | struct object_info *oi, |
843 | | unsigned flags) |
844 | 0 | { |
845 | 0 | int ret; |
846 | |
|
847 | 0 | if (oid->algo && (hash_algo_by_ptr(odb->repo->hash_algo) != oid->algo)) |
848 | 0 | return oid_object_info_convert(odb->repo, oid, oi, flags); |
849 | | |
850 | 0 | obj_read_lock(); |
851 | 0 | ret = do_oid_object_info_extended(odb, oid, oi, flags); |
852 | 0 | obj_read_unlock(); |
853 | 0 | return ret; |
854 | 0 | } |
855 | | |
856 | | |
857 | | /* returns enum object_type or negative */ |
858 | | int odb_read_object_info(struct object_database *odb, |
859 | | const struct object_id *oid, |
860 | | unsigned long *sizep) |
861 | 0 | { |
862 | 0 | enum object_type type; |
863 | 0 | struct object_info oi = OBJECT_INFO_INIT; |
864 | |
|
865 | 0 | oi.typep = &type; |
866 | 0 | oi.sizep = sizep; |
867 | 0 | if (odb_read_object_info_extended(odb, oid, &oi, |
868 | 0 | OBJECT_INFO_LOOKUP_REPLACE) < 0) |
869 | 0 | return -1; |
870 | 0 | return type; |
871 | 0 | } |
872 | | |
873 | | int odb_pretend_object(struct object_database *odb, |
874 | | void *buf, unsigned long len, enum object_type type, |
875 | | struct object_id *oid) |
876 | 0 | { |
877 | 0 | struct cached_object_entry *co; |
878 | 0 | char *co_buf; |
879 | |
|
880 | 0 | hash_object_file(odb->repo->hash_algo, buf, len, type, oid); |
881 | 0 | if (odb_has_object(odb, oid, 0) || |
882 | 0 | find_cached_object(odb, oid)) |
883 | 0 | return 0; |
884 | | |
885 | 0 | ALLOC_GROW(odb->cached_objects, |
886 | 0 | odb->cached_object_nr + 1, odb->cached_object_alloc); |
887 | 0 | co = &odb->cached_objects[odb->cached_object_nr++]; |
888 | 0 | co->value.size = len; |
889 | 0 | co->value.type = type; |
890 | 0 | co_buf = xmalloc(len); |
891 | 0 | memcpy(co_buf, buf, len); |
892 | 0 | co->value.buf = co_buf; |
893 | 0 | oidcpy(&co->oid, oid); |
894 | 0 | return 0; |
895 | 0 | } |
896 | | |
897 | | void *odb_read_object(struct object_database *odb, |
898 | | const struct object_id *oid, |
899 | | enum object_type *type, |
900 | | unsigned long *size) |
901 | 0 | { |
902 | 0 | struct object_info oi = OBJECT_INFO_INIT; |
903 | 0 | unsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_LOOKUP_REPLACE; |
904 | 0 | void *data; |
905 | |
|
906 | 0 | oi.typep = type; |
907 | 0 | oi.sizep = size; |
908 | 0 | oi.contentp = &data; |
909 | 0 | if (odb_read_object_info_extended(odb, oid, &oi, flags)) |
910 | 0 | return NULL; |
911 | | |
912 | 0 | return data; |
913 | 0 | } |
914 | | |
915 | | void *odb_read_object_peeled(struct object_database *odb, |
916 | | const struct object_id *oid, |
917 | | enum object_type required_type, |
918 | | unsigned long *size, |
919 | | struct object_id *actual_oid_return) |
920 | 0 | { |
921 | 0 | enum object_type type; |
922 | 0 | void *buffer; |
923 | 0 | unsigned long isize; |
924 | 0 | struct object_id actual_oid; |
925 | |
|
926 | 0 | oidcpy(&actual_oid, oid); |
927 | 0 | while (1) { |
928 | 0 | int ref_length = -1; |
929 | 0 | const char *ref_type = NULL; |
930 | |
|
931 | 0 | buffer = odb_read_object(odb, &actual_oid, &type, &isize); |
932 | 0 | if (!buffer) |
933 | 0 | return NULL; |
934 | 0 | if (type == required_type) { |
935 | 0 | *size = isize; |
936 | 0 | if (actual_oid_return) |
937 | 0 | oidcpy(actual_oid_return, &actual_oid); |
938 | 0 | return buffer; |
939 | 0 | } |
940 | | /* Handle references */ |
941 | 0 | else if (type == OBJ_COMMIT) |
942 | 0 | ref_type = "tree "; |
943 | 0 | else if (type == OBJ_TAG) |
944 | 0 | ref_type = "object "; |
945 | 0 | else { |
946 | 0 | free(buffer); |
947 | 0 | return NULL; |
948 | 0 | } |
949 | 0 | ref_length = strlen(ref_type); |
950 | |
|
951 | 0 | if (ref_length + odb->repo->hash_algo->hexsz > isize || |
952 | 0 | memcmp(buffer, ref_type, ref_length) || |
953 | 0 | get_oid_hex_algop((char *) buffer + ref_length, &actual_oid, |
954 | 0 | odb->repo->hash_algo)) { |
955 | 0 | free(buffer); |
956 | 0 | return NULL; |
957 | 0 | } |
958 | 0 | free(buffer); |
959 | | /* Now we have the ID of the referred-to object in |
960 | | * actual_oid. Check again. */ |
961 | 0 | } |
962 | 0 | } |
963 | | |
964 | | int odb_has_object(struct object_database *odb, const struct object_id *oid, |
965 | | unsigned flags) |
966 | 0 | { |
967 | 0 | unsigned object_info_flags = 0; |
968 | |
|
969 | 0 | if (!startup_info->have_repository) |
970 | 0 | return 0; |
971 | 0 | if (!(flags & HAS_OBJECT_RECHECK_PACKED)) |
972 | 0 | object_info_flags |= OBJECT_INFO_QUICK; |
973 | 0 | if (!(flags & HAS_OBJECT_FETCH_PROMISOR)) |
974 | 0 | object_info_flags |= OBJECT_INFO_SKIP_FETCH_OBJECT; |
975 | |
|
976 | 0 | return odb_read_object_info_extended(odb, oid, NULL, object_info_flags) >= 0; |
977 | 0 | } |
978 | | |
979 | | int odb_freshen_object(struct object_database *odb, |
980 | | const struct object_id *oid) |
981 | 0 | { |
982 | 0 | struct odb_source *source; |
983 | |
|
984 | 0 | if (packfile_store_freshen_object(odb->packfiles, oid)) |
985 | 0 | return 1; |
986 | | |
987 | 0 | odb_prepare_alternates(odb); |
988 | 0 | for (source = odb->sources; source; source = source->next) |
989 | 0 | if (odb_source_loose_freshen_object(source, oid)) |
990 | 0 | return 1; |
991 | | |
992 | 0 | return 0; |
993 | 0 | } |
994 | | |
995 | | void odb_assert_oid_type(struct object_database *odb, |
996 | | const struct object_id *oid, enum object_type expect) |
997 | 0 | { |
998 | 0 | enum object_type type = odb_read_object_info(odb, oid, NULL); |
999 | 0 | if (type < 0) |
1000 | 0 | die(_("%s is not a valid object"), oid_to_hex(oid)); |
1001 | 0 | if (type != expect) |
1002 | 0 | die(_("%s is not a valid '%s' object"), oid_to_hex(oid), |
1003 | 0 | type_name(expect)); |
1004 | 0 | } |
1005 | | |
1006 | | int odb_write_object_ext(struct object_database *odb, |
1007 | | const void *buf, unsigned long len, |
1008 | | enum object_type type, |
1009 | | struct object_id *oid, |
1010 | | struct object_id *compat_oid, |
1011 | | unsigned flags) |
1012 | 0 | { |
1013 | 0 | return odb_source_loose_write_object(odb->sources, buf, len, type, |
1014 | 0 | oid, compat_oid, flags); |
1015 | 0 | } |
1016 | | |
1017 | | int odb_write_object_stream(struct object_database *odb, |
1018 | | struct odb_write_stream *stream, size_t len, |
1019 | | struct object_id *oid) |
1020 | 0 | { |
1021 | 0 | return odb_source_loose_write_stream(odb->sources, stream, len, oid); |
1022 | 0 | } |
1023 | | |
1024 | | static void odb_update_commondir(const char *name UNUSED, |
1025 | | const char *old_cwd, |
1026 | | const char *new_cwd, |
1027 | | void *cb_data) |
1028 | 0 | { |
1029 | 0 | struct object_database *odb = cb_data; |
1030 | 0 | struct tmp_objdir *tmp_objdir; |
1031 | 0 | struct odb_source *source; |
1032 | |
|
1033 | 0 | tmp_objdir = tmp_objdir_unapply_primary_odb(); |
1034 | | |
1035 | | /* |
1036 | | * In theory, we only have to do this for the primary object source, as |
1037 | | * alternates' paths are always resolved to an absolute path. |
1038 | | */ |
1039 | 0 | for (source = odb->sources; source; source = source->next) { |
1040 | 0 | char *path; |
1041 | |
|
1042 | 0 | if (is_absolute_path(source->path)) |
1043 | 0 | continue; |
1044 | | |
1045 | 0 | path = reparent_relative_path(old_cwd, new_cwd, |
1046 | 0 | source->path); |
1047 | |
|
1048 | 0 | free(source->path); |
1049 | 0 | source->path = path; |
1050 | 0 | } |
1051 | |
|
1052 | 0 | if (tmp_objdir) |
1053 | 0 | tmp_objdir_reapply_primary_odb(tmp_objdir, old_cwd, new_cwd); |
1054 | 0 | } |
1055 | | |
1056 | | struct object_database *odb_new(struct repository *repo, |
1057 | | const char *primary_source, |
1058 | | const char *secondary_sources) |
1059 | 0 | { |
1060 | 0 | struct object_database *o = xmalloc(sizeof(*o)); |
1061 | 0 | char *to_free = NULL; |
1062 | |
|
1063 | 0 | memset(o, 0, sizeof(*o)); |
1064 | 0 | o->repo = repo; |
1065 | 0 | o->packfiles = packfile_store_new(o); |
1066 | 0 | pthread_mutex_init(&o->replace_mutex, NULL); |
1067 | 0 | string_list_init_dup(&o->submodule_source_paths); |
1068 | |
|
1069 | 0 | if (!primary_source) |
1070 | 0 | primary_source = to_free = xstrfmt("%s/objects", repo->commondir); |
1071 | 0 | o->sources = odb_source_new(o, primary_source, true); |
1072 | 0 | o->sources_tail = &o->sources->next; |
1073 | 0 | o->alternate_db = xstrdup_or_null(secondary_sources); |
1074 | |
|
1075 | 0 | free(to_free); |
1076 | |
|
1077 | 0 | chdir_notify_register(NULL, odb_update_commondir, o); |
1078 | |
|
1079 | 0 | return o; |
1080 | 0 | } |
1081 | | |
1082 | | void odb_close(struct object_database *o) |
1083 | 0 | { |
1084 | 0 | struct odb_source *source; |
1085 | |
|
1086 | 0 | packfile_store_close(o->packfiles); |
1087 | |
|
1088 | 0 | for (source = o->sources; source; source = source->next) { |
1089 | 0 | if (source->midx) |
1090 | 0 | close_midx(source->midx); |
1091 | 0 | source->midx = NULL; |
1092 | 0 | } |
1093 | |
|
1094 | 0 | close_commit_graph(o); |
1095 | 0 | } |
1096 | | |
1097 | | static void odb_free_sources(struct object_database *o) |
1098 | 0 | { |
1099 | 0 | while (o->sources) { |
1100 | 0 | struct odb_source *next; |
1101 | |
|
1102 | 0 | next = o->sources->next; |
1103 | 0 | odb_source_free(o->sources); |
1104 | 0 | o->sources = next; |
1105 | 0 | } |
1106 | 0 | kh_destroy_odb_path_map(o->source_by_path); |
1107 | 0 | o->source_by_path = NULL; |
1108 | 0 | } |
1109 | | |
1110 | | void odb_free(struct object_database *o) |
1111 | 60 | { |
1112 | 60 | if (!o) |
1113 | 60 | return; |
1114 | | |
1115 | 0 | free(o->alternate_db); |
1116 | |
|
1117 | 0 | oidmap_clear(&o->replace_map, 1); |
1118 | 0 | pthread_mutex_destroy(&o->replace_mutex); |
1119 | |
|
1120 | 0 | odb_free_sources(o); |
1121 | |
|
1122 | 0 | for (size_t i = 0; i < o->cached_object_nr; i++) |
1123 | 0 | free((char *) o->cached_objects[i].value.buf); |
1124 | 0 | free(o->cached_objects); |
1125 | |
|
1126 | 0 | odb_close(o); |
1127 | 0 | packfile_store_free(o->packfiles); |
1128 | 0 | string_list_clear(&o->submodule_source_paths, 0); |
1129 | |
|
1130 | 0 | chdir_notify_unregister(NULL, odb_update_commondir, o); |
1131 | |
|
1132 | 0 | free(o); |
1133 | 0 | } |
1134 | | |
1135 | | void odb_reprepare(struct object_database *o) |
1136 | 0 | { |
1137 | 0 | struct odb_source *source; |
1138 | |
|
1139 | 0 | obj_read_lock(); |
1140 | | |
1141 | | /* |
1142 | | * Reprepare alt odbs, in case the alternates file was modified |
1143 | | * during the course of this process. This only _adds_ odbs to |
1144 | | * the linked list, so existing odbs will continue to exist for |
1145 | | * the lifetime of the process. |
1146 | | */ |
1147 | 0 | o->loaded_alternates = 0; |
1148 | 0 | odb_prepare_alternates(o); |
1149 | |
|
1150 | 0 | for (source = o->sources; source; source = source->next) |
1151 | 0 | odb_source_loose_reprepare(source); |
1152 | |
|
1153 | 0 | o->approximate_object_count_valid = 0; |
1154 | |
|
1155 | 0 | packfile_store_reprepare(o->packfiles); |
1156 | |
|
1157 | 0 | obj_read_unlock(); |
1158 | 0 | } |
1159 | | |
1160 | | struct odb_transaction *odb_transaction_begin(struct object_database *odb) |
1161 | 0 | { |
1162 | 0 | return object_file_transaction_begin(odb->sources); |
1163 | 0 | } |
1164 | | |
1165 | | void odb_transaction_commit(struct odb_transaction *transaction) |
1166 | 0 | { |
1167 | 0 | object_file_transaction_commit(transaction); |
1168 | 0 | } |