object-file: split out functions relating to object store subsystem

While we have the "object-store.h" header, most of the functionality for object stores is actually hosted in "object-file.c". This makes it hard to find relevant functions and causes us to mix up concerns. Split out functions relating to the object store subsystem into a new "object-store.c" file. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Apr 15, 2025 at 11:38 UTC d9f517d051d1008178cb6c809b5f906d0905508f
20 files changed +1074 -1040
Makefile
+1
@@ -1086,6 +1086,7 @@ LIB_OBJS += notes.o
1086 LIB_OBJS += object-file-convert.o
1087 LIB_OBJS += object-file.o
1088 LIB_OBJS += object-name.o
1089 +LIB_OBJS += object-store.o
1090 LIB_OBJS += object.o
1091 LIB_OBJS += oid-array.o
1092 LIB_OBJS += oidmap.o
builtin/checkout.c
+1
@@ -18,6 +18,7 @@
18 #include "lockfile.h"
19 #include "mem-pool.h"
20 #include "merge-recursive.h"
21 +#include "object-file.h"
22 #include "object-name.h"
23 #include "object-store-ll.h"
24 #include "parse-options.h"
builtin/merge-file.c
+1
@@ -5,6 +5,7 @@
5 #include "abspath.h"
6 #include "diff.h"
7 #include "hex.h"
8 +#include "object-file.h"
9 #include "object-name.h"
10 #include "object-store.h"
11 #include "config.h"
builtin/mktree.c
+1
@@ -11,6 +11,7 @@
11 #include "strbuf.h"
12 #include "tree.h"
13 #include "parse-options.h"
14 +#include "object-file.h"
15 #include "object-store-ll.h"
16
17 static struct treeent {
builtin/notes.c
+1
@@ -14,6 +14,7 @@
14 #include "gettext.h"
15 #include "hex.h"
16 #include "notes.h"
17 +#include "object-file.h"
18 #include "object-name.h"
19 #include "object-store-ll.h"
20 #include "path.h"
builtin/receive-pack.c
+1
@@ -31,6 +31,7 @@
31 #include "tmp-objdir.h"
32 #include "oidset.h"
33 #include "packfile.h"
34 +#include "object-file.h"
35 #include "object-name.h"
36 #include "object-store-ll.h"
37 #include "path.h"
builtin/tag.c
+1
@@ -17,6 +17,7 @@
17 #include "gettext.h"
18 #include "hex.h"
19 #include "refs.h"
20 +#include "object-file.h"
21 #include "object-name.h"
22 #include "object-store-ll.h"
23 #include "path.h"
builtin/unpack-file.c
+1
@@ -2,6 +2,7 @@
2 #include "builtin.h"
3 #include "config.h"
4 #include "hex.h"
5 +#include "object-file.h"
6 #include "object-name.h"
7 #include "object-store-ll.h"
8
builtin/unpack-objects.c
+1
@@ -8,6 +8,7 @@
8 #include "gettext.h"
9 #include "git-zlib.h"
10 #include "hex.h"
11 +#include "object-file.h"
12 #include "object-store-ll.h"
13 #include "object.h"
14 #include "delta.h"
commit.c
+1
@@ -29,6 +29,7 @@
29 #include "tree.h"
30 #include "hook.h"
31 #include "parse.h"
32 +#include "object-file.h"
33 #include "object-file-convert.h"
34
35 static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
http-push.c
+1
@@ -19,6 +19,7 @@
19 #include "tree-walk.h"
20 #include "url.h"
21 #include "packfile.h"
22 +#include "object-file.h"
23 #include "object-store-ll.h"
24 #include "commit-reach.h"
25
match-trees.c
+2 -1
@@ -6,7 +6,8 @@
6 #include "strbuf.h"
7 #include "tree.h"
8 #include "tree-walk.h"
9 -#include "object-store-ll.h"
9 +#include "object-file.h"
10 +#include "object-store.h"
11 #include "repository.h"
12
13 static int score_missing(unsigned mode)
merge-ort.c
+2 -1
@@ -36,8 +36,9 @@
36 #include "merge-ll.h"
37 #include "match-trees.h"
38 #include "mem-pool.h"
39 +#include "object-file.h"
40 #include "object-name.h"
40 -#include "object-store-ll.h"
41 +#include "object-store.h"
42 #include "oid-array.h"
43 #include "path.h"
44 #include "promisor-remote.h"
meson.build
+1
@@ -355,6 +355,7 @@ libgit_sources = [
355 'object-file-convert.c',
356 'object-file.c',
357 'object-name.c',
358 + 'object-store.c',
359 'object.c',
360 'oid-array.c',
361 'oidmap.c',
notes-cache.c
+2 -1
@@ -2,7 +2,8 @@
2
3 #include "git-compat-util.h"
4 #include "notes-cache.h"
5 -#include "object-store-ll.h"
5 +#include "object-file.h"
6 +#include "object-store.h"
7 #include "pretty.h"
8 #include "repository.h"
9 #include "commit.h"
notes.c
+2 -1
@@ -6,8 +6,9 @@
6 #include "environment.h"
7 #include "hex.h"
8 #include "notes.h"
9 +#include "object-file.h"
10 #include "object-name.h"
10 -#include "object-store-ll.h"
11 +#include "object-store.h"
12 #include "utf8.h"
13 #include "strbuf.h"
14 #include "tree-walk.h"
object-file.c
+13 -977
@@ -11,75 +11,26 @@
11 #define DISABLE_SIGN_COMPARE_WARNINGS
12
13 #include "git-compat-util.h"
14 -#include "abspath.h"
15 -#include "config.h"
14 +#include "bulk-checkin.h"
15 #include "convert.h"
16 #include "environment.h"
17 +#include "fsck.h"
18 #include "gettext.h"
19 #include "hex.h"
20 -#include "string-list.h"
21 -#include "lockfile.h"
22 -#include "pack.h"
23 -#include "commit.h"
24 -#include "run-command.h"
25 -#include "refs.h"
26 -#include "bulk-checkin.h"
27 -#include "repository.h"
28 -#include "replace-object.h"
29 -#include "streaming.h"
30 -#include "dir.h"
31 -#include "list.h"
32 -#include "quote.h"
33 -#include "packfile.h"
20 +#include "loose.h"
21 +#include "object-file-convert.h"
22 #include "object-file.h"
23 #include "object-store.h"
24 #include "oidtree.h"
25 +#include "pack.h"
26 +#include "packfile.h"
27 #include "path.h"
38 -#include "promisor-remote.h"
28 #include "setup.h"
40 -#include "submodule.h"
41 -#include "fsck.h"
42 -#include "loose.h"
43 -#include "object-file-convert.h"
29 +#include "streaming.h"
30
31 /* The maximum size for an object header. */
32 #define MAX_HEADER_LEN 32
33
48 -/*
49 - * This is meant to hold a *small* number of objects that you would
50 - * want repo_read_object_file() to be able to return, but yet you do not want
51 - * to write them into the object store (e.g. a browse-only
52 - * application).
53 - */
54 -static struct cached_object_entry {
55 - struct object_id oid;
56 - struct cached_object {
57 - enum object_type type;
58 - const void *buf;
59 - unsigned long size;
60 - } value;
61 -} *cached_objects;
62 -static int cached_object_nr, cached_object_alloc;
63 -
64 -static const struct cached_object *find_cached_object(const struct object_id *oid)
65 -{
66 - static const struct cached_object empty_tree = {
67 - .type = OBJ_TREE,
68 - .buf = "",
69 - };
70 - int i;
71 - const struct cached_object_entry *co = cached_objects;
72 -
73 - for (i = 0; i < cached_object_nr; i++, co++) {
74 - if (oideq(&co->oid, oid))
75 - return &co->value;
76 - }
77 - if (oideq(oid, the_hash_algo->empty_tree))
78 - return &empty_tree;
79 - return NULL;
80 -}
81 -
82 -
34 static int get_conv_flags(unsigned flags)
35 {
36 if (flags & HASH_RENORMALIZE)
@@ -90,39 +41,6 @@ static int get_conv_flags(unsigned flags)
41 return 0;
42 }
43
93 -int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
94 -{
95 - int fd;
96 - /*
97 - * we let the umask do its job, don't try to be more
98 - * restrictive except to remove write permission.
99 - */
100 - int mode = 0444;
101 - repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
102 - fd = git_mkstemp_mode(temp_filename->buf, mode);
103 - if (0 <= fd)
104 - return fd;
105 -
106 - /* slow path */
107 - /* some mkstemp implementations erase temp_filename on failure */
108 - repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
109 - safe_create_leading_directories(the_repository, temp_filename->buf);
110 - return xmkstemp_mode(temp_filename->buf, mode);
111 -}
112 -
113 -int odb_pack_keep(const char *name)
114 -{
115 - int fd;
116 -
117 - fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
118 - if (0 <= fd)
119 - return fd;
120 -
121 - /* slow path */
122 - safe_create_leading_directories_const(the_repository, name);
123 - return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
124 -}
125 -
44 static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
45 {
46 int i;
@@ -136,9 +54,9 @@ static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
54 }
55 }
56
139 -static const char *odb_loose_path(struct object_directory *odb,
140 - struct strbuf *buf,
141 - const struct object_id *oid)
57 +const char *odb_loose_path(struct object_directory *odb,
58 + struct strbuf *buf,
59 + const struct object_id *oid)
60 {
61 strbuf_reset(buf);
62 strbuf_addstr(buf, odb->path);
@@ -147,513 +65,6 @@ static const char *odb_loose_path(struct object_directory *odb,
65 return buf->buf;
66 }
67
150 -const char *loose_object_path(struct repository *r, struct strbuf *buf,
151 - const struct object_id *oid)
152 -{
153 - return odb_loose_path(r->objects->odb, buf, oid);
154 -}
155 -
156 -/*
157 - * Return non-zero iff the path is usable as an alternate object database.
158 - */
159 -static int alt_odb_usable(struct raw_object_store *o,
160 - struct strbuf *path,
161 - const char *normalized_objdir, khiter_t *pos)
162 -{
163 - int r;
164 -
165 - /* Detect cases where alternate disappeared */
166 - if (!is_directory(path->buf)) {
167 - error(_("object directory %s does not exist; "
168 - "check .git/objects/info/alternates"),
169 - path->buf);
170 - return 0;
171 - }
172 -
173 - /*
174 - * Prevent the common mistake of listing the same
175 - * thing twice, or object directory itself.
176 - */
177 - if (!o->odb_by_path) {
178 - khiter_t p;
179 -
180 - o->odb_by_path = kh_init_odb_path_map();
181 - assert(!o->odb->next);
182 - p = kh_put_odb_path_map(o->odb_by_path, o->odb->path, &r);
183 - assert(r == 1); /* never used */
184 - kh_value(o->odb_by_path, p) = o->odb;
185 - }
186 - if (fspatheq(path->buf, normalized_objdir))
187 - return 0;
188 - *pos = kh_put_odb_path_map(o->odb_by_path, path->buf, &r);
189 - /* r: 0 = exists, 1 = never used, 2 = deleted */
190 - return r == 0 ? 0 : 1;
191 -}
192 -
193 -/*
194 - * Prepare alternate object database registry.
195 - *
196 - * The variable alt_odb_list points at the list of struct
197 - * object_directory. The elements on this list come from
198 - * non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
199 - * environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
200 - * whose contents is similar to that environment variable but can be
201 - * LF separated. Its base points at a statically allocated buffer that
202 - * contains "/the/directory/corresponding/to/.git/objects/...", while
203 - * its name points just after the slash at the end of ".git/objects/"
204 - * in the example above, and has enough space to hold all hex characters
205 - * of the object ID, an extra slash for the first level indirection, and
206 - * the terminating NUL.
207 - */
208 -static void read_info_alternates(struct repository *r,
209 - const char *relative_base,
210 - int depth);
211 -static int link_alt_odb_entry(struct repository *r, const struct strbuf *entry,
212 - const char *relative_base, int depth, const char *normalized_objdir)
213 -{
214 - struct object_directory *ent;
215 - struct strbuf pathbuf = STRBUF_INIT;
216 - struct strbuf tmp = STRBUF_INIT;
217 - khiter_t pos;
218 - int ret = -1;
219 -
220 - if (!is_absolute_path(entry->buf) && relative_base) {
221 - strbuf_realpath(&pathbuf, relative_base, 1);
222 - strbuf_addch(&pathbuf, '/');
223 - }
224 - strbuf_addbuf(&pathbuf, entry);
225 -
226 - if (!strbuf_realpath(&tmp, pathbuf.buf, 0)) {
227 - error(_("unable to normalize alternate object path: %s"),
228 - pathbuf.buf);
229 - goto error;
230 - }
231 - strbuf_swap(&pathbuf, &tmp);
232 -
233 - /*
234 - * The trailing slash after the directory name is given by
235 - * this function at the end. Remove duplicates.
236 - */
237 - while (pathbuf.len && pathbuf.buf[pathbuf.len - 1] == '/')
238 - strbuf_setlen(&pathbuf, pathbuf.len - 1);
239 -
240 - if (!alt_odb_usable(r->objects, &pathbuf, normalized_objdir, &pos))
241 - goto error;
242 -
243 - CALLOC_ARRAY(ent, 1);
244 - /* pathbuf.buf is already in r->objects->odb_by_path */
245 - ent->path = strbuf_detach(&pathbuf, NULL);
246 -
247 - /* add the alternate entry */
248 - *r->objects->odb_tail = ent;
249 - r->objects->odb_tail = &(ent->next);
250 - ent->next = NULL;
251 - assert(r->objects->odb_by_path);
252 - kh_value(r->objects->odb_by_path, pos) = ent;
253 -
254 - /* recursively add alternates */
255 - read_info_alternates(r, ent->path, depth + 1);
256 - ret = 0;
257 - error:
258 - strbuf_release(&tmp);
259 - strbuf_release(&pathbuf);
260 - return ret;
261 -}
262 -
263 -static const char *parse_alt_odb_entry(const char *string,
264 - int sep,
265 - struct strbuf *out)
266 -{
267 - const char *end;
268 -
269 - strbuf_reset(out);
270 -
271 - if (*string == '#') {
272 - /* comment; consume up to next separator */
273 - end = strchrnul(string, sep);
274 - } else if (*string == '"' && !unquote_c_style(out, string, &end)) {
275 - /*
276 - * quoted path; unquote_c_style has copied the
277 - * data for us and set "end". Broken quoting (e.g.,
278 - * an entry that doesn't end with a quote) falls
279 - * back to the unquoted case below.
280 - */
281 - } else {
282 - /* normal, unquoted path */
283 - end = strchrnul(string, sep);
284 - strbuf_add(out, string, end - string);
285 - }
286 -
287 - if (*end)
288 - end++;
289 - return end;
290 -}
291 -
292 -static void link_alt_odb_entries(struct repository *r, const char *alt,
293 - int sep, const char *relative_base, int depth)
294 -{
295 - struct strbuf objdirbuf = STRBUF_INIT;
296 - struct strbuf entry = STRBUF_INIT;
297 -
298 - if (!alt || !*alt)
299 - return;
300 -
301 - if (depth > 5) {
302 - error(_("%s: ignoring alternate object stores, nesting too deep"),
303 - relative_base);
304 - return;
305 - }
306 -
307 - strbuf_realpath(&objdirbuf, r->objects->odb->path, 1);
308 -
309 - while (*alt) {
310 - alt = parse_alt_odb_entry(alt, sep, &entry);
311 - if (!entry.len)
312 - continue;
313 - link_alt_odb_entry(r, &entry,
314 - relative_base, depth, objdirbuf.buf);
315 - }
316 - strbuf_release(&entry);
317 - strbuf_release(&objdirbuf);
318 -}
319 -
320 -static void read_info_alternates(struct repository *r,
321 - const char *relative_base,
322 - int depth)
323 -{
324 - char *path;
325 - struct strbuf buf = STRBUF_INIT;
326 -
327 - path = xstrfmt("%s/info/alternates", relative_base);
328 - if (strbuf_read_file(&buf, path, 1024) < 0) {
329 - warn_on_fopen_errors(path);
330 - free(path);
331 - return;
332 - }
333 -
334 - link_alt_odb_entries(r, buf.buf, '\n', relative_base, depth);
335 - strbuf_release(&buf);
336 - free(path);
337 -}
338 -
339 -void add_to_alternates_file(const char *reference)
340 -{
341 - struct lock_file lock = LOCK_INIT;
342 - char *alts = repo_git_path(the_repository, "objects/info/alternates");
343 - FILE *in, *out;
344 - int found = 0;
345 -
346 - hold_lock_file_for_update(&lock, alts, LOCK_DIE_ON_ERROR);
347 - out = fdopen_lock_file(&lock, "w");
348 - if (!out)
349 - die_errno(_("unable to fdopen alternates lockfile"));
350 -
351 - in = fopen(alts, "r");
352 - if (in) {
353 - struct strbuf line = STRBUF_INIT;
354 -
355 - while (strbuf_getline(&line, in) != EOF) {
356 - if (!strcmp(reference, line.buf)) {
357 - found = 1;
358 - break;
359 - }
360 - fprintf_or_die(out, "%s\n", line.buf);
361 - }
362 -
363 - strbuf_release(&line);
364 - fclose(in);
365 - }
366 - else if (errno != ENOENT)
367 - die_errno(_("unable to read alternates file"));
368 -
369 - if (found) {
370 - rollback_lock_file(&lock);
371 - } else {
372 - fprintf_or_die(out, "%s\n", reference);
373 - if (commit_lock_file(&lock))
374 - die_errno(_("unable to move new alternates file into place"));
375 - if (the_repository->objects->loaded_alternates)
376 - link_alt_odb_entries(the_repository, reference,
377 - '\n', NULL, 0);
378 - }
379 - free(alts);
380 -}
381 -
382 -void add_to_alternates_memory(const char *reference)
383 -{
384 - /*
385 - * Make sure alternates are initialized, or else our entry may be
386 - * overwritten when they are.
387 - */
388 - prepare_alt_odb(the_repository);
389 -
390 - link_alt_odb_entries(the_repository, reference,
391 - '\n', NULL, 0);
392 -}
393 -
394 -struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy)
395 -{
396 - struct object_directory *new_odb;
397 -
398 - /*
399 - * Make sure alternates are initialized, or else our entry may be
400 - * overwritten when they are.
401 - */
402 - prepare_alt_odb(the_repository);
403 -
404 - /*
405 - * Make a new primary odb and link the old primary ODB in as an
406 - * alternate
407 - */
408 - new_odb = xcalloc(1, sizeof(*new_odb));
409 - new_odb->path = xstrdup(dir);
410 -
411 - /*
412 - * Disable ref updates while a temporary odb is active, since
413 - * the objects in the database may roll back.
414 - */
415 - new_odb->disable_ref_updates = 1;
416 - new_odb->will_destroy = will_destroy;
417 - new_odb->next = the_repository->objects->odb;
418 - the_repository->objects->odb = new_odb;
419 - return new_odb->next;
420 -}
421 -
422 -void restore_primary_odb(struct object_directory *restore_odb, const char *old_path)
423 -{
424 - struct object_directory *cur_odb = the_repository->objects->odb;
425 -
426 - if (strcmp(old_path, cur_odb->path))
427 - BUG("expected %s as primary object store; found %s",
428 - old_path, cur_odb->path);
429 -
430 - if (cur_odb->next != restore_odb)
431 - BUG("we expect the old primary object store to be the first alternate");
432 -
433 - the_repository->objects->odb = restore_odb;
434 - free_object_directory(cur_odb);
435 -}
436 -
437 -/*
438 - * Compute the exact path an alternate is at and returns it. In case of
439 - * error NULL is returned and the human readable error is added to `err`
440 - * `path` may be relative and should point to $GIT_DIR.
441 - * `err` must not be null.
442 - */
443 -char *compute_alternate_path(const char *path, struct strbuf *err)
444 -{
445 - char *ref_git = NULL;
446 - const char *repo;
447 - int seen_error = 0;
448 -
449 - ref_git = real_pathdup(path, 0);
450 - if (!ref_git) {
451 - seen_error = 1;
452 - strbuf_addf(err, _("path '%s' does not exist"), path);
453 - goto out;
454 - }
455 -
456 - repo = read_gitfile(ref_git);
457 - if (!repo)
458 - repo = read_gitfile(mkpath("%s/.git", ref_git));
459 - if (repo) {
460 - free(ref_git);
461 - ref_git = xstrdup(repo);
462 - }
463 -
464 - if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) {
465 - char *ref_git_git = mkpathdup("%s/.git", ref_git);
466 - free(ref_git);
467 - ref_git = ref_git_git;
468 - } else if (!is_directory(mkpath("%s/objects", ref_git))) {
469 - struct strbuf sb = STRBUF_INIT;
470 - seen_error = 1;
471 - if (get_common_dir(&sb, ref_git)) {
472 - strbuf_addf(err,
473 - _("reference repository '%s' as a linked "
474 - "checkout is not supported yet."),
475 - path);
476 - goto out;
477 - }
478 -
479 - strbuf_addf(err, _("reference repository '%s' is not a "
480 - "local repository."), path);
481 - goto out;
482 - }
483 -
484 - if (!access(mkpath("%s/shallow", ref_git), F_OK)) {
485 - strbuf_addf(err, _("reference repository '%s' is shallow"),
486 - path);
487 - seen_error = 1;
488 - goto out;
489 - }
490 -
491 - if (!access(mkpath("%s/info/grafts", ref_git), F_OK)) {
492 - strbuf_addf(err,
493 - _("reference repository '%s' is grafted"),
494 - path);
495 - seen_error = 1;
496 - goto out;
497 - }
498 -
499 -out:
500 - if (seen_error) {
501 - FREE_AND_NULL(ref_git);
502 - }
503 -
504 - return ref_git;
505 -}
506 -
507 -struct object_directory *find_odb(struct repository *r, const char *obj_dir)
508 -{
509 - struct object_directory *odb;
510 - char *obj_dir_real = real_pathdup(obj_dir, 1);
511 - struct strbuf odb_path_real = STRBUF_INIT;
512 -
513 - prepare_alt_odb(r);
514 - for (odb = r->objects->odb; odb; odb = odb->next) {
515 - strbuf_realpath(&odb_path_real, odb->path, 1);
516 - if (!strcmp(obj_dir_real, odb_path_real.buf))
517 - break;
518 - }
519 -
520 - free(obj_dir_real);
521 - strbuf_release(&odb_path_real);
522 -
523 - if (!odb)
524 - die(_("could not find object directory matching %s"), obj_dir);
525 - return odb;
526 -}
527 -
528 -static void fill_alternate_refs_command(struct child_process *cmd,
529 - const char *repo_path)
530 -{
531 - const char *value;
532 -
533 - if (!git_config_get_value("core.alternateRefsCommand", &value)) {
534 - cmd->use_shell = 1;
535 -
536 - strvec_push(&cmd->args, value);
537 - strvec_push(&cmd->args, repo_path);
538 - } else {
539 - cmd->git_cmd = 1;
540 -
541 - strvec_pushf(&cmd->args, "--git-dir=%s", repo_path);
542 - strvec_push(&cmd->args, "for-each-ref");
543 - strvec_push(&cmd->args, "--format=%(objectname)");
544 -
545 - if (!git_config_get_value("core.alternateRefsPrefixes", &value)) {
546 - strvec_push(&cmd->args, "--");
547 - strvec_split(&cmd->args, value);
548 - }
549 - }
550 -
551 - strvec_pushv(&cmd->env, (const char **)local_repo_env);
552 - cmd->out = -1;
553 -}
554 -
555 -static void read_alternate_refs(const char *path,
556 - alternate_ref_fn *cb,
557 - void *data)
558 -{
559 - struct child_process cmd = CHILD_PROCESS_INIT;
560 - struct strbuf line = STRBUF_INIT;
561 - FILE *fh;
562 -
563 - fill_alternate_refs_command(&cmd, path);
564 -
565 - if (start_command(&cmd))
566 - return;
567 -
568 - fh = xfdopen(cmd.out, "r");
569 - while (strbuf_getline_lf(&line, fh) != EOF) {
570 - struct object_id oid;
571 - const char *p;
572 -
573 - if (parse_oid_hex(line.buf, &oid, &p) || *p) {
574 - warning(_("invalid line while parsing alternate refs: %s"),
575 - line.buf);
576 - break;
577 - }
578 -
579 - cb(&oid, data);
580 - }
581 -
582 - fclose(fh);
583 - finish_command(&cmd);
584 - strbuf_release(&line);
585 -}
586 -
587 -struct alternate_refs_data {
588 - alternate_ref_fn *fn;
589 - void *data;
590 -};
591 -
592 -static int refs_from_alternate_cb(struct object_directory *e,
593 - void *data)
594 -{
595 - struct strbuf path = STRBUF_INIT;
596 - size_t base_len;
597 - struct alternate_refs_data *cb = data;
598 -
599 - if (!strbuf_realpath(&path, e->path, 0))
600 - goto out;
601 - if (!strbuf_strip_suffix(&path, "/objects"))
602 - goto out;
603 - base_len = path.len;
604 -
605 - /* Is this a git repository with refs? */
606 - strbuf_addstr(&path, "/refs");
607 - if (!is_directory(path.buf))
608 - goto out;
609 - strbuf_setlen(&path, base_len);
610 -
611 - read_alternate_refs(path.buf, cb->fn, cb->data);
612 -
613 -out:
614 - strbuf_release(&path);
615 - return 0;
616 -}
617 -
618 -void for_each_alternate_ref(alternate_ref_fn fn, void *data)
619 -{
620 - struct alternate_refs_data cb;
621 - cb.fn = fn;
622 - cb.data = data;
623 - foreach_alt_odb(refs_from_alternate_cb, &cb);
624 -}
625 -
626 -int foreach_alt_odb(alt_odb_fn fn, void *cb)
627 -{
628 - struct object_directory *ent;
629 - int r = 0;
630 -
631 - prepare_alt_odb(the_repository);
632 - for (ent = the_repository->objects->odb->next; ent; ent = ent->next) {
633 - r = fn(ent, cb);
634 - if (r)
635 - break;
636 - }
637 - return r;
638 -}
639 -
640 -void prepare_alt_odb(struct repository *r)
641 -{
642 - if (r->objects->loaded_alternates)
643 - return;
644 -
645 - link_alt_odb_entries(r, r->objects->alternate_db, PATH_SEP, NULL, 0);
646 -
647 - read_info_alternates(r, r->objects->odb->path, 0);
648 - r->objects->loaded_alternates = 1;
649 -}
650 -
651 -int has_alt_odb(struct repository *r)
652 -{
653 - prepare_alt_odb(r);
654 - return !!r->objects->odb->next;
655 -}
656 -
68 /* Returns 1 if we have successfully freshened the file, 0 otherwise. */
69 static int freshen_file(const char *fn)
70 {
@@ -1055,9 +466,9 @@ int parse_loose_header(const char *hdr, struct object_info *oi)
466 return 0;
467 }
468
1058 -static int loose_object_info(struct repository *r,
1059 - const struct object_id *oid,
1060 - struct object_info *oi, int flags)
469 +int loose_object_info(struct repository *r,
470 + const struct object_id *oid,
471 + struct object_info *oi, int flags)
472 {
473 int status = 0;
474 int fd;
@@ -1153,345 +564,6 @@ cleanup:
564 return status;
565 }
566
1156 -int obj_read_use_lock = 0;
1157 -pthread_mutex_t obj_read_mutex;
1158 -
1159 -void enable_obj_read_lock(void)
1160 -{
1161 - if (obj_read_use_lock)
1162 - return;
1163 -
1164 - obj_read_use_lock = 1;
1165 - init_recursive_mutex(&obj_read_mutex);
1166 -}
1167 -
1168 -void disable_obj_read_lock(void)
1169 -{
1170 - if (!obj_read_use_lock)
1171 - return;
1172 -
1173 - obj_read_use_lock = 0;
1174 - pthread_mutex_destroy(&obj_read_mutex);
1175 -}
1176 -
1177 -int fetch_if_missing = 1;
1178 -
1179 -static int do_oid_object_info_extended(struct repository *r,
1180 - const struct object_id *oid,
1181 - struct object_info *oi, unsigned flags)
1182 -{
1183 - static struct object_info blank_oi = OBJECT_INFO_INIT;
1184 - const struct cached_object *co;
1185 - struct pack_entry e;
1186 - int rtype;
1187 - const struct object_id *real = oid;
1188 - int already_retried = 0;
1189 -
1190 -
1191 - if (flags & OBJECT_INFO_LOOKUP_REPLACE)
1192 - real = lookup_replace_object(r, oid);
1193 -
1194 - if (is_null_oid(real))
1195 - return -1;
1196 -
1197 - if (!oi)
1198 - oi = &blank_oi;
1199 -
1200 - co = find_cached_object(real);
1201 - if (co) {
1202 - if (oi->typep)
1203 - *(oi->typep) = co->type;
1204 - if (oi->sizep)
1205 - *(oi->sizep) = co->size;
1206 - if (oi->disk_sizep)
1207 - *(oi->disk_sizep) = 0;
1208 - if (oi->delta_base_oid)
1209 - oidclr(oi->delta_base_oid, the_repository->hash_algo);
1210 - if (oi->type_name)
1211 - strbuf_addstr(oi->type_name, type_name(co->type));
1212 - if (oi->contentp)
1213 - *oi->contentp = xmemdupz(co->buf, co->size);
1214 - oi->whence = OI_CACHED;
1215 - return 0;
1216 - }
1217 -
1218 - while (1) {
1219 - if (find_pack_entry(r, real, &e))
1220 - break;
1221 -
1222 - /* Most likely it's a loose object. */
1223 - if (!loose_object_info(r, real, oi, flags))
1224 - return 0;
1225 -
1226 - /* Not a loose object; someone else may have just packed it. */
1227 - if (!(flags & OBJECT_INFO_QUICK)) {
1228 - reprepare_packed_git(r);
1229 - if (find_pack_entry(r, real, &e))
1230 - break;
1231 - }
1232 -
1233 - /*
1234 - * If r is the_repository, this might be an attempt at
1235 - * accessing a submodule object as if it were in the_repository
1236 - * (having called add_submodule_odb() on that submodule's ODB).
1237 - * If any such ODBs exist, register them and try again.
1238 - */
1239 - if (r == the_repository &&
1240 - register_all_submodule_odb_as_alternates())
1241 - /* We added some alternates; retry */
1242 - continue;
1243 -
1244 - /* Check if it is a missing object */
1245 - if (fetch_if_missing && repo_has_promisor_remote(r) &&
1246 - !already_retried &&
1247 - !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
1248 - promisor_remote_get_direct(r, real, 1);
1249 - already_retried = 1;
1250 - continue;
1251 - }
1252 -
1253 - if (flags & OBJECT_INFO_DIE_IF_CORRUPT) {
1254 - const struct packed_git *p;
1255 - if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
1256 - die(_("replacement %s not found for %s"),
1257 - oid_to_hex(real), oid_to_hex(oid));
1258 - if ((p = has_packed_and_bad(r, real)))
1259 - die(_("packed object %s (stored in %s) is corrupt"),
1260 - oid_to_hex(real), p->pack_name);
1261 - }
1262 - return -1;
1263 - }
1264 -
1265 - if (oi == &blank_oi)
1266 - /*
1267 - * We know that the caller doesn't actually need the
1268 - * information below, so return early.
1269 - */
1270 - return 0;
1271 - rtype = packed_object_info(r, e.p, e.offset, oi);
1272 - if (rtype < 0) {
1273 - mark_bad_packed_object(e.p, real);
1274 - return do_oid_object_info_extended(r, real, oi, 0);
1275 - } else if (oi->whence == OI_PACKED) {
1276 - oi->u.packed.offset = e.offset;
1277 - oi->u.packed.pack = e.p;
1278 - oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
1279 - rtype == OBJ_OFS_DELTA);
1280 - }
1281 -
1282 - return 0;
1283 -}
1284 -
1285 -static int oid_object_info_convert(struct repository *r,
1286 - const struct object_id *input_oid,
1287 - struct object_info *input_oi, unsigned flags)
1288 -{
1289 - const struct git_hash_algo *input_algo = &hash_algos[input_oid->algo];
1290 - int do_die = flags & OBJECT_INFO_DIE_IF_CORRUPT;
1291 - struct strbuf type_name = STRBUF_INIT;
1292 - struct object_id oid, delta_base_oid;
1293 - struct object_info new_oi, *oi;
1294 - unsigned long size;
1295 - void *content;
1296 - int ret;
1297 -
1298 - if (repo_oid_to_algop(r, input_oid, the_hash_algo, &oid)) {
1299 - if (do_die)
1300 - die(_("missing mapping of %s to %s"),
1301 - oid_to_hex(input_oid), the_hash_algo->name);
1302 - return -1;
1303 - }
1304 -
1305 - /* Is new_oi needed? */
1306 - oi = input_oi;
1307 - if (input_oi && (input_oi->delta_base_oid || input_oi->sizep ||
1308 - input_oi->contentp)) {
1309 - new_oi = *input_oi;
1310 - /* Does delta_base_oid need to be converted? */
1311 - if (input_oi->delta_base_oid)
1312 - new_oi.delta_base_oid = &delta_base_oid;
1313 - /* Will the attributes differ when converted? */
1314 - if (input_oi->sizep || input_oi->contentp) {
1315 - new_oi.contentp = &content;
1316 - new_oi.sizep = &size;
1317 - new_oi.type_name = &type_name;
1318 - }
1319 - oi = &new_oi;
1320 - }
1321 -
1322 - ret = oid_object_info_extended(r, &oid, oi, flags);
1323 - if (ret)
1324 - return -1;
1325 - if (oi == input_oi)
1326 - return ret;
1327 -
1328 - if (new_oi.contentp) {
1329 - struct strbuf outbuf = STRBUF_INIT;
1330 - enum object_type type;
1331 -
1332 - type = type_from_string_gently(type_name.buf, type_name.len,
1333 - !do_die);
1334 - if (type == -1)
1335 - return -1;
1336 - if (type != OBJ_BLOB) {
1337 - ret = convert_object_file(the_repository, &outbuf,
1338 - the_hash_algo, input_algo,
1339 - content, size, type, !do_die);
1340 - free(content);
1341 - if (ret == -1)
1342 - return -1;
1343 - size = outbuf.len;
1344 - content = strbuf_detach(&outbuf, NULL);
1345 - }
1346 - if (input_oi->sizep)
1347 - *input_oi->sizep = size;
1348 - if (input_oi->contentp)
1349 - *input_oi->contentp = content;
1350 - else
1351 - free(content);
1352 - if (input_oi->type_name)
1353 - *input_oi->type_name = type_name;
1354 - else
1355 - strbuf_release(&type_name);
1356 - }
1357 - if (new_oi.delta_base_oid == &delta_base_oid) {
1358 - if (repo_oid_to_algop(r, &delta_base_oid, input_algo,
1359 - input_oi->delta_base_oid)) {
1360 - if (do_die)
1361 - die(_("missing mapping of %s to %s"),
1362 - oid_to_hex(&delta_base_oid),
1363 - input_algo->name);
1364 - return -1;
1365 - }
1366 - }
1367 - input_oi->whence = new_oi.whence;
1368 - input_oi->u = new_oi.u;
1369 - return ret;
1370 -}
1371 -
1372 -int oid_object_info_extended(struct repository *r, const struct object_id *oid,
1373 - struct object_info *oi, unsigned flags)
1374 -{
1375 - int ret;
1376 -
1377 - if (oid->algo && (hash_algo_by_ptr(r->hash_algo) != oid->algo))
1378 - return oid_object_info_convert(r, oid, oi, flags);
1379 -
1380 - obj_read_lock();
1381 - ret = do_oid_object_info_extended(r, oid, oi, flags);
1382 - obj_read_unlock();
1383 - return ret;
1384 -}
1385 -
1386 -
1387 -/* returns enum object_type or negative */
1388 -int oid_object_info(struct repository *r,
1389 - const struct object_id *oid,
1390 - unsigned long *sizep)
1391 -{
1392 - enum object_type type;
1393 - struct object_info oi = OBJECT_INFO_INIT;
1394 -
1395 - oi.typep = &type;
1396 - oi.sizep = sizep;
1397 - if (oid_object_info_extended(r, oid, &oi,
1398 - OBJECT_INFO_LOOKUP_REPLACE) < 0)
1399 - return -1;
1400 - return type;
1401 -}
1402 -
1403 -int pretend_object_file(void *buf, unsigned long len, enum object_type type,
1404 - struct object_id *oid)
1405 -{
1406 - struct cached_object_entry *co;
1407 - char *co_buf;
1408 -
1409 - hash_object_file(the_hash_algo, buf, len, type, oid);
1410 - if (repo_has_object_file_with_flags(the_repository, oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
1411 - find_cached_object(oid))
1412 - return 0;
1413 - ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
1414 - co = &cached_objects[cached_object_nr++];
1415 - co->value.size = len;
1416 - co->value.type = type;
1417 - co_buf = xmalloc(len);
1418 - memcpy(co_buf, buf, len);
1419 - co->value.buf = co_buf;
1420 - oidcpy(&co->oid, oid);
1421 - return 0;
1422 -}
1423 -
1424 -/*
1425 - * This function dies on corrupt objects; the callers who want to
1426 - * deal with them should arrange to call oid_object_info_extended() and give
1427 - * error messages themselves.
1428 - */
1429 -void *repo_read_object_file(struct repository *r,
1430 - const struct object_id *oid,
1431 - enum object_type *type,
1432 - unsigned long *size)
1433 -{
1434 - struct object_info oi = OBJECT_INFO_INIT;
1435 - unsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_LOOKUP_REPLACE;
1436 - void *data;
1437 -
1438 - oi.typep = type;
1439 - oi.sizep = size;
1440 - oi.contentp = &data;
1441 - if (oid_object_info_extended(r, oid, &oi, flags))
1442 - return NULL;
1443 -
1444 - return data;
1445 -}
1446 -
1447 -void *read_object_with_reference(struct repository *r,
1448 - const struct object_id *oid,
1449 - enum object_type required_type,
1450 - unsigned long *size,
1451 - struct object_id *actual_oid_return)
1452 -{
1453 - enum object_type type;
1454 - void *buffer;
1455 - unsigned long isize;
1456 - struct object_id actual_oid;
1457 -
1458 - oidcpy(&actual_oid, oid);
1459 - while (1) {
1460 - int ref_length = -1;
1461 - const char *ref_type = NULL;
1462 -
1463 - buffer = repo_read_object_file(r, &actual_oid, &type, &isize);
1464 - if (!buffer)
1465 - return NULL;
1466 - if (type == required_type) {
1467 - *size = isize;
1468 - if (actual_oid_return)
1469 - oidcpy(actual_oid_return, &actual_oid);
1470 - return buffer;
1471 - }
1472 - /* Handle references */
1473 - else if (type == OBJ_COMMIT)
1474 - ref_type = "tree ";
1475 - else if (type == OBJ_TAG)
1476 - ref_type = "object ";
1477 - else {
1478 - free(buffer);
1479 - return NULL;
1480 - }
1481 - ref_length = strlen(ref_type);
1482 -
1483 - if (ref_length + the_hash_algo->hexsz > isize ||
1484 - memcmp(buffer, ref_type, ref_length) ||
1485 - get_oid_hex((char *) buffer + ref_length, &actual_oid)) {
1486 - free(buffer);
1487 - return NULL;
1488 - }
1489 - free(buffer);
1490 - /* Now we have the ID of the referred-to object in
1491 - * actual_oid. Check again. */
1492 - }
1493 -}
1494 -
567 static void hash_object_body(const struct git_hash_algo *algo, struct git_hash_ctx *c,
568 const void *buf, unsigned long len,
569 struct object_id *oid,
@@ -2154,32 +1226,6 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
1226 return ret;
1227 }
1228
2157 -int has_object(struct repository *r, const struct object_id *oid,
2158 - unsigned flags)
2159 -{
2160 - int quick = !(flags & HAS_OBJECT_RECHECK_PACKED);
2161 - unsigned object_info_flags = OBJECT_INFO_SKIP_FETCH_OBJECT |
2162 - (quick ? OBJECT_INFO_QUICK : 0);
2163 -
2164 - if (!startup_info->have_repository)
2165 - return 0;
2166 - return oid_object_info_extended(r, oid, NULL, object_info_flags) >= 0;
2167 -}
2168 -
2169 -int repo_has_object_file_with_flags(struct repository *r,
2170 - const struct object_id *oid, int flags)
2171 -{
2172 - if (!startup_info->have_repository)
2173 - return 0;
2174 - return oid_object_info_extended(r, oid, NULL, flags) >= 0;
2175 -}
2176 -
2177 -int repo_has_object_file(struct repository *r,
2178 - const struct object_id *oid)
2179 -{
2180 - return repo_has_object_file_with_flags(r, oid, 0);
2181 -}
2182 -
1229 /*
1230 * We can't use the normal fsck_error_function() for index_mem(),
1231 * because we don't yet have a valid oid for it to report. Instead,
@@ -2407,16 +1453,6 @@ int read_pack_header(int fd, struct pack_header *header)
1453 return 0;
1454 }
1455
2410 -void assert_oid_type(const struct object_id *oid, enum object_type expect)
2411 -{
2412 - enum object_type type = oid_object_info(the_repository, oid, NULL);
2413 - if (type < 0)
2414 - die(_("%s is not a valid object"), oid_to_hex(oid));
2415 - if (type != expect)
2416 - die(_("%s is not a valid '%s' object"), oid_to_hex(oid),
2417 - type_name(expect));
2418 -}
2419 -
1456 int for_each_file_in_obj_subdir(unsigned int subdir_nr,
1457 struct strbuf *path,
1458 each_loose_object_fn obj_cb,
object-file.h
+63 -5
@@ -21,6 +21,29 @@ extern int fetch_if_missing;
21 int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
22 int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
23
24 +struct object_directory;
25 +
26 +const char *odb_loose_path(struct object_directory *odb,
27 + struct strbuf *buf,
28 + const struct object_id *oid);
29 +
30 +/*
31 + * Return true iff an alternate object database has a loose object
32 + * with the specified name. This function does not respect replace
33 + * references.
34 + */
35 +int has_loose_object_nonlocal(const struct object_id *);
36 +
37 +int has_loose_object(const struct object_id *);
38 +
39 +/**
40 + * format_object_header() is a thin wrapper around s xsnprintf() that
41 + * writes the initial "<type> <obj-len>" part of the loose object
42 + * header. It returns the size that snprintf() returns + 1.
43 + */
44 +int format_object_header(char *str, size_t size, enum object_type type,
45 + size_t objsize);
46 +
47 /**
48 * unpack_loose_header() initializes the data stream needed to unpack
49 * a loose object header.
@@ -61,6 +84,29 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
84 struct object_info;
85 int parse_loose_header(const char *hdr, struct object_info *oi);
86
87 +int write_object_file_flags(const void *buf, unsigned long len,
88 + enum object_type type, struct object_id *oid,
89 + struct object_id *comapt_oid_in, unsigned flags);
90 +static inline int write_object_file(const void *buf, unsigned long len,
91 + enum object_type type, struct object_id *oid)
92 +{
93 + return write_object_file_flags(buf, len, type, oid, NULL, 0);
94 +}
95 +
96 +struct input_stream {
97 + const void *(*read)(struct input_stream *, unsigned long *len);
98 + void *data;
99 + int is_finished;
100 +};
101 +
102 +int write_object_file_literally(const void *buf, unsigned long len,
103 + const char *type, struct object_id *oid,
104 + unsigned flags);
105 +int stream_loose_object(struct input_stream *in_stream, size_t len,
106 + struct object_id *oid);
107 +
108 +int force_object_loose(const struct object_id *oid, time_t mtime);
109 +
110 /**
111 * With in-core object data in "buf", rehash it to make sure the
112 * object name actually matches "oid" to detect object corruption.
@@ -79,6 +125,10 @@ int check_object_signature(struct repository *r, const struct object_id *oid,
125 */
126 int stream_object_signature(struct repository *r, const struct object_id *oid);
127
128 +int loose_object_info(struct repository *r,
129 + const struct object_id *oid,
130 + struct object_info *oi, int flags);
131 +
132 enum finalize_object_file_flags {
133 FOF_SKIP_COLLISION_CHECK = 1,
134 };
@@ -90,10 +140,18 @@ int finalize_object_file_flags(const char *tmpfile, const char *filename,
140 /* Helper to check and "touch" a file */
141 int check_and_freshen_file(const char *fn, int freshen);
142
93 -void *read_object_with_reference(struct repository *r,
94 - const struct object_id *oid,
95 - enum object_type required_type,
96 - unsigned long *size,
97 - struct object_id *oid_ret);
143 +/*
144 + * Open the loose object at path, check its hash, and return the contents,
145 + * use the "oi" argument to assert things about the object, or e.g. populate its
146 + * type, and size. If the object is a blob, then "contents" may return NULL,
147 + * to allow streaming of large blobs.
148 + *
149 + * Returns 0 on success, negative on error (details may be written to stderr).
150 + */
151 +int read_loose_object(const char *path,
152 + const struct object_id *expected_oid,
153 + struct object_id *real_oid,
154 + void **contents,
155 + struct object_info *oi);
156
157 #endif /* OBJECT_FILE_H */
object-store-ll.h
+6 -54
@@ -49,12 +49,6 @@ struct object_directory {
49 char *path;
50 };
51
52 -struct input_stream {
53 - const void *(*read)(struct input_stream *, unsigned long *len);
54 - void *data;
55 - int is_finished;
56 -};
57 -
52 void prepare_alt_odb(struct repository *r);
53 int has_alt_odb(struct repository *r);
54 char *compute_alternate_path(const char *path, struct strbuf *err);
@@ -273,21 +267,6 @@ void hash_object_file(const struct git_hash_algo *algo, const void *buf,
267 unsigned long len, enum object_type type,
268 struct object_id *oid);
269
276 -int write_object_file_flags(const void *buf, unsigned long len,
277 - enum object_type type, struct object_id *oid,
278 - struct object_id *comapt_oid_in, unsigned flags);
279 -static inline int write_object_file(const void *buf, unsigned long len,
280 - enum object_type type, struct object_id *oid)
281 -{
282 - return write_object_file_flags(buf, len, type, oid, NULL, 0);
283 -}
284 -
285 -int write_object_file_literally(const void *buf, unsigned long len,
286 - const char *type, struct object_id *oid,
287 - unsigned flags);
288 -int stream_loose_object(struct input_stream *in_stream, size_t len,
289 - struct object_id *oid);
290 -
270 /*
271 * Add an object file to the in-memory object store, without writing it
272 * to disk.
@@ -299,8 +278,6 @@ int stream_loose_object(struct input_stream *in_stream, size_t len,
278 int pretend_object_file(void *, unsigned long, enum object_type,
279 struct object_id *oid);
280
302 -int force_object_loose(const struct object_id *oid, time_t mtime);
303 -
281 struct object_info {
282 /* Request */
283 enum object_type *typep;
@@ -364,20 +341,6 @@ int oid_object_info_extended(struct repository *r,
341 const struct object_id *,
342 struct object_info *, unsigned flags);
343
367 -/*
368 - * Open the loose object at path, check its hash, and return the contents,
369 - * use the "oi" argument to assert things about the object, or e.g. populate its
370 - * type, and size. If the object is a blob, then "contents" may return NULL,
371 - * to allow streaming of large blobs.
372 - *
373 - * Returns 0 on success, negative on error (details may be written to stderr).
374 - */
375 -int read_loose_object(const char *path,
376 - const struct object_id *expected_oid,
377 - struct object_id *real_oid,
378 - void **contents,
379 - struct object_info *oi);
380 -
344 /* Retry packed storage after checking packed and loose storage */
345 #define HAS_OBJECT_RECHECK_PACKED 1
346
@@ -405,23 +368,6 @@ int repo_has_object_file(struct repository *r, const struct object_id *oid);
368 int repo_has_object_file_with_flags(struct repository *r,
369 const struct object_id *oid, int flags);
370
408 -/*
409 - * Return true iff an alternate object database has a loose object
410 - * with the specified name. This function does not respect replace
411 - * references.
412 - */
413 -int has_loose_object_nonlocal(const struct object_id *);
414 -
415 -int has_loose_object(const struct object_id *);
416 -
417 -/**
418 - * format_object_header() is a thin wrapper around s xsnprintf() that
419 - * writes the initial "<type> <obj-len>" part of the loose object
420 - * header. It returns the size that snprintf() returns + 1.
421 - */
422 -int format_object_header(char *str, size_t size, enum object_type type,
423 - size_t objsize);
424 -
371 void assert_oid_type(const struct object_id *oid, enum object_type expect);
372
373 /*
@@ -553,4 +499,10 @@ int for_each_object_in_pack(struct packed_git *p,
499 int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
500 void *data, enum for_each_object_flags flags);
501
502 +void *read_object_with_reference(struct repository *r,
503 + const struct object_id *oid,
504 + enum object_type required_type,
505 + unsigned long *size,
506 + struct object_id *oid_ret);
507 +
508 #endif /* OBJECT_STORE_LL_H */
object-store.c new
+972
@@ -0,0 +1,972 @@
1 +#define USE_THE_REPOSITORY_VARIABLE
2 +
3 +#include "git-compat-util.h"
4 +#include "abspath.h"
5 +#include "config.h"
6 +#include "environment.h"
7 +#include "gettext.h"
8 +#include "hex.h"
9 +#include "lockfile.h"
10 +#include "object-file-convert.h"
11 +#include "object-file.h"
12 +#include "object-store.h"
13 +#include "packfile.h"
14 +#include "path.h"
15 +#include "promisor-remote.h"
16 +#include "quote.h"
17 +#include "replace-object.h"
18 +#include "run-command.h"
19 +#include "setup.h"
20 +#include "strbuf.h"
21 +#include "strvec.h"
22 +#include "submodule.h"
23 +#include "write-or-die.h"
24 +
25 +/*
26 + * This is meant to hold a *small* number of objects that you would
27 + * want repo_read_object_file() to be able to return, but yet you do not want
28 + * to write them into the object store (e.g. a browse-only
29 + * application).
30 + */
31 +static struct cached_object_entry {
32 + struct object_id oid;
33 + struct cached_object {
34 + enum object_type type;
35 + const void *buf;
36 + unsigned long size;
37 + } value;
38 +} *cached_objects;
39 +static int cached_object_nr, cached_object_alloc;
40 +
41 +static const struct cached_object *find_cached_object(const struct object_id *oid)
42 +{
43 + static const struct cached_object empty_tree = {
44 + .type = OBJ_TREE,
45 + .buf = "",
46 + };
47 + int i;
48 + const struct cached_object_entry *co = cached_objects;
49 +
50 + for (i = 0; i < cached_object_nr; i++, co++) {
51 + if (oideq(&co->oid, oid))
52 + return &co->value;
53 + }
54 + if (oideq(oid, the_hash_algo->empty_tree))
55 + return &empty_tree;
56 + return NULL;
57 +}
58 +
59 +int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
60 +{
61 + int fd;
62 + /*
63 + * we let the umask do its job, don't try to be more
64 + * restrictive except to remove write permission.
65 + */
66 + int mode = 0444;
67 + repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
68 + fd = git_mkstemp_mode(temp_filename->buf, mode);
69 + if (0 <= fd)
70 + return fd;
71 +
72 + /* slow path */
73 + /* some mkstemp implementations erase temp_filename on failure */
74 + repo_git_path_replace(the_repository, temp_filename, "objects/%s", pattern);
75 + safe_create_leading_directories(the_repository, temp_filename->buf);
76 + return xmkstemp_mode(temp_filename->buf, mode);
77 +}
78 +
79 +int odb_pack_keep(const char *name)
80 +{
81 + int fd;
82 +
83 + fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
84 + if (0 <= fd)
85 + return fd;
86 +
87 + /* slow path */
88 + safe_create_leading_directories_const(the_repository, name);
89 + return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
90 +}
91 +
92 +const char *loose_object_path(struct repository *r, struct strbuf *buf,
93 + const struct object_id *oid)
94 +{
95 + return odb_loose_path(r->objects->odb, buf, oid);
96 +}
97 +
98 +/*
99 + * Return non-zero iff the path is usable as an alternate object database.
100 + */
101 +static int alt_odb_usable(struct raw_object_store *o,
102 + struct strbuf *path,
103 + const char *normalized_objdir, khiter_t *pos)
104 +{
105 + int r;
106 +
107 + /* Detect cases where alternate disappeared */
108 + if (!is_directory(path->buf)) {
109 + error(_("object directory %s does not exist; "
110 + "check .git/objects/info/alternates"),
111 + path->buf);
112 + return 0;
113 + }
114 +
115 + /*
116 + * Prevent the common mistake of listing the same
117 + * thing twice, or object directory itself.
118 + */
119 + if (!o->odb_by_path) {
120 + khiter_t p;
121 +
122 + o->odb_by_path = kh_init_odb_path_map();
123 + assert(!o->odb->next);
124 + p = kh_put_odb_path_map(o->odb_by_path, o->odb->path, &r);
125 + assert(r == 1); /* never used */
126 + kh_value(o->odb_by_path, p) = o->odb;
127 + }
128 + if (fspatheq(path->buf, normalized_objdir))
129 + return 0;
130 + *pos = kh_put_odb_path_map(o->odb_by_path, path->buf, &r);
131 + /* r: 0 = exists, 1 = never used, 2 = deleted */
132 + return r == 0 ? 0 : 1;
133 +}
134 +
135 +/*
136 + * Prepare alternate object database registry.
137 + *
138 + * The variable alt_odb_list points at the list of struct
139 + * object_directory. The elements on this list come from
140 + * non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
141 + * environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
142 + * whose contents is similar to that environment variable but can be
143 + * LF separated. Its base points at a statically allocated buffer that
144 + * contains "/the/directory/corresponding/to/.git/objects/...", while
145 + * its name points just after the slash at the end of ".git/objects/"
146 + * in the example above, and has enough space to hold all hex characters
147 + * of the object ID, an extra slash for the first level indirection, and
148 + * the terminating NUL.
149 + */
150 +static void read_info_alternates(struct repository *r,
151 + const char *relative_base,
152 + int depth);
153 +static int link_alt_odb_entry(struct repository *r, const struct strbuf *entry,
154 + const char *relative_base, int depth, const char *normalized_objdir)
155 +{
156 + struct object_directory *ent;
157 + struct strbuf pathbuf = STRBUF_INIT;
158 + struct strbuf tmp = STRBUF_INIT;
159 + khiter_t pos;
160 + int ret = -1;
161 +
162 + if (!is_absolute_path(entry->buf) && relative_base) {
163 + strbuf_realpath(&pathbuf, relative_base, 1);
164 + strbuf_addch(&pathbuf, '/');
165 + }
166 + strbuf_addbuf(&pathbuf, entry);
167 +
168 + if (!strbuf_realpath(&tmp, pathbuf.buf, 0)) {
169 + error(_("unable to normalize alternate object path: %s"),
170 + pathbuf.buf);
171 + goto error;
172 + }
173 + strbuf_swap(&pathbuf, &tmp);
174 +
175 + /*
176 + * The trailing slash after the directory name is given by
177 + * this function at the end. Remove duplicates.
178 + */
179 + while (pathbuf.len && pathbuf.buf[pathbuf.len - 1] == '/')
180 + strbuf_setlen(&pathbuf, pathbuf.len - 1);
181 +
182 + if (!alt_odb_usable(r->objects, &pathbuf, normalized_objdir, &pos))
183 + goto error;
184 +
185 + CALLOC_ARRAY(ent, 1);
186 + /* pathbuf.buf is already in r->objects->odb_by_path */
187 + ent->path = strbuf_detach(&pathbuf, NULL);
188 +
189 + /* add the alternate entry */
190 + *r->objects->odb_tail = ent;
191 + r->objects->odb_tail = &(ent->next);
192 + ent->next = NULL;
193 + assert(r->objects->odb_by_path);
194 + kh_value(r->objects->odb_by_path, pos) = ent;
195 +
196 + /* recursively add alternates */
197 + read_info_alternates(r, ent->path, depth + 1);
198 + ret = 0;
199 + error:
200 + strbuf_release(&tmp);
201 + strbuf_release(&pathbuf);
202 + return ret;
203 +}
204 +
205 +static const char *parse_alt_odb_entry(const char *string,
206 + int sep,
207 + struct strbuf *out)
208 +{
209 + const char *end;
210 +
211 + strbuf_reset(out);
212 +
213 + if (*string == '#') {
214 + /* comment; consume up to next separator */
215 + end = strchrnul(string, sep);
216 + } else if (*string == '"' && !unquote_c_style(out, string, &end)) {
217 + /*
218 + * quoted path; unquote_c_style has copied the
219 + * data for us and set "end". Broken quoting (e.g.,
220 + * an entry that doesn't end with a quote) falls
221 + * back to the unquoted case below.
222 + */
223 + } else {
224 + /* normal, unquoted path */
225 + end = strchrnul(string, sep);
226 + strbuf_add(out, string, end - string);
227 + }
228 +
229 + if (*end)
230 + end++;
231 + return end;
232 +}
233 +
234 +static void link_alt_odb_entries(struct repository *r, const char *alt,
235 + int sep, const char *relative_base, int depth)
236 +{
237 + struct strbuf objdirbuf = STRBUF_INIT;
238 + struct strbuf entry = STRBUF_INIT;
239 +
240 + if (!alt || !*alt)
241 + return;
242 +
243 + if (depth > 5) {
244 + error(_("%s: ignoring alternate object stores, nesting too deep"),
245 + relative_base);
246 + return;
247 + }
248 +
249 + strbuf_realpath(&objdirbuf, r->objects->odb->path, 1);
250 +
251 + while (*alt) {
252 + alt = parse_alt_odb_entry(alt, sep, &entry);
253 + if (!entry.len)
254 + continue;
255 + link_alt_odb_entry(r, &entry,
256 + relative_base, depth, objdirbuf.buf);
257 + }
258 + strbuf_release(&entry);
259 + strbuf_release(&objdirbuf);
260 +}
261 +
262 +static void read_info_alternates(struct repository *r,
263 + const char *relative_base,
264 + int depth)
265 +{
266 + char *path;
267 + struct strbuf buf = STRBUF_INIT;
268 +
269 + path = xstrfmt("%s/info/alternates", relative_base);
270 + if (strbuf_read_file(&buf, path, 1024) < 0) {
271 + warn_on_fopen_errors(path);
272 + free(path);
273 + return;
274 + }
275 +
276 + link_alt_odb_entries(r, buf.buf, '\n', relative_base, depth);
277 + strbuf_release(&buf);
278 + free(path);
279 +}
280 +
281 +void add_to_alternates_file(const char *reference)
282 +{
283 + struct lock_file lock = LOCK_INIT;
284 + char *alts = repo_git_path(the_repository, "objects/info/alternates");
285 + FILE *in, *out;
286 + int found = 0;
287 +
288 + hold_lock_file_for_update(&lock, alts, LOCK_DIE_ON_ERROR);
289 + out = fdopen_lock_file(&lock, "w");
290 + if (!out)
291 + die_errno(_("unable to fdopen alternates lockfile"));
292 +
293 + in = fopen(alts, "r");
294 + if (in) {
295 + struct strbuf line = STRBUF_INIT;
296 +
297 + while (strbuf_getline(&line, in) != EOF) {
298 + if (!strcmp(reference, line.buf)) {
299 + found = 1;
300 + break;
301 + }
302 + fprintf_or_die(out, "%s\n", line.buf);
303 + }
304 +
305 + strbuf_release(&line);
306 + fclose(in);
307 + }
308 + else if (errno != ENOENT)
309 + die_errno(_("unable to read alternates file"));
310 +
311 + if (found) {
312 + rollback_lock_file(&lock);
313 + } else {
314 + fprintf_or_die(out, "%s\n", reference);
315 + if (commit_lock_file(&lock))
316 + die_errno(_("unable to move new alternates file into place"));
317 + if (the_repository->objects->loaded_alternates)
318 + link_alt_odb_entries(the_repository, reference,
319 + '\n', NULL, 0);
320 + }
321 + free(alts);
322 +}
323 +
324 +void add_to_alternates_memory(const char *reference)
325 +{
326 + /*
327 + * Make sure alternates are initialized, or else our entry may be
328 + * overwritten when they are.
329 + */
330 + prepare_alt_odb(the_repository);
331 +
332 + link_alt_odb_entries(the_repository, reference,
333 + '\n', NULL, 0);
334 +}
335 +
336 +struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy)
337 +{
338 + struct object_directory *new_odb;
339 +
340 + /*
341 + * Make sure alternates are initialized, or else our entry may be
342 + * overwritten when they are.
343 + */
344 + prepare_alt_odb(the_repository);
345 +
346 + /*
347 + * Make a new primary odb and link the old primary ODB in as an
348 + * alternate
349 + */
350 + new_odb = xcalloc(1, sizeof(*new_odb));
351 + new_odb->path = xstrdup(dir);
352 +
353 + /*
354 + * Disable ref updates while a temporary odb is active, since
355 + * the objects in the database may roll back.
356 + */
357 + new_odb->disable_ref_updates = 1;
358 + new_odb->will_destroy = will_destroy;
359 + new_odb->next = the_repository->objects->odb;
360 + the_repository->objects->odb = new_odb;
361 + return new_odb->next;
362 +}
363 +
364 +void restore_primary_odb(struct object_directory *restore_odb, const char *old_path)
365 +{
366 + struct object_directory *cur_odb = the_repository->objects->odb;
367 +
368 + if (strcmp(old_path, cur_odb->path))
369 + BUG("expected %s as primary object store; found %s",
370 + old_path, cur_odb->path);
371 +
372 + if (cur_odb->next != restore_odb)
373 + BUG("we expect the old primary object store to be the first alternate");
374 +
375 + the_repository->objects->odb = restore_odb;
376 + free_object_directory(cur_odb);
377 +}
378 +
379 +/*
380 + * Compute the exact path an alternate is at and returns it. In case of
381 + * error NULL is returned and the human readable error is added to `err`
382 + * `path` may be relative and should point to $GIT_DIR.
383 + * `err` must not be null.
384 + */
385 +char *compute_alternate_path(const char *path, struct strbuf *err)
386 +{
387 + char *ref_git = NULL;
388 + const char *repo;
389 + int seen_error = 0;
390 +
391 + ref_git = real_pathdup(path, 0);
392 + if (!ref_git) {
393 + seen_error = 1;
394 + strbuf_addf(err, _("path '%s' does not exist"), path);
395 + goto out;
396 + }
397 +
398 + repo = read_gitfile(ref_git);
399 + if (!repo)
400 + repo = read_gitfile(mkpath("%s/.git", ref_git));
401 + if (repo) {
402 + free(ref_git);
403 + ref_git = xstrdup(repo);
404 + }
405 +
406 + if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) {
407 + char *ref_git_git = mkpathdup("%s/.git", ref_git);
408 + free(ref_git);
409 + ref_git = ref_git_git;
410 + } else if (!is_directory(mkpath("%s/objects", ref_git))) {
411 + struct strbuf sb = STRBUF_INIT;
412 + seen_error = 1;
413 + if (get_common_dir(&sb, ref_git)) {
414 + strbuf_addf(err,
415 + _("reference repository '%s' as a linked "
416 + "checkout is not supported yet."),
417 + path);
418 + goto out;
419 + }
420 +
421 + strbuf_addf(err, _("reference repository '%s' is not a "
422 + "local repository."), path);
423 + goto out;
424 + }
425 +
426 + if (!access(mkpath("%s/shallow", ref_git), F_OK)) {
427 + strbuf_addf(err, _("reference repository '%s' is shallow"),
428 + path);
429 + seen_error = 1;
430 + goto out;
431 + }
432 +
433 + if (!access(mkpath("%s/info/grafts", ref_git), F_OK)) {
434 + strbuf_addf(err,
435 + _("reference repository '%s' is grafted"),
436 + path);
437 + seen_error = 1;
438 + goto out;
439 + }
440 +
441 +out:
442 + if (seen_error) {
443 + FREE_AND_NULL(ref_git);
444 + }
445 +
446 + return ref_git;
447 +}
448 +
449 +struct object_directory *find_odb(struct repository *r, const char *obj_dir)
450 +{
451 + struct object_directory *odb;
452 + char *obj_dir_real = real_pathdup(obj_dir, 1);
453 + struct strbuf odb_path_real = STRBUF_INIT;
454 +
455 + prepare_alt_odb(r);
456 + for (odb = r->objects->odb; odb; odb = odb->next) {
457 + strbuf_realpath(&odb_path_real, odb->path, 1);
458 + if (!strcmp(obj_dir_real, odb_path_real.buf))
459 + break;
460 + }
461 +
462 + free(obj_dir_real);
463 + strbuf_release(&odb_path_real);
464 +
465 + if (!odb)
466 + die(_("could not find object directory matching %s"), obj_dir);
467 + return odb;
468 +}
469 +
470 +static void fill_alternate_refs_command(struct child_process *cmd,
471 + const char *repo_path)
472 +{
473 + const char *value;
474 +
475 + if (!git_config_get_value("core.alternateRefsCommand", &value)) {
476 + cmd->use_shell = 1;
477 +
478 + strvec_push(&cmd->args, value);
479 + strvec_push(&cmd->args, repo_path);
480 + } else {
481 + cmd->git_cmd = 1;
482 +
483 + strvec_pushf(&cmd->args, "--git-dir=%s", repo_path);
484 + strvec_push(&cmd->args, "for-each-ref");
485 + strvec_push(&cmd->args, "--format=%(objectname)");
486 +
487 + if (!git_config_get_value("core.alternateRefsPrefixes", &value)) {
488 + strvec_push(&cmd->args, "--");
489 + strvec_split(&cmd->args, value);
490 + }
491 + }
492 +
493 + strvec_pushv(&cmd->env, (const char **)local_repo_env);
494 + cmd->out = -1;
495 +}
496 +
497 +static void read_alternate_refs(const char *path,
498 + alternate_ref_fn *cb,
499 + void *data)
500 +{
501 + struct child_process cmd = CHILD_PROCESS_INIT;
502 + struct strbuf line = STRBUF_INIT;
503 + FILE *fh;
504 +
505 + fill_alternate_refs_command(&cmd, path);
506 +
507 + if (start_command(&cmd))
508 + return;
509 +
510 + fh = xfdopen(cmd.out, "r");
511 + while (strbuf_getline_lf(&line, fh) != EOF) {
512 + struct object_id oid;
513 + const char *p;
514 +
515 + if (parse_oid_hex(line.buf, &oid, &p) || *p) {
516 + warning(_("invalid line while parsing alternate refs: %s"),
517 + line.buf);
518 + break;
519 + }
520 +
521 + cb(&oid, data);
522 + }
523 +
524 + fclose(fh);
525 + finish_command(&cmd);
526 + strbuf_release(&line);
527 +}
528 +
529 +struct alternate_refs_data {
530 + alternate_ref_fn *fn;
531 + void *data;
532 +};
533 +
534 +static int refs_from_alternate_cb(struct object_directory *e,
535 + void *data)
536 +{
537 + struct strbuf path = STRBUF_INIT;
538 + size_t base_len;
539 + struct alternate_refs_data *cb = data;
540 +
541 + if (!strbuf_realpath(&path, e->path, 0))
542 + goto out;
543 + if (!strbuf_strip_suffix(&path, "/objects"))
544 + goto out;
545 + base_len = path.len;
546 +
547 + /* Is this a git repository with refs? */
548 + strbuf_addstr(&path, "/refs");
549 + if (!is_directory(path.buf))
550 + goto out;
551 + strbuf_setlen(&path, base_len);
552 +
553 + read_alternate_refs(path.buf, cb->fn, cb->data);
554 +
555 +out:
556 + strbuf_release(&path);
557 + return 0;
558 +}
559 +
560 +void for_each_alternate_ref(alternate_ref_fn fn, void *data)
561 +{
562 + struct alternate_refs_data cb;
563 + cb.fn = fn;
564 + cb.data = data;
565 + foreach_alt_odb(refs_from_alternate_cb, &cb);
566 +}
567 +
568 +int foreach_alt_odb(alt_odb_fn fn, void *cb)
569 +{
570 + struct object_directory *ent;
571 + int r = 0;
572 +
573 + prepare_alt_odb(the_repository);
574 + for (ent = the_repository->objects->odb->next; ent; ent = ent->next) {
575 + r = fn(ent, cb);
576 + if (r)
577 + break;
578 + }
579 + return r;
580 +}
581 +
582 +void prepare_alt_odb(struct repository *r)
583 +{
584 + if (r->objects->loaded_alternates)
585 + return;
586 +
587 + link_alt_odb_entries(r, r->objects->alternate_db, PATH_SEP, NULL, 0);
588 +
589 + read_info_alternates(r, r->objects->odb->path, 0);
590 + r->objects->loaded_alternates = 1;
591 +}
592 +
593 +int has_alt_odb(struct repository *r)
594 +{
595 + prepare_alt_odb(r);
596 + return !!r->objects->odb->next;
597 +}
598 +
599 +int obj_read_use_lock = 0;
600 +pthread_mutex_t obj_read_mutex;
601 +
602 +void enable_obj_read_lock(void)
603 +{
604 + if (obj_read_use_lock)
605 + return;
606 +
607 + obj_read_use_lock = 1;
608 + init_recursive_mutex(&obj_read_mutex);
609 +}
610 +
611 +void disable_obj_read_lock(void)
612 +{
613 + if (!obj_read_use_lock)
614 + return;
615 +
616 + obj_read_use_lock = 0;
617 + pthread_mutex_destroy(&obj_read_mutex);
618 +}
619 +
620 +int fetch_if_missing = 1;
621 +
622 +static int do_oid_object_info_extended(struct repository *r,
623 + const struct object_id *oid,
624 + struct object_info *oi, unsigned flags)
625 +{
626 + static struct object_info blank_oi = OBJECT_INFO_INIT;
627 + const struct cached_object *co;
628 + struct pack_entry e;
629 + int rtype;
630 + const struct object_id *real = oid;
631 + int already_retried = 0;
632 +
633 +
634 + if (flags & OBJECT_INFO_LOOKUP_REPLACE)
635 + real = lookup_replace_object(r, oid);
636 +
637 + if (is_null_oid(real))
638 + return -1;
639 +
640 + if (!oi)
641 + oi = &blank_oi;
642 +
643 + co = find_cached_object(real);
644 + if (co) {
645 + if (oi->typep)
646 + *(oi->typep) = co->type;
647 + if (oi->sizep)
648 + *(oi->sizep) = co->size;
649 + if (oi->disk_sizep)
650 + *(oi->disk_sizep) = 0;
651 + if (oi->delta_base_oid)
652 + oidclr(oi->delta_base_oid, the_repository->hash_algo);
653 + if (oi->type_name)
654 + strbuf_addstr(oi->type_name, type_name(co->type));
655 + if (oi->contentp)
656 + *oi->contentp = xmemdupz(co->buf, co->size);
657 + oi->whence = OI_CACHED;
658 + return 0;
659 + }
660 +
661 + while (1) {
662 + if (find_pack_entry(r, real, &e))
663 + break;
664 +
665 + /* Most likely it's a loose object. */
666 + if (!loose_object_info(r, real, oi, flags))
667 + return 0;
668 +
669 + /* Not a loose object; someone else may have just packed it. */
670 + if (!(flags & OBJECT_INFO_QUICK)) {
671 + reprepare_packed_git(r);
672 + if (find_pack_entry(r, real, &e))
673 + break;
674 + }
675 +
676 + /*
677 + * If r is the_repository, this might be an attempt at
678 + * accessing a submodule object as if it were in the_repository
679 + * (having called add_submodule_odb() on that submodule's ODB).
680 + * If any such ODBs exist, register them and try again.
681 + */
682 + if (r == the_repository &&
683 + register_all_submodule_odb_as_alternates())
684 + /* We added some alternates; retry */
685 + continue;
686 +
687 + /* Check if it is a missing object */
688 + if (fetch_if_missing && repo_has_promisor_remote(r) &&
689 + !already_retried &&
690 + !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
691 + promisor_remote_get_direct(r, real, 1);
692 + already_retried = 1;
693 + continue;
694 + }
695 +
696 + if (flags & OBJECT_INFO_DIE_IF_CORRUPT) {
697 + const struct packed_git *p;
698 + if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
699 + die(_("replacement %s not found for %s"),
700 + oid_to_hex(real), oid_to_hex(oid));
701 + if ((p = has_packed_and_bad(r, real)))
702 + die(_("packed object %s (stored in %s) is corrupt"),
703 + oid_to_hex(real), p->pack_name);
704 + }
705 + return -1;
706 + }
707 +
708 + if (oi == &blank_oi)
709 + /*
710 + * We know that the caller doesn't actually need the
711 + * information below, so return early.
712 + */
713 + return 0;
714 + rtype = packed_object_info(r, e.p, e.offset, oi);
715 + if (rtype < 0) {
716 + mark_bad_packed_object(e.p, real);
717 + return do_oid_object_info_extended(r, real, oi, 0);
718 + } else if (oi->whence == OI_PACKED) {
719 + oi->u.packed.offset = e.offset;
720 + oi->u.packed.pack = e.p;
721 + oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
722 + rtype == OBJ_OFS_DELTA);
723 + }
724 +
725 + return 0;
726 +}
727 +
728 +static int oid_object_info_convert(struct repository *r,
729 + const struct object_id *input_oid,
730 + struct object_info *input_oi, unsigned flags)
731 +{
732 + const struct git_hash_algo *input_algo = &hash_algos[input_oid->algo];
733 + int do_die = flags & OBJECT_INFO_DIE_IF_CORRUPT;
734 + struct strbuf type_name = STRBUF_INIT;
735 + struct object_id oid, delta_base_oid;
736 + struct object_info new_oi, *oi;
737 + unsigned long size;
738 + void *content;
739 + int ret;
740 +
741 + if (repo_oid_to_algop(r, input_oid, the_hash_algo, &oid)) {
742 + if (do_die)
743 + die(_("missing mapping of %s to %s"),
744 + oid_to_hex(input_oid), the_hash_algo->name);
745 + return -1;
746 + }
747 +
748 + /* Is new_oi needed? */
749 + oi = input_oi;
750 + if (input_oi && (input_oi->delta_base_oid || input_oi->sizep ||
751 + input_oi->contentp)) {
752 + new_oi = *input_oi;
753 + /* Does delta_base_oid need to be converted? */
754 + if (input_oi->delta_base_oid)
755 + new_oi.delta_base_oid = &delta_base_oid;
756 + /* Will the attributes differ when converted? */
757 + if (input_oi->sizep || input_oi->contentp) {
758 + new_oi.contentp = &content;
759 + new_oi.sizep = &size;
760 + new_oi.type_name = &type_name;
761 + }
762 + oi = &new_oi;
763 + }
764 +
765 + ret = oid_object_info_extended(r, &oid, oi, flags);
766 + if (ret)
767 + return -1;
768 + if (oi == input_oi)
769 + return ret;
770 +
771 + if (new_oi.contentp) {
772 + struct strbuf outbuf = STRBUF_INIT;
773 + enum object_type type;
774 +
775 + type = type_from_string_gently(type_name.buf, type_name.len,
776 + !do_die);
777 + if (type == -1)
778 + return -1;
779 + if (type != OBJ_BLOB) {
780 + ret = convert_object_file(the_repository, &outbuf,
781 + the_hash_algo, input_algo,
782 + content, size, type, !do_die);
783 + free(content);
784 + if (ret == -1)
785 + return -1;
786 + size = outbuf.len;
787 + content = strbuf_detach(&outbuf, NULL);
788 + }
789 + if (input_oi->sizep)
790 + *input_oi->sizep = size;
791 + if (input_oi->contentp)
792 + *input_oi->contentp = content;
793 + else
794 + free(content);
795 + if (input_oi->type_name)
796 + *input_oi->type_name = type_name;
797 + else
798 + strbuf_release(&type_name);
799 + }
800 + if (new_oi.delta_base_oid == &delta_base_oid) {
801 + if (repo_oid_to_algop(r, &delta_base_oid, input_algo,
802 + input_oi->delta_base_oid)) {
803 + if (do_die)
804 + die(_("missing mapping of %s to %s"),
805 + oid_to_hex(&delta_base_oid),
806 + input_algo->name);
807 + return -1;
808 + }
809 + }
810 + input_oi->whence = new_oi.whence;
811 + input_oi->u = new_oi.u;
812 + return ret;
813 +}
814 +
815 +int oid_object_info_extended(struct repository *r, const struct object_id *oid,
816 + struct object_info *oi, unsigned flags)
817 +{
818 + int ret;
819 +
820 + if (oid->algo && (hash_algo_by_ptr(r->hash_algo) != oid->algo))
821 + return oid_object_info_convert(r, oid, oi, flags);
822 +
823 + obj_read_lock();
824 + ret = do_oid_object_info_extended(r, oid, oi, flags);
825 + obj_read_unlock();
826 + return ret;
827 +}
828 +
829 +
830 +/* returns enum object_type or negative */
831 +int oid_object_info(struct repository *r,
832 + const struct object_id *oid,
833 + unsigned long *sizep)
834 +{
835 + enum object_type type;
836 + struct object_info oi = OBJECT_INFO_INIT;
837 +
838 + oi.typep = &type;
839 + oi.sizep = sizep;
840 + if (oid_object_info_extended(r, oid, &oi,
841 + OBJECT_INFO_LOOKUP_REPLACE) < 0)
842 + return -1;
843 + return type;
844 +}
845 +
846 +int pretend_object_file(void *buf, unsigned long len, enum object_type type,
847 + struct object_id *oid)
848 +{
849 + struct cached_object_entry *co;
850 + char *co_buf;
851 +
852 + hash_object_file(the_hash_algo, buf, len, type, oid);
853 + if (repo_has_object_file_with_flags(the_repository, oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) ||
854 + find_cached_object(oid))
855 + return 0;
856 + ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
857 + co = &cached_objects[cached_object_nr++];
858 + co->value.size = len;
859 + co->value.type = type;
860 + co_buf = xmalloc(len);
861 + memcpy(co_buf, buf, len);
862 + co->value.buf = co_buf;
863 + oidcpy(&co->oid, oid);
864 + return 0;
865 +}
866 +
867 +/*
868 + * This function dies on corrupt objects; the callers who want to
869 + * deal with them should arrange to call oid_object_info_extended() and give
870 + * error messages themselves.
871 + */
872 +void *repo_read_object_file(struct repository *r,
873 + const struct object_id *oid,
874 + enum object_type *type,
875 + unsigned long *size)
876 +{
877 + struct object_info oi = OBJECT_INFO_INIT;
878 + unsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_LOOKUP_REPLACE;
879 + void *data;
880 +
881 + oi.typep = type;
882 + oi.sizep = size;
883 + oi.contentp = &data;
884 + if (oid_object_info_extended(r, oid, &oi, flags))
885 + return NULL;
886 +
887 + return data;
888 +}
889 +
890 +void *read_object_with_reference(struct repository *r,
891 + const struct object_id *oid,
892 + enum object_type required_type,
893 + unsigned long *size,
894 + struct object_id *actual_oid_return)
895 +{
896 + enum object_type type;
897 + void *buffer;
898 + unsigned long isize;
899 + struct object_id actual_oid;
900 +
901 + oidcpy(&actual_oid, oid);
902 + while (1) {
903 + int ref_length = -1;
904 + const char *ref_type = NULL;
905 +
906 + buffer = repo_read_object_file(r, &actual_oid, &type, &isize);
907 + if (!buffer)
908 + return NULL;
909 + if (type == required_type) {
910 + *size = isize;
911 + if (actual_oid_return)
912 + oidcpy(actual_oid_return, &actual_oid);
913 + return buffer;
914 + }
915 + /* Handle references */
916 + else if (type == OBJ_COMMIT)
917 + ref_type = "tree ";
918 + else if (type == OBJ_TAG)
919 + ref_type = "object ";
920 + else {
921 + free(buffer);
922 + return NULL;
923 + }
924 + ref_length = strlen(ref_type);
925 +
926 + if (ref_length + the_hash_algo->hexsz > isize ||
927 + memcmp(buffer, ref_type, ref_length) ||
928 + get_oid_hex((char *) buffer + ref_length, &actual_oid)) {
929 + free(buffer);
930 + return NULL;
931 + }
932 + free(buffer);
933 + /* Now we have the ID of the referred-to object in
934 + * actual_oid. Check again. */
935 + }
936 +}
937 +
938 +int has_object(struct repository *r, const struct object_id *oid,
939 + unsigned flags)
940 +{
941 + int quick = !(flags & HAS_OBJECT_RECHECK_PACKED);
942 + unsigned object_info_flags = OBJECT_INFO_SKIP_FETCH_OBJECT |
943 + (quick ? OBJECT_INFO_QUICK : 0);
944 +
945 + if (!startup_info->have_repository)
946 + return 0;
947 + return oid_object_info_extended(r, oid, NULL, object_info_flags) >= 0;
948 +}
949 +
950 +int repo_has_object_file_with_flags(struct repository *r,
951 + const struct object_id *oid, int flags)
952 +{
953 + if (!startup_info->have_repository)
954 + return 0;
955 + return oid_object_info_extended(r, oid, NULL, flags) >= 0;
956 +}
957 +
958 +int repo_has_object_file(struct repository *r,
959 + const struct object_id *oid)
960 +{
961 + return repo_has_object_file_with_flags(r, oid, 0);
962 +}
963 +
964 +void assert_oid_type(const struct object_id *oid, enum object_type expect)
965 +{
966 + enum object_type type = oid_object_info(the_repository, oid, NULL);
967 + if (type < 0)
968 + die(_("%s is not a valid object"), oid_to_hex(oid));
969 + if (type != expect)
970 + die(_("%s is not a valid '%s' object"), oid_to_hex(oid),
971 + type_name(expect));
972 +}