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
+}