Line | Count | Source |
1 | | #ifndef PACKFILE_H |
2 | | #define PACKFILE_H |
3 | | |
4 | | #include "list.h" |
5 | | #include "object.h" |
6 | | #include "odb.h" |
7 | | #include "oidset.h" |
8 | | #include "repository.h" |
9 | | #include "strmap.h" |
10 | | |
11 | | /* in odb.h */ |
12 | | struct object_info; |
13 | | struct odb_read_stream; |
14 | | |
15 | | struct packed_git { |
16 | | struct pack_window *windows; |
17 | | off_t pack_size; |
18 | | const void *index_data; |
19 | | size_t index_size; |
20 | | uint32_t num_objects; |
21 | | size_t crc_offset; |
22 | | struct oidset bad_objects; |
23 | | int index_version; |
24 | | time_t mtime; |
25 | | int pack_fd; |
26 | | int index; /* for builtin/pack-objects.c */ |
27 | | unsigned pack_local:1, |
28 | | pack_keep:1, |
29 | | pack_keep_in_core:1, |
30 | | freshened:1, |
31 | | do_not_close:1, |
32 | | pack_promisor:1, |
33 | | multi_pack_index:1, |
34 | | is_cruft:1; |
35 | | unsigned char hash[GIT_MAX_RAWSZ]; |
36 | | struct revindex_entry *revindex; |
37 | | const uint32_t *revindex_data; |
38 | | const uint32_t *revindex_map; |
39 | | size_t revindex_size; |
40 | | /* |
41 | | * mtimes_map points at the beginning of the memory mapped region of |
42 | | * this pack's corresponding .mtimes file, and mtimes_size is the size |
43 | | * of that .mtimes file |
44 | | */ |
45 | | const uint32_t *mtimes_map; |
46 | | size_t mtimes_size; |
47 | | |
48 | | /* repo denotes the repository this packfile belongs to */ |
49 | | struct repository *repo; |
50 | | |
51 | | /* something like ".git/objects/pack/xxxxx.pack" */ |
52 | | char pack_name[FLEX_ARRAY]; /* more */ |
53 | | }; |
54 | | |
55 | | struct packfile_list { |
56 | | struct packfile_list_entry *head, *tail; |
57 | | }; |
58 | | |
59 | | struct packfile_list_entry { |
60 | | struct packfile_list_entry *next; |
61 | | struct packed_git *pack; |
62 | | }; |
63 | | |
64 | | void packfile_list_clear(struct packfile_list *list); |
65 | | void packfile_list_remove(struct packfile_list *list, struct packed_git *pack); |
66 | | void packfile_list_prepend(struct packfile_list *list, struct packed_git *pack); |
67 | | void packfile_list_append(struct packfile_list *list, struct packed_git *pack); |
68 | | |
69 | | /* |
70 | | * Find the pack within the "packs" list whose index contains the object |
71 | | * "oid". For general object lookups, you probably don't want this; use |
72 | | * find_pack_entry() instead. |
73 | | */ |
74 | | struct packed_git *packfile_list_find_oid(struct packfile_list_entry *packs, |
75 | | const struct object_id *oid); |
76 | | |
77 | | /* |
78 | | * A store that manages packfiles for a given object database. |
79 | | */ |
80 | | struct packfile_store { |
81 | | struct odb_source *source; |
82 | | |
83 | | /* |
84 | | * The list of packfiles in the order in which they have been most |
85 | | * recently used. |
86 | | */ |
87 | | struct packfile_list packs; |
88 | | |
89 | | /* |
90 | | * Cache of packfiles which are marked as "kept", either because there |
91 | | * is an on-disk ".keep" file or because they are marked as "kept" in |
92 | | * memory. |
93 | | * |
94 | | * Should not be accessed directly, but via |
95 | | * `packfile_store_get_kept_pack_cache()`. The list of packs gets |
96 | | * invalidated when the stored flags and the flags passed to |
97 | | * `packfile_store_get_kept_pack_cache()` mismatch. |
98 | | */ |
99 | | struct { |
100 | | struct packed_git **packs; |
101 | | unsigned flags; |
102 | | } kept_cache; |
103 | | |
104 | | /* The multi-pack index that belongs to this specific packfile store. */ |
105 | | struct multi_pack_index *midx; |
106 | | |
107 | | /* |
108 | | * A map of packfile names to packed_git structs for tracking which |
109 | | * packs have been loaded already. |
110 | | */ |
111 | | struct strmap packs_by_path; |
112 | | |
113 | | /* |
114 | | * Whether packfiles have already been populated with this store's |
115 | | * packs. |
116 | | */ |
117 | | bool initialized; |
118 | | |
119 | | /* |
120 | | * Usually, packfiles will be reordered to the front of the `packs` |
121 | | * list whenever an object is looked up via them. This has the effect |
122 | | * that packs that contain a lot of accessed objects will be located |
123 | | * towards the front. |
124 | | * |
125 | | * This is usually desireable, but there are exceptions. One exception |
126 | | * is when the looking up multiple objects in a loop for each packfile. |
127 | | * In that case, we may easily end up with an infinite loop as the |
128 | | * packfiles get reordered to the front repeatedly. |
129 | | * |
130 | | * Setting this field to `true` thus disables these reorderings. |
131 | | */ |
132 | | bool skip_mru_updates; |
133 | | }; |
134 | | |
135 | | /* |
136 | | * Allocate and initialize a new empty packfile store for the given object |
137 | | * database source. |
138 | | */ |
139 | | struct packfile_store *packfile_store_new(struct odb_source *source); |
140 | | |
141 | | /* |
142 | | * Free the packfile store and all its associated state. All packfiles |
143 | | * tracked by the store will be closed. |
144 | | */ |
145 | | void packfile_store_free(struct packfile_store *store); |
146 | | |
147 | | /* |
148 | | * Close all packfiles associated with this store. The packfiles won't be |
149 | | * free'd, so they can be re-opened at a later point in time. |
150 | | */ |
151 | | void packfile_store_close(struct packfile_store *store); |
152 | | |
153 | | /* |
154 | | * Prepare the packfile store by loading packfiles and multi-pack indices for |
155 | | * all alternates. This becomes a no-op if the store is already prepared. |
156 | | * |
157 | | * It shouldn't typically be necessary to call this function directly, as |
158 | | * functions that access the store know to prepare it. |
159 | | */ |
160 | | void packfile_store_prepare(struct packfile_store *store); |
161 | | |
162 | | /* |
163 | | * Clear the packfile caches and try to look up any new packfiles that have |
164 | | * appeared since last preparing the packfiles store. |
165 | | * |
166 | | * This function must be called under the `odb_read_lock()`. |
167 | | */ |
168 | | void packfile_store_reprepare(struct packfile_store *store); |
169 | | |
170 | | /* |
171 | | * Add the pack to the store so that contained objects become accessible via |
172 | | * the store. This moves ownership into the store. |
173 | | */ |
174 | | void packfile_store_add_pack(struct packfile_store *store, |
175 | | struct packed_git *pack); |
176 | | |
177 | | /* |
178 | | * Get all packs managed by the given store, including packfiles that are |
179 | | * referenced by multi-pack indices. |
180 | | */ |
181 | | struct packfile_list_entry *packfile_store_get_packs(struct packfile_store *store); |
182 | | |
183 | | struct repo_for_each_pack_data { |
184 | | struct odb_source *source; |
185 | | struct packfile_list_entry *entry; |
186 | | }; |
187 | | |
188 | | static inline struct repo_for_each_pack_data repo_for_eack_pack_data_init(struct repository *repo) |
189 | 0 | { |
190 | 0 | struct repo_for_each_pack_data data = { 0 }; |
191 | |
|
192 | 0 | odb_prepare_alternates(repo->objects); |
193 | |
|
194 | 0 | for (struct odb_source *source = repo->objects->sources; source; source = source->next) { |
195 | 0 | struct packfile_list_entry *entry = packfile_store_get_packs(source->packfiles); |
196 | 0 | if (!entry) |
197 | 0 | continue; |
198 | 0 | data.source = source; |
199 | 0 | data.entry = entry; |
200 | 0 | break; |
201 | 0 | } |
202 | |
|
203 | 0 | return data; |
204 | 0 | } Unexecuted instantiation: commit-graph.c:repo_for_eack_pack_data_init Unexecuted instantiation: object-file.c:repo_for_eack_pack_data_init Unexecuted instantiation: object-name.c:repo_for_eack_pack_data_init Unexecuted instantiation: odb.c:repo_for_eack_pack_data_init Unexecuted instantiation: streaming.c:repo_for_eack_pack_data_init Unexecuted instantiation: pack-write.c:repo_for_eack_pack_data_init Unexecuted instantiation: packfile.c:repo_for_eack_pack_data_init Unexecuted instantiation: path.c:repo_for_eack_pack_data_init Unexecuted instantiation: promisor-remote.c:repo_for_eack_pack_data_init Unexecuted instantiation: repo-settings.c:repo_for_eack_pack_data_init Unexecuted instantiation: revision.c:repo_for_eack_pack_data_init Unexecuted instantiation: run-command.c:repo_for_eack_pack_data_init Unexecuted instantiation: tag.c:repo_for_eack_pack_data_init Unexecuted instantiation: connected.c:repo_for_eack_pack_data_init Unexecuted instantiation: diff.c:repo_for_eack_pack_data_init Unexecuted instantiation: fetch-pack.c:repo_for_eack_pack_data_init Unexecuted instantiation: fsck.c:repo_for_eack_pack_data_init Unexecuted instantiation: list-objects.c:repo_for_eack_pack_data_init Unexecuted instantiation: midx.c:repo_for_eack_pack_data_init Unexecuted instantiation: pack-check.c:repo_for_eack_pack_data_init Unexecuted instantiation: pack-revindex.c:repo_for_eack_pack_data_init Unexecuted instantiation: transport-helper.c:repo_for_eack_pack_data_init |
205 | | |
206 | | static inline void repo_for_each_pack_data_next(struct repo_for_each_pack_data *data) |
207 | 0 | { |
208 | 0 | struct odb_source *source; |
209 | |
|
210 | 0 | data->entry = data->entry->next; |
211 | 0 | if (data->entry) |
212 | 0 | return; |
213 | | |
214 | 0 | for (source = data->source->next; source; source = source->next) { |
215 | 0 | struct packfile_list_entry *entry = packfile_store_get_packs(source->packfiles); |
216 | 0 | if (!entry) |
217 | 0 | continue; |
218 | 0 | data->source = source; |
219 | 0 | data->entry = entry; |
220 | 0 | return; |
221 | 0 | } |
222 | | |
223 | 0 | data->source = NULL; |
224 | 0 | data->entry = NULL; |
225 | 0 | } Unexecuted instantiation: commit-graph.c:repo_for_each_pack_data_next Unexecuted instantiation: object-file.c:repo_for_each_pack_data_next Unexecuted instantiation: object-name.c:repo_for_each_pack_data_next Unexecuted instantiation: odb.c:repo_for_each_pack_data_next Unexecuted instantiation: streaming.c:repo_for_each_pack_data_next Unexecuted instantiation: pack-write.c:repo_for_each_pack_data_next Unexecuted instantiation: packfile.c:repo_for_each_pack_data_next Unexecuted instantiation: path.c:repo_for_each_pack_data_next Unexecuted instantiation: promisor-remote.c:repo_for_each_pack_data_next Unexecuted instantiation: repo-settings.c:repo_for_each_pack_data_next Unexecuted instantiation: revision.c:repo_for_each_pack_data_next Unexecuted instantiation: run-command.c:repo_for_each_pack_data_next Unexecuted instantiation: tag.c:repo_for_each_pack_data_next Unexecuted instantiation: connected.c:repo_for_each_pack_data_next Unexecuted instantiation: diff.c:repo_for_each_pack_data_next Unexecuted instantiation: fetch-pack.c:repo_for_each_pack_data_next Unexecuted instantiation: fsck.c:repo_for_each_pack_data_next Unexecuted instantiation: list-objects.c:repo_for_each_pack_data_next Unexecuted instantiation: midx.c:repo_for_each_pack_data_next Unexecuted instantiation: pack-check.c:repo_for_each_pack_data_next Unexecuted instantiation: pack-revindex.c:repo_for_each_pack_data_next Unexecuted instantiation: transport-helper.c:repo_for_each_pack_data_next |
226 | | |
227 | | /* |
228 | | * Load and iterate through all packs of the given repository. This helper |
229 | | * function will yield packfiles from all object sources connected to the |
230 | | * repository. |
231 | | */ |
232 | | #define repo_for_each_pack(repo, p) \ |
233 | 0 | for (struct repo_for_each_pack_data eack_pack_data = repo_for_eack_pack_data_init(repo); \ |
234 | 0 | ((p) = (eack_pack_data.entry ? eack_pack_data.entry->pack : NULL)); \ |
235 | 0 | repo_for_each_pack_data_next(&eack_pack_data)) |
236 | | |
237 | | int packfile_store_read_object_stream(struct odb_read_stream **out, |
238 | | struct packfile_store *store, |
239 | | const struct object_id *oid); |
240 | | |
241 | | /* |
242 | | * Try to read the object identified by its ID from the object store and |
243 | | * populate the object info with its data. Returns 1 in case the object was |
244 | | * not found, 0 if it was and read successfully, and a negative error code in |
245 | | * case the object was corrupted. |
246 | | */ |
247 | | int packfile_store_read_object_info(struct packfile_store *store, |
248 | | const struct object_id *oid, |
249 | | struct object_info *oi, |
250 | | unsigned flags); |
251 | | |
252 | | /* |
253 | | * Open the packfile and add it to the store if it isn't yet known. Returns |
254 | | * either the newly opened packfile or the preexisting packfile. Returns a |
255 | | * `NULL` pointer in case the packfile could not be opened. |
256 | | */ |
257 | | struct packed_git *packfile_store_load_pack(struct packfile_store *store, |
258 | | const char *idx_path, int local); |
259 | | |
260 | | int packfile_store_freshen_object(struct packfile_store *store, |
261 | | const struct object_id *oid); |
262 | | |
263 | | enum kept_pack_type { |
264 | | KEPT_PACK_ON_DISK = (1 << 0), |
265 | | KEPT_PACK_IN_CORE = (1 << 1), |
266 | | }; |
267 | | |
268 | | /* |
269 | | * Retrieve the cache of kept packs from the given packfile store. Accepts a |
270 | | * combination of `kept_pack_type` flags. The cache is computed on demand and |
271 | | * will be recomputed whenever the flags change. |
272 | | */ |
273 | | struct packed_git **packfile_store_get_kept_pack_cache(struct packfile_store *store, |
274 | | unsigned flags); |
275 | | |
276 | | struct pack_window { |
277 | | struct pack_window *next; |
278 | | unsigned char *base; |
279 | | off_t offset; |
280 | | size_t len; |
281 | | unsigned int last_used; |
282 | | unsigned int inuse_cnt; |
283 | | }; |
284 | | |
285 | | struct pack_entry { |
286 | | off_t offset; |
287 | | struct packed_git *p; |
288 | | }; |
289 | | |
290 | | /* |
291 | | * Generate the filename to be used for a pack file with checksum "sha1" and |
292 | | * extension "ext". The result is written into the strbuf "buf", overwriting |
293 | | * any existing contents. A pointer to buf->buf is returned as a convenience. |
294 | | * |
295 | | * Example: odb_pack_name(out, sha1, "idx") => ".git/objects/pack/pack-1234..idx" |
296 | | */ |
297 | | char *odb_pack_name(struct repository *r, struct strbuf *buf, |
298 | | const unsigned char *hash, const char *ext); |
299 | | |
300 | | /* |
301 | | * Return the basename of the packfile, omitting any containing directory |
302 | | * (e.g., "pack-1234abcd[...].pack"). |
303 | | */ |
304 | | const char *pack_basename(struct packed_git *p); |
305 | | |
306 | | /* |
307 | | * Parse the pack idx file found at idx_path and create a packed_git struct |
308 | | * which can be used with find_pack_entry_one(). |
309 | | * |
310 | | * You probably don't want to use this function! It skips most of the normal |
311 | | * sanity checks (including whether we even have the matching .pack file), |
312 | | * and does not add the resulting packed_git struct to the internal list of |
313 | | * packs. You probably want add_packed_git() instead. |
314 | | */ |
315 | | struct packed_git *parse_pack_index(struct repository *r, unsigned char *sha1, |
316 | | const char *idx_path); |
317 | | |
318 | | typedef void each_file_in_pack_dir_fn(const char *full_path, size_t full_path_len, |
319 | | const char *file_name, void *data); |
320 | | void for_each_file_in_pack_subdir(const char *objdir, |
321 | | const char *subdir, |
322 | | each_file_in_pack_dir_fn fn, |
323 | | void *data); |
324 | | void for_each_file_in_pack_dir(const char *objdir, |
325 | | each_file_in_pack_dir_fn fn, |
326 | | void *data); |
327 | | |
328 | | /* |
329 | | * Iterate over all accessible packed objects without respect to reachability. |
330 | | * By default, this includes both local and alternate packs. |
331 | | * |
332 | | * Note that some objects may appear twice if they are found in multiple packs. |
333 | | * Each pack is visited in an unspecified order. By default, objects within a |
334 | | * pack are visited in pack-idx order (i.e., sorted by oid). |
335 | | */ |
336 | | typedef int each_packed_object_fn(const struct object_id *oid, |
337 | | struct packed_git *pack, |
338 | | uint32_t pos, |
339 | | void *data); |
340 | | int for_each_object_in_pack(struct packed_git *p, |
341 | | each_packed_object_fn, void *data, |
342 | | enum for_each_object_flags flags); |
343 | | int for_each_packed_object(struct repository *repo, each_packed_object_fn cb, |
344 | | void *data, enum for_each_object_flags flags); |
345 | | |
346 | | /* A hook to report invalid files in pack directory */ |
347 | 0 | #define PACKDIR_FILE_PACK 1 |
348 | 0 | #define PACKDIR_FILE_IDX 2 |
349 | 0 | #define PACKDIR_FILE_GARBAGE 4 |
350 | | extern void (*report_garbage)(unsigned seen_bits, const char *path); |
351 | | |
352 | | /* |
353 | | * Give a rough count of objects in the repository. This sacrifices accuracy |
354 | | * for speed. |
355 | | */ |
356 | | unsigned long repo_approximate_object_count(struct repository *r); |
357 | | |
358 | | void pack_report(struct repository *repo); |
359 | | |
360 | | /* |
361 | | * mmap the index file for the specified packfile (if it is not |
362 | | * already mmapped). Return 0 on success. |
363 | | */ |
364 | | int open_pack_index(struct packed_git *); |
365 | | |
366 | | /* |
367 | | * munmap the index file for the specified packfile (if it is |
368 | | * currently mmapped). |
369 | | */ |
370 | | void close_pack_index(struct packed_git *); |
371 | | |
372 | | int close_pack_fd(struct packed_git *p); |
373 | | |
374 | | uint32_t get_pack_fanout(struct packed_git *p, uint32_t value); |
375 | | |
376 | | struct object_database; |
377 | | |
378 | | unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *); |
379 | | void close_pack_windows(struct packed_git *); |
380 | | void close_pack(struct packed_git *); |
381 | | void unuse_pack(struct pack_window **); |
382 | | void clear_delta_base_cache(void); |
383 | | struct packed_git *add_packed_git(struct repository *r, const char *path, |
384 | | size_t path_len, int local); |
385 | | |
386 | | /* |
387 | | * Unlink the .pack and associated extension files. |
388 | | * Does not unlink if 'force_delete' is false and the pack-file is |
389 | | * marked as ".keep". |
390 | | */ |
391 | | void unlink_pack_path(const char *pack_name, int force_delete); |
392 | | |
393 | | /* |
394 | | * Make sure that a pointer access into an mmap'd index file is within bounds, |
395 | | * and can provide at least 8 bytes of data. |
396 | | * |
397 | | * Note that this is only necessary for variable-length segments of the file |
398 | | * (like the 64-bit extended offset table), as we compare the size to the |
399 | | * fixed-length parts when we open the file. |
400 | | */ |
401 | | void check_pack_index_ptr(const struct packed_git *p, const void *ptr); |
402 | | |
403 | | /* |
404 | | * Perform binary search on a pack-index for a given oid. Packfile is expected to |
405 | | * have a valid pack-index. |
406 | | * |
407 | | * See 'bsearch_hash' for more information. |
408 | | */ |
409 | | int bsearch_pack(const struct object_id *oid, const struct packed_git *p, uint32_t *result); |
410 | | |
411 | | /* |
412 | | * Write the oid of the nth object within the specified packfile into the first |
413 | | * parameter. Open the index if it is not already open. Returns 0 on success, |
414 | | * negative otherwise. |
415 | | */ |
416 | | int nth_packed_object_id(struct object_id *, struct packed_git *, uint32_t n); |
417 | | |
418 | | /* |
419 | | * Return the offset of the nth object within the specified packfile. |
420 | | * The index must already be opened. |
421 | | */ |
422 | | off_t nth_packed_object_offset(const struct packed_git *, uint32_t n); |
423 | | |
424 | | /* |
425 | | * If the object named by oid is present in the specified packfile, |
426 | | * return its offset within the packfile; otherwise, return 0. |
427 | | */ |
428 | | off_t find_pack_entry_one(const struct object_id *oid, struct packed_git *); |
429 | | |
430 | | int is_pack_valid(struct packed_git *); |
431 | | void *unpack_entry(struct repository *r, struct packed_git *, off_t, enum object_type *, unsigned long *); |
432 | | unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep); |
433 | | unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t); |
434 | | int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, unsigned long *); |
435 | | off_t get_delta_base(struct packed_git *p, struct pack_window **w_curs, |
436 | | off_t *curpos, enum object_type type, |
437 | | off_t delta_obj_offset); |
438 | | |
439 | | void release_pack_memory(size_t); |
440 | | |
441 | | /* global flag to enable extra checks when accessing packed objects */ |
442 | | extern int do_check_packed_object_crc; |
443 | | |
444 | | /* |
445 | | * Look up the object info for a specific offset in the packfile. |
446 | | * Returns zero on success, a negative error code otherwise. |
447 | | */ |
448 | | int packed_object_info(struct packed_git *pack, |
449 | | off_t offset, struct object_info *); |
450 | | |
451 | | void mark_bad_packed_object(struct packed_git *, const struct object_id *); |
452 | | const struct packed_git *has_packed_and_bad(struct repository *, const struct object_id *); |
453 | | |
454 | | int has_object_pack(struct repository *r, const struct object_id *oid); |
455 | | int has_object_kept_pack(struct repository *r, const struct object_id *oid, |
456 | | unsigned flags); |
457 | | |
458 | | /* |
459 | | * Return 1 if an object in a promisor packfile is or refers to the given |
460 | | * object, 0 otherwise. |
461 | | */ |
462 | | int is_promisor_object(struct repository *r, const struct object_id *oid); |
463 | | |
464 | | /* |
465 | | * Expose a function for fuzz testing. |
466 | | * |
467 | | * load_idx() parses a block of memory as a packfile index and puts the results |
468 | | * into a struct packed_git. |
469 | | * |
470 | | * This function should not be used directly. It is exposed here only so that we |
471 | | * have a convenient entry-point for fuzz testing. For real uses, you should |
472 | | * probably use open_pack_index() instead. |
473 | | */ |
474 | | int load_idx(const char *path, const unsigned int hashsz, void *idx_map, |
475 | | size_t idx_size, struct packed_git *p); |
476 | | |
477 | | /* |
478 | | * Parse a --pack_header option as accepted by index-pack and unpack-objects, |
479 | | * turning it into the matching bytes we'd find in a pack. |
480 | | */ |
481 | | int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *len); |
482 | | |
483 | | #endif |