odb/source-loose: wire up `for_each_object()` callback

Move `odb_source_loose_for_each_object()` and its associated helpers from "object-file.c" into "odb/source-loose.c" and wire it up as the `for_each_object()` callback of the loose source. Again, as in the preceding commit, we are forced to expose a couple of functions from "object-file.c" that are now used by both subsystems. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jun 1, 2026 at 10:20 UTC e4f1d9ba5714957389bee87dd5f9fedb69d8a764
5 files changed +297 -305
builtin/cat-file.c
+3 -2
@@ -862,8 +862,9 @@ static void batch_each_object(struct batch_options *opt,
862 */
863 odb_prepare_alternates(the_repository->objects);
864 for (source = the_repository->objects->sources; source; source = source->next) {
865 - int ret = odb_source_loose_for_each_object(source, NULL, batch_one_object_oi,
866 - &payload, &opts);
865 + struct odb_source_files *files = odb_source_files_downcast(source);
866 + int ret = odb_source_for_each_object(&files->loose->base, NULL, batch_one_object_oi,
867 + &payload, &opts);
868 if (ret)
869 break;
870 }
object-file.c
+16 -283
@@ -22,7 +22,6 @@
22 #include "odb.h"
23 #include "odb/streaming.h"
24 #include "odb/transaction.h"
25 -#include "oidtree.h"
25 #include "pack.h"
26 #include "packfile.h"
27 #include "path.h"
@@ -31,12 +30,6 @@
30 #include "tempfile.h"
31 #include "tmp-objdir.h"
32
34 -/* The maximum size for an object header. */
35 -#define MAX_HEADER_LEN 32
36 -
37 -static struct oidtree *odb_source_loose_cache(struct odb_source *source,
38 - const struct object_id *oid);
39 -
33 static int get_conv_flags(unsigned flags)
34 {
35 if (flags & INDEX_RENORMALIZE)
@@ -164,12 +157,6 @@ int stream_object_signature(struct repository *r,
157 return !oideq(oid, &real_oid) ? -1 : 0;
158 }
159
167 -static int quick_has_loose(struct odb_source_loose *loose,
168 - const struct object_id *oid)
169 -{
170 - return !!oidtree_contains(odb_source_loose_cache(&loose->files->base, oid), oid);
171 -}
172 -
160 /*
161 * Map and close the given loose object fd. The path argument is used for
162 * error reporting.
@@ -227,9 +214,9 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
214 return ULHR_TOO_LONG;
215 }
216
230 -static void *unpack_loose_rest(git_zstream *stream,
231 - void *buffer, unsigned long size,
232 - const struct object_id *oid)
217 +void *unpack_loose_rest(git_zstream *stream,
218 + void *buffer, unsigned long size,
219 + const struct object_id *oid)
220 {
221 size_t bytes = strlen(buffer) + 1, n;
222 unsigned char *buf = xmallocz(size);
@@ -343,149 +330,6 @@ int parse_loose_header(const char *hdr, struct object_info *oi)
330 return 0;
331 }
332
346 -int read_object_info_from_path(struct odb_source_loose *loose,
347 - const char *path,
348 - const struct object_id *oid,
349 - struct object_info *oi,
350 - enum object_info_flags flags)
351 -{
352 - int ret;
353 - int fd;
354 - unsigned long mapsize;
355 - void *map = NULL;
356 - git_zstream stream, *stream_to_end = NULL;
357 - char hdr[MAX_HEADER_LEN];
358 - unsigned long size_scratch;
359 - enum object_type type_scratch;
360 - struct stat st;
361 -
362 - /*
363 - * If we don't care about type or size, then we don't
364 - * need to look inside the object at all. Note that we
365 - * do not optimize out the stat call, even if the
366 - * caller doesn't care about the disk-size, since our
367 - * return value implicitly indicates whether the
368 - * object even exists.
369 - */
370 - if (!oi || (!oi->typep && !oi->sizep && !oi->contentp)) {
371 - struct stat st;
372 -
373 - if ((!oi || (!oi->disk_sizep && !oi->mtimep)) && (flags & OBJECT_INFO_QUICK)) {
374 - ret = quick_has_loose(loose, oid) ? 0 : -1;
375 - goto out;
376 - }
377 -
378 - if (lstat(path, &st) < 0) {
379 - ret = -1;
380 - goto out;
381 - }
382 -
383 - if (oi) {
384 - if (oi->disk_sizep)
385 - *oi->disk_sizep = st.st_size;
386 - if (oi->mtimep)
387 - *oi->mtimep = st.st_mtime;
388 - }
389 -
390 - ret = 0;
391 - goto out;
392 - }
393 -
394 - fd = git_open(path);
395 - if (fd < 0) {
396 - if (errno != ENOENT)
397 - error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
398 - ret = -1;
399 - goto out;
400 - }
401 -
402 - if (fstat(fd, &st)) {
403 - close(fd);
404 - ret = -1;
405 - goto out;
406 - }
407 -
408 - mapsize = xsize_t(st.st_size);
409 - if (!mapsize) {
410 - close(fd);
411 - ret = error(_("object file %s is empty"), path);
412 - goto out;
413 - }
414 -
415 - map = xmmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
416 - close(fd);
417 - if (!map) {
418 - ret = -1;
419 - goto out;
420 - }
421 -
422 - if (oi->disk_sizep)
423 - *oi->disk_sizep = mapsize;
424 - if (oi->mtimep)
425 - *oi->mtimep = st.st_mtime;
426 -
427 - stream_to_end = &stream;
428 -
429 - switch (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr))) {
430 - case ULHR_OK:
431 - if (!oi->sizep)
432 - oi->sizep = &size_scratch;
433 - if (!oi->typep)
434 - oi->typep = &type_scratch;
435 -
436 - if (parse_loose_header(hdr, oi) < 0) {
437 - ret = error(_("unable to parse %s header"), oid_to_hex(oid));
438 - goto corrupt;
439 - }
440 -
441 - if (*oi->typep < 0)
442 - die(_("invalid object type"));
443 -
444 - if (oi->contentp) {
445 - *oi->contentp = unpack_loose_rest(&stream, hdr, *oi->sizep, oid);
446 - if (!*oi->contentp) {
447 - ret = -1;
448 - goto corrupt;
449 - }
450 - }
451 -
452 - break;
453 - case ULHR_BAD:
454 - ret = error(_("unable to unpack %s header"),
455 - oid_to_hex(oid));
456 - goto corrupt;
457 - case ULHR_TOO_LONG:
458 - ret = error(_("header for %s too long, exceeds %d bytes"),
459 - oid_to_hex(oid), MAX_HEADER_LEN);
460 - goto corrupt;
461 - }
462 -
463 - ret = 0;
464 -
465 -corrupt:
466 - if (ret && (flags & OBJECT_INFO_DIE_IF_CORRUPT))
467 - die(_("loose object %s (stored in %s) is corrupt"),
468 - oid_to_hex(oid), path);
469 -
470 -out:
471 - if (stream_to_end)
472 - git_inflate_end(stream_to_end);
473 - if (map)
474 - munmap(map, mapsize);
475 - if (oi) {
476 - if (oi->sizep == &size_scratch)
477 - oi->sizep = NULL;
478 - if (oi->typep == &type_scratch)
479 - oi->typep = NULL;
480 - if (oi->delta_base_oid)
481 - oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo);
482 - if (!ret)
483 - oi->whence = OI_LOOSE;
484 - }
485 -
486 - return ret;
487 -}
488 -
333 static void hash_object_body(const struct git_hash_algo *algo, struct git_hash_ctx *c,
334 const void *buf, unsigned long len,
335 struct object_id *oid,
@@ -1667,13 +1511,13 @@ int read_pack_header(int fd, struct pack_header *header)
1511 return 0;
1512 }
1513
1670 -static int for_each_file_in_obj_subdir(unsigned int subdir_nr,
1671 - struct strbuf *path,
1672 - const struct git_hash_algo *algop,
1673 - each_loose_object_fn obj_cb,
1674 - each_loose_cruft_fn cruft_cb,
1675 - each_loose_subdir_fn subdir_cb,
1676 - void *data)
1514 +int for_each_file_in_obj_subdir(unsigned int subdir_nr,
1515 + struct strbuf *path,
1516 + const struct git_hash_algo *algop,
1517 + each_loose_object_fn obj_cb,
1518 + each_loose_cruft_fn cruft_cb,
1519 + each_loose_subdir_fn subdir_cb,
1520 + void *data)
1521 {
1522 size_t origlen, baselen;
1523 DIR *dir;
@@ -1758,78 +1602,6 @@ int for_each_loose_file_in_source(struct odb_source *source,
1602 return r;
1603 }
1604
1761 -struct for_each_object_wrapper_data {
1762 - struct odb_source_loose *loose;
1763 - const struct object_info *request;
1764 - odb_for_each_object_cb cb;
1765 - void *cb_data;
1766 -};
1767 -
1768 -static int for_each_object_wrapper_cb(const struct object_id *oid,
1769 - const char *path,
1770 - void *cb_data)
1771 -{
1772 - struct for_each_object_wrapper_data *data = cb_data;
1773 -
1774 - if (data->request) {
1775 - struct object_info oi = *data->request;
1776 -
1777 - if (read_object_info_from_path(data->loose, path, oid, &oi, 0) < 0)
1778 - return -1;
1779 -
1780 - return data->cb(oid, &oi, data->cb_data);
1781 - } else {
1782 - return data->cb(oid, NULL, data->cb_data);
1783 - }
1784 -}
1785 -
1786 -static int for_each_prefixed_object_wrapper_cb(const struct object_id *oid,
1787 - void *node_data UNUSED,
1788 - void *cb_data)
1789 -{
1790 - struct for_each_object_wrapper_data *data = cb_data;
1791 - if (data->request) {
1792 - struct object_info oi = *data->request;
1793 -
1794 - if (odb_source_read_object_info(&data->loose->base,
1795 - oid, &oi, 0) < 0)
1796 - return -1;
1797 -
1798 - return data->cb(oid, &oi, data->cb_data);
1799 - } else {
1800 - return data->cb(oid, NULL, data->cb_data);
1801 - }
1802 -}
1803 -
1804 -int odb_source_loose_for_each_object(struct odb_source *source,
1805 - const struct object_info *request,
1806 - odb_for_each_object_cb cb,
1807 - void *cb_data,
1808 - const struct odb_for_each_object_options *opts)
1809 -{
1810 - struct odb_source_files *files = odb_source_files_downcast(source);
1811 - struct for_each_object_wrapper_data data = {
1812 - .loose = files->loose,
1813 - .request = request,
1814 - .cb = cb,
1815 - .cb_data = cb_data,
1816 - };
1817 -
1818 - /* There are no loose promisor objects, so we can return immediately. */
1819 - if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
1820 - return 0;
1821 - if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
1822 - return 0;
1823 -
1824 - if (opts->prefix)
1825 - return oidtree_each(odb_source_loose_cache(source, opts->prefix),
1826 - opts->prefix, opts->prefix_hex_len,
1827 - for_each_prefixed_object_wrapper_cb, &data);
1828 -
1829 - return for_each_loose_file_in_source(source, for_each_object_wrapper_cb,
1830 - NULL, NULL, &data);
1831 -}
1832 -
1605 static int count_loose_object(const struct object_id *oid UNUSED,
1606 struct object_info *oi UNUSED,
1607 void *payload)
@@ -1843,6 +1615,7 @@ int odb_source_loose_count_objects(struct odb_source *source,
1615 enum odb_count_objects_flags flags,
1616 unsigned long *out)
1617 {
1618 + struct odb_source_files *files = odb_source_files_downcast(source);
1619 const unsigned hexsz = source->odb->repo->hash_algo->hexsz - 2;
1620 char *path = NULL;
1621 DIR *dir = NULL;
@@ -1878,8 +1651,8 @@ int odb_source_loose_count_objects(struct odb_source *source,
1651 } else {
1652 struct odb_for_each_object_options opts = { 0 };
1653 *out = 0;
1881 - ret = odb_source_loose_for_each_object(source, NULL, count_loose_object,
1882 - out, &opts);
1654 + ret = odb_source_for_each_object(&files->loose->base, NULL, count_loose_object,
1655 + out, &opts);
1656 }
1657
1658 out:
@@ -1910,6 +1683,7 @@ int odb_source_loose_find_abbrev_len(struct odb_source *source,
1683 unsigned min_len,
1684 unsigned *out)
1685 {
1686 + struct odb_source_files *files = odb_source_files_downcast(source);
1687 struct odb_for_each_object_options opts = {
1688 .prefix = oid,
1689 .prefix_hex_len = min_len,
@@ -1920,54 +1694,13 @@ int odb_source_loose_find_abbrev_len(struct odb_source *source,
1694 };
1695 int ret;
1696
1923 - ret = odb_source_loose_for_each_object(source, NULL, find_abbrev_len_cb,
1924 - &data, &opts);
1697 + ret = odb_source_for_each_object(&files->loose->base, NULL, find_abbrev_len_cb,
1698 + &data, &opts);
1699 *out = data.len;
1700
1701 return ret;
1702 }
1703
1930 -static int append_loose_object(const struct object_id *oid,
1931 - const char *path UNUSED,
1932 - void *data)
1933 -{
1934 - oidtree_insert(data, oid, NULL);
1935 - return 0;
1936 -}
1937 -
1938 -static struct oidtree *odb_source_loose_cache(struct odb_source *source,
1939 - const struct object_id *oid)
1940 -{
1941 - struct odb_source_files *files = odb_source_files_downcast(source);
1942 - int subdir_nr = oid->hash[0];
1943 - struct strbuf buf = STRBUF_INIT;
1944 - size_t word_bits = bitsizeof(files->loose->subdir_seen[0]);
1945 - size_t word_index = subdir_nr / word_bits;
1946 - size_t mask = (size_t)1u << (subdir_nr % word_bits);
1947 - uint32_t *bitmap;
1948 -
1949 - if (subdir_nr < 0 ||
1950 - (size_t) subdir_nr >= bitsizeof(files->loose->subdir_seen))
1951 - BUG("subdir_nr out of range");
1952 -
1953 - bitmap = &files->loose->subdir_seen[word_index];
1954 - if (*bitmap & mask)
1955 - return files->loose->cache;
1956 - if (!files->loose->cache) {
1957 - ALLOC_ARRAY(files->loose->cache, 1);
1958 - oidtree_init(files->loose->cache);
1959 - }
1960 - strbuf_addstr(&buf, source->path);
1961 - for_each_file_in_obj_subdir(subdir_nr, &buf,
1962 - source->odb->repo->hash_algo,
1963 - append_loose_object,
1964 - NULL, NULL,
1965 - files->loose->cache);
1966 - *bitmap |= mask;
1967 - strbuf_release(&buf);
1968 - return files->loose->cache;
1969 -}
1970 -
1704 static int check_stream_oid(git_zstream *stream,
1705 const char *hdr,
1706 unsigned long size,
object-file.h
+13 -19
@@ -6,6 +6,9 @@
6 #include "odb.h"
7 #include "odb/source-loose.h"
8
9 +/* The maximum size for an object header. */
10 +#define MAX_HEADER_LEN 32
11 +
12 struct index_state;
13
14 enum {
@@ -85,19 +88,13 @@ int for_each_loose_file_in_source(struct odb_source *source,
88 each_loose_cruft_fn cruft_cb,
89 each_loose_subdir_fn subdir_cb,
90 void *data);
88 -
89 -/*
90 - * Iterate through all loose objects in the given object database source and
91 - * invoke the callback function for each of them. If an object info request is
92 - * given, then the object info will be read for every individual object and
93 - * passed to the callback as if `odb_source_loose_read_object_info()` was
94 - * called for the object.
95 - */
96 -int odb_source_loose_for_each_object(struct odb_source *source,
97 - const struct object_info *request,
98 - odb_for_each_object_cb cb,
99 - void *cb_data,
100 - const struct odb_for_each_object_options *opts);
91 +int for_each_file_in_obj_subdir(unsigned int subdir_nr,
92 + struct strbuf *path,
93 + const struct git_hash_algo *algop,
94 + each_loose_object_fn obj_cb,
95 + each_loose_cruft_fn cruft_cb,
96 + each_loose_subdir_fn subdir_cb,
97 + void *data);
98
99 /*
100 * Count the number of loose objects in this source.
@@ -188,12 +185,6 @@ int read_loose_object(struct repository *repo,
185 void **contents,
186 struct object_info *oi);
187
191 -int read_object_info_from_path(struct odb_source_loose *loose,
192 - const char *path,
193 - const struct object_id *oid,
194 - struct object_info *oi,
195 - enum object_info_flags flags);
196 -
188 enum unpack_loose_header_result {
189 ULHR_OK,
190 ULHR_BAD,
@@ -217,6 +208,9 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
208 unsigned long mapsize,
209 void *buffer,
210 unsigned long bufsiz);
211 +void *unpack_loose_rest(git_zstream *stream,
212 + void *buffer, unsigned long size,
213 + const struct object_id *oid);
214
215 int parse_loose_header(const char *hdr, struct object_info *oi);
216
odb/source-files.c
+1 -1
@@ -82,7 +82,7 @@ static int odb_source_files_for_each_object(struct odb_source *source,
82 int ret;
83
84 if (!(opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
85 - ret = odb_source_loose_for_each_object(source, request, cb, cb_data, opts);
85 + ret = odb_source_for_each_object(&files->loose->base, request, cb, cb_data, opts);
86 if (ret)
87 return ret;
88 }
odb/source-loose.c
+264
@@ -2,6 +2,7 @@
2 #include "abspath.h"
3 #include "chdir-notify.h"
4 #include "gettext.h"
5 +#include "hex.h"
6 #include "loose.h"
7 #include "object-file.h"
8 #include "odb.h"
@@ -9,8 +10,198 @@
10 #include "odb/source-loose.h"
11 #include "odb/streaming.h"
12 #include "oidtree.h"
13 +#include "repository.h"
14 #include "strbuf.h"
15
16 +static int append_loose_object(const struct object_id *oid,
17 + const char *path UNUSED,
18 + void *data)
19 +{
20 + oidtree_insert(data, oid, NULL);
21 + return 0;
22 +}
23 +
24 +static struct oidtree *odb_source_loose_cache(struct odb_source_loose *loose,
25 + const struct object_id *oid)
26 +{
27 + int subdir_nr = oid->hash[0];
28 + struct strbuf buf = STRBUF_INIT;
29 + size_t word_bits = bitsizeof(loose->subdir_seen[0]);
30 + size_t word_index = subdir_nr / word_bits;
31 + size_t mask = (size_t)1u << (subdir_nr % word_bits);
32 + uint32_t *bitmap;
33 +
34 + if (subdir_nr < 0 ||
35 + (size_t) subdir_nr >= bitsizeof(loose->subdir_seen))
36 + BUG("subdir_nr out of range");
37 +
38 + bitmap = &loose->subdir_seen[word_index];
39 + if (*bitmap & mask)
40 + return loose->cache;
41 + if (!loose->cache) {
42 + ALLOC_ARRAY(loose->cache, 1);
43 + oidtree_init(loose->cache);
44 + }
45 + strbuf_addstr(&buf, loose->base.path);
46 + for_each_file_in_obj_subdir(subdir_nr, &buf,
47 + loose->base.odb->repo->hash_algo,
48 + append_loose_object,
49 + NULL, NULL,
50 + loose->cache);
51 + *bitmap |= mask;
52 + strbuf_release(&buf);
53 + return loose->cache;
54 +}
55 +
56 +static int quick_has_loose(struct odb_source_loose *loose,
57 + const struct object_id *oid)
58 +{
59 + return !!oidtree_contains(odb_source_loose_cache(loose, oid), oid);
60 +}
61 +
62 +static int read_object_info_from_path(struct odb_source_loose *loose,
63 + const char *path,
64 + const struct object_id *oid,
65 + struct object_info *oi,
66 + enum object_info_flags flags)
67 +{
68 + int ret;
69 + int fd;
70 + unsigned long mapsize;
71 + void *map = NULL;
72 + git_zstream stream, *stream_to_end = NULL;
73 + char hdr[MAX_HEADER_LEN];
74 + unsigned long size_scratch;
75 + enum object_type type_scratch;
76 + struct stat st;
77 +
78 + /*
79 + * If we don't care about type or size, then we don't
80 + * need to look inside the object at all. Note that we
81 + * do not optimize out the stat call, even if the
82 + * caller doesn't care about the disk-size, since our
83 + * return value implicitly indicates whether the
84 + * object even exists.
85 + */
86 + if (!oi || (!oi->typep && !oi->sizep && !oi->contentp)) {
87 + struct stat st;
88 +
89 + if ((!oi || (!oi->disk_sizep && !oi->mtimep)) && (flags & OBJECT_INFO_QUICK)) {
90 + ret = quick_has_loose(loose, oid) ? 0 : -1;
91 + goto out;
92 + }
93 +
94 + if (lstat(path, &st) < 0) {
95 + ret = -1;
96 + goto out;
97 + }
98 +
99 + if (oi) {
100 + if (oi->disk_sizep)
101 + *oi->disk_sizep = st.st_size;
102 + if (oi->mtimep)
103 + *oi->mtimep = st.st_mtime;
104 + }
105 +
106 + ret = 0;
107 + goto out;
108 + }
109 +
110 + fd = git_open(path);
111 + if (fd < 0) {
112 + if (errno != ENOENT)
113 + error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
114 + ret = -1;
115 + goto out;
116 + }
117 +
118 + if (fstat(fd, &st)) {
119 + close(fd);
120 + ret = -1;
121 + goto out;
122 + }
123 +
124 + mapsize = xsize_t(st.st_size);
125 + if (!mapsize) {
126 + close(fd);
127 + ret = error(_("object file %s is empty"), path);
128 + goto out;
129 + }
130 +
131 + map = xmmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
132 + close(fd);
133 + if (!map) {
134 + ret = -1;
135 + goto out;
136 + }
137 +
138 + if (oi->disk_sizep)
139 + *oi->disk_sizep = mapsize;
140 + if (oi->mtimep)
141 + *oi->mtimep = st.st_mtime;
142 +
143 + stream_to_end = &stream;
144 +
145 + switch (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr))) {
146 + case ULHR_OK:
147 + if (!oi->sizep)
148 + oi->sizep = &size_scratch;
149 + if (!oi->typep)
150 + oi->typep = &type_scratch;
151 +
152 + if (parse_loose_header(hdr, oi) < 0) {
153 + ret = error(_("unable to parse %s header"), oid_to_hex(oid));
154 + goto corrupt;
155 + }
156 +
157 + if (*oi->typep < 0)
158 + die(_("invalid object type"));
159 +
160 + if (oi->contentp) {
161 + *oi->contentp = unpack_loose_rest(&stream, hdr, *oi->sizep, oid);
162 + if (!*oi->contentp) {
163 + ret = -1;
164 + goto corrupt;
165 + }
166 + }
167 +
168 + break;
169 + case ULHR_BAD:
170 + ret = error(_("unable to unpack %s header"),
171 + oid_to_hex(oid));
172 + goto corrupt;
173 + case ULHR_TOO_LONG:
174 + ret = error(_("header for %s too long, exceeds %d bytes"),
175 + oid_to_hex(oid), MAX_HEADER_LEN);
176 + goto corrupt;
177 + }
178 +
179 + ret = 0;
180 +
181 +corrupt:
182 + if (ret && (flags & OBJECT_INFO_DIE_IF_CORRUPT))
183 + die(_("loose object %s (stored in %s) is corrupt"),
184 + oid_to_hex(oid), path);
185 +
186 +out:
187 + if (stream_to_end)
188 + git_inflate_end(stream_to_end);
189 + if (map)
190 + munmap(map, mapsize);
191 + if (oi) {
192 + if (oi->sizep == &size_scratch)
193 + oi->sizep = NULL;
194 + if (oi->typep == &type_scratch)
195 + oi->typep = NULL;
196 + if (oi->delta_base_oid)
197 + oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo);
198 + if (!ret)
199 + oi->whence = OI_LOOSE;
200 + }
201 +
202 + return ret;
203 +}
204 +
205 static int odb_source_loose_read_object_info(struct odb_source *source,
206 const struct object_id *oid,
207 struct object_info *oi,
@@ -218,6 +409,78 @@ error:
409 return -1;
410 }
411
412 +struct for_each_object_wrapper_data {
413 + struct odb_source_loose *loose;
414 + const struct object_info *request;
415 + odb_for_each_object_cb cb;
416 + void *cb_data;
417 +};
418 +
419 +static int for_each_object_wrapper_cb(const struct object_id *oid,
420 + const char *path,
421 + void *cb_data)
422 +{
423 + struct for_each_object_wrapper_data *data = cb_data;
424 +
425 + if (data->request) {
426 + struct object_info oi = *data->request;
427 +
428 + if (read_object_info_from_path(data->loose, path, oid, &oi, 0) < 0)
429 + return -1;
430 +
431 + return data->cb(oid, &oi, data->cb_data);
432 + } else {
433 + return data->cb(oid, NULL, data->cb_data);
434 + }
435 +}
436 +
437 +static int for_each_prefixed_object_wrapper_cb(const struct object_id *oid,
438 + void *node_data UNUSED,
439 + void *cb_data)
440 +{
441 + struct for_each_object_wrapper_data *data = cb_data;
442 + if (data->request) {
443 + struct object_info oi = *data->request;
444 +
445 + if (odb_source_read_object_info(&data->loose->base,
446 + oid, &oi, 0) < 0)
447 + return -1;
448 +
449 + return data->cb(oid, &oi, data->cb_data);
450 + } else {
451 + return data->cb(oid, NULL, data->cb_data);
452 + }
453 +}
454 +
455 +static int odb_source_loose_for_each_object(struct odb_source *source,
456 + const struct object_info *request,
457 + odb_for_each_object_cb cb,
458 + void *cb_data,
459 + const struct odb_for_each_object_options *opts)
460 +{
461 + struct odb_source_loose *loose = odb_source_loose_downcast(source);
462 + struct for_each_object_wrapper_data data = {
463 + .loose = loose,
464 + .request = request,
465 + .cb = cb,
466 + .cb_data = cb_data,
467 + };
468 +
469 + /* There are no loose promisor objects, so we can return immediately. */
470 + if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
471 + return 0;
472 + if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
473 + return 0;
474 +
475 + if (opts->prefix)
476 + return oidtree_each(odb_source_loose_cache(loose, opts->prefix),
477 + opts->prefix, opts->prefix_hex_len,
478 + for_each_prefixed_object_wrapper_cb, &data);
479 +
480 + return for_each_loose_file_in_source(source, for_each_object_wrapper_cb,
481 + NULL, NULL, &data);
482 +}
483 +
484 static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
485 {
486 oidtree_clear(loose->cache);
@@ -273,6 +536,7 @@ struct odb_source_loose *odb_source_loose_new(struct odb_source_files *files)
536 loose->base.reprepare = odb_source_loose_reprepare;
537 loose->base.read_object_info = odb_source_loose_read_object_info;
538 loose->base.read_object_stream = odb_source_loose_read_object_stream;
539 + loose->base.for_each_object = odb_source_loose_for_each_object;
540
541 if (!is_absolute_path(loose->base.path))
542 chdir_notify_register(NULL, odb_source_loose_reparent, loose);