Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
4 - * This file is part of libgit2, distributed under the GNU GPL v2 with
5 - * a Linking Exception. For full terms see the included COPYING file.
6 - */
7 -
8 - #include "common.h"
9 -
10 - #include <zlib.h>
11 - #include "git2/repository.h"
12 - #include "git2/indexer.h"
13 - #include "git2/sys/odb_backend.h"
14 - #include "futils.h"
15 - #include "hash.h"
16 - #include "odb.h"
17 - #include "delta.h"
18 - #include "mwindow.h"
19 - #include "pack.h"
20 -
21 - #include "git2/odb_backend.h"
22 -
23 - /* re-freshen pack files no more than every 2 seconds */
24 - #define FRESHEN_FREQUENCY 2
25 -
26 - struct pack_backend {
27 - git_odb_backend parent;
28 - git_vector packs;
29 - struct git_pack_file *last_found;
30 - char *pack_folder;
31 - };
32 -
33 - struct pack_writepack {
34 - struct git_odb_writepack parent;
35 - git_indexer *indexer;
36 - };
37 -
38 - /**
39 - * The wonderful tale of a Packed Object lookup query
40 - * ===================================================
41 - * A riveting and epic story of epicness and ASCII
42 - * art, presented by yours truly,
43 - * Sir Vicent of Marti
44 - *
45 - *
46 - * Chapter 1: Once upon a time...
47 - * Initialization of the Pack Backend
48 - * --------------------------------------------------
49 - *
50 - * # git_odb_backend_pack
51 - * | Creates the pack backend structure, initializes the
52 - * | callback pointers to our default read() and exist() methods,
53 - * | and tries to preload all the known packfiles in the ODB.
54 - * |
55 - * |-# packfile_load_all
56 - * | Tries to find the `pack` folder, if it exists. ODBs without
57 - * | a pack folder are ignored altogether. If there's a `pack` folder
58 - * | we run a `dirent` callback through every file in the pack folder
59 - * | to find our packfiles. The packfiles are then sorted according
60 - * | to a sorting callback.
61 - * |
62 - * |-# packfile_load__cb
63 - * | | This callback is called from `dirent` with every single file
64 - * | | inside the pack folder. We find the packs by actually locating
65 - * | | their index (ends in ".idx"). From that index, we verify that
66 - * | | the corresponding packfile exists and is valid, and if so, we
67 - * | | add it to the pack list.
68 - * | |
69 - * | |-# packfile_check
70 - * | Make sure that there's a packfile to back this index, and store
71 - * | some very basic information regarding the packfile itself,
72 - * | such as the full path, the size, and the modification time.
73 - * | We don't actually open the packfile to check for internal consistency.
74 - * |
75 - * |-# packfile_sort__cb
76 - * Sort all the preloaded packs according to some specific criteria:
77 - * we prioritize the "newer" packs because it's more likely they
78 - * contain the objects we are looking for, and we prioritize local
79 - * packs over remote ones.
80 - *
81 - *
82 - *
83 - * Chapter 2: To be, or not to be...
84 - * A standard packed `exist` query for an OID
85 - * --------------------------------------------------
86 - *
87 - * # pack_backend__exists
88 - * | Check if the given SHA1 oid exists in any of the packs
89 - * | that have been loaded for our ODB.
90 - * |
91 - * |-# pack_entry_find
92 - * | Iterate through all the packs that have been preloaded
93 - * | (starting by the pack where the latest object was found)
94 - * | to try to find the OID in one of them.
95 - * |
96 - * |-# pack_entry_find1
97 - * | Check the index of an individual pack to see if the SHA1
98 - * | OID can be found. If we can find the offset to that SHA1
99 - * | inside of the index, that means the object is contained
100 - * | inside of the packfile and we can stop searching.
101 - * | Before returning, we verify that the packfile behing the
102 - * | index we are searching still exists on disk.
103 - * |
104 - * |-# pack_entry_find_offset
105 - * | | Mmap the actual index file to disk if it hasn't been opened
106 - * | | yet, and run a binary search through it to find the OID.
107 - * | | See <http://book.git-scm.com/7_the_packfile.html> for specifics
108 - * | | on the Packfile Index format and how do we find entries in it.
109 - * | |
110 - * | |-# pack_index_open
111 - * | | Guess the name of the index based on the full path to the
112 - * | | packfile, open it and verify its contents. Only if the index
113 - * | | has not been opened already.
114 - * | |
115 - * | |-# pack_index_check
116 - * | Mmap the index file and do a quick run through the header
117 - * | to guess the index version (right now we support v1 and v2),
118 - * | and to verify that the size of the index makes sense.
119 - * |
120 - * |-# packfile_open
121 - * See `packfile_open` in Chapter 3
122 - *
123 - *
124 - *
125 - * Chapter 3: The neverending story...
126 - * A standard packed `lookup` query for an OID
127 - * --------------------------------------------------
128 - * TODO
129 - *
130 - */
131 -
132 -
133 - /***********************************************************
134 - *
135 - * FORWARD DECLARATIONS
136 - *
137 - ***********************************************************/
138 -
139 - static int packfile_sort__cb(const void *a_, const void *b_);
140 -
141 - static int packfile_load__cb(void *_data, git_buf *path);
142 -
143 - static int pack_entry_find(struct git_pack_entry *e,
144 - struct pack_backend *backend, const git_oid *oid);
145 -
146 - /* Can find the offset of an object given
147 - * a prefix of an identifier.
148 - * Sets GIT_EAMBIGUOUS if short oid is ambiguous.
149 - * This method assumes that len is between
150 - * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
151 - */
152 - static int pack_entry_find_prefix(
153 - struct git_pack_entry *e,
154 - struct pack_backend *backend,
155 - const git_oid *short_oid,
156 - size_t len);
157 -
158 -
159 -
160 - /***********************************************************
161 - *
162 - * PACK WINDOW MANAGEMENT
163 - *
164 - ***********************************************************/
165 -
166 4267 2 static int packfile_sort__cb(const void *a_, const void *b_)
167 - {
168 4267 2 const struct git_pack_file *a = a_;
169 4267 2 const struct git_pack_file *b = b_;
170 - int st;
171 -
172 - /*
173 - * Local packs tend to contain objects specific to our
174 - * variant of the project than remote ones. In addition,
175 - * remote ones could be on a network mounted filesystem.
176 - * Favor local ones for these reasons.
177 - */
178 4267 2 st = a->pack_local - b->pack_local;
179 4267 2 if (st)
180 ##### 3 return -st;
181 -
182 - /*
183 - * Younger packs tend to contain more recent objects,
184 - * and more recent objects tend to get accessed more
185 - * often.
186 - */
187 4267 4 if (a->mtime < b->mtime)
188 ##### 5 return 1;
189 4267 6 else if (a->mtime == b->mtime)
190 4267 7 return 0;
191 -
192 ##### 8 return -1;
193 - }
194 -
195 -
196 - 2 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files)static int packfile_load__cb(void *data, git_buf *path)
197 - {
198 - 2 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) struct pack_backend *backend = data;
199 - struct git_pack_file *pack;
200 - 2 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) const char *path_str = git_buf_cstr(path);
201 - 3 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) size_t i, cmp_len = git_buf_len(path);
202 - int error;
203 -
204 - 4-6 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) if (cmp_len <= strlen(".idx") || git__suffixcmp(path_str, ".idx") != 0)
205 - 7 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) return 0; /* not an index */
206 -
207 - 8 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) cmp_len -= strlen(".idx");
208 -
209 - 8,12,13 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) for (i = 0; i < backend->packs.length; ++i) {
210 - 9 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) struct git_pack_file *p = git_vector_get(&backend->packs, i);
211 -
212 - 10 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) if (strncmp(p->pack_name, path_str, cmp_len) == 0)
213 - 11 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) return 0;
214 - }
215 -
216 - 14 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) error = git_mwindow_get_pack(&pack, path->ptr);
217 -
218 - /* ignore missing .pack file as git does */
219 - 15 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) if (error == GIT_ENOTFOUND) {
220 - 16 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) git_error_clear();
221 - 17 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) return 0;
222 - }
223 -
224 - 18 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) if (!error)
225 - 19 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) error = git_vector_insert(&backend->packs, pack);
226 -
227 - 20 suppressed: function cannot be solved packfile_load__cb (automatic due to inconsistent arc counts in .gcda files) return error;
228 -
229 - }
230 -
231 69071 2 static int pack_entry_find_inner(
232 - struct git_pack_entry *e,
233 - struct pack_backend *backend,
234 - const git_oid *oid,
235 - struct git_pack_file *last_found)
236 - {
237 - size_t i;
238 -
239 69071 2,4 if (last_found &&
240 28302 3 git_pack_entry_find(e, last_found, oid, GIT_OID_HEXSZ) == 0)
241 ##### 5 return 0;
242 -
243 174340 6,13,14 for (i = 0; i < backend->packs.length; ++i) {
244 - struct git_pack_file *p;
245 -
246 107723 7 p = git_vector_get(&backend->packs, i);
247 106875 8 if (p == last_found)
248 26589 9 continue;
249 -
250 80286 10,11 if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == 0) {
251 1020 12 backend->last_found = p;
252 1020 12 return 0;
253 - }
254 - }
255 -
256 66617 15 return -1;
257 - }
258 -
259 102727 2 static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid)
260 - {
261 102727 2 struct git_pack_file *last_found = backend->last_found;
262 -
263 102727 2,4 if (backend->last_found &&
264 63303 3 git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0)
265 34593 5 return 0;
266 -
267 67648 6,7 if (!pack_entry_find_inner(e, backend, oid, last_found))
268 1020 8 return 0;
269 -
270 66444 9 return git_odb__error_notfound(
271 - "failed to find pack entry", oid, GIT_OID_HEXSZ);
272 - }
273 -
274 577 2 static int pack_entry_find_prefix(
275 - struct git_pack_entry *e,
276 - struct pack_backend *backend,
277 - const git_oid *short_oid,
278 - size_t len)
279 - {
280 - int error;
281 - size_t i;
282 577 2 git_oid found_full_oid = {{0}};
283 577 2 bool found = false;
284 577 2 struct git_pack_file *last_found = backend->last_found;
285 -
286 577 2 if (last_found) {
287 258 3 error = git_pack_entry_find(e, last_found, short_oid, len);
288 258 4 if (error == GIT_EAMBIGUOUS)
289 12 5 return error;
290 246 6 if (!error) {
291 148 7 git_oid_cpy(&found_full_oid, &e->sha1);
292 148 8 found = true;
293 - }
294 - }
295 -
296 1456 9,23,24 for (i = 0; i < backend->packs.length; ++i) {
297 - struct git_pack_file *p;
298 -
299 897 10 p = git_vector_get(&backend->packs, i);
300 897 11 if (p == last_found)
301 246 12 continue;
302 -
303 651 13 error = git_pack_entry_find(e, p, short_oid, len);
304 651 14 if (error == GIT_EAMBIGUOUS)
305 4 15 return error;
306 647 16 if (!error) {
307 65 17-19 if (found && git_oid_cmp(&e->sha1, &found_full_oid))
308 2 20 return git_odb__error_ambiguous("found multiple pack entries");
309 63 21 git_oid_cpy(&found_full_oid, &e->sha1);
310 63 22 found = true;
311 63 22 backend->last_found = p;
312 - }
313 - }
314 -
315 559 25 if (!found)
316 359 26 return git_odb__error_notfound("no matching pack entry for prefix",
317 - short_oid, len);
318 - else
319 200 27 return 0;
320 - }
321 -
322 -
323 - /***********************************************************
324 - *
325 - * PACKED BACKEND PUBLIC API
326 - *
327 - * Implement the git_odb_backend API calls
328 - *
329 - ***********************************************************/
330 - 2 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files)static int pack_backend__refresh(git_odb_backend *backend_)
331 - {
332 - int error;
333 - struct stat st;
334 - 2 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) git_buf path = GIT_BUF_INIT;
335 - 2 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) struct pack_backend *backend = (struct pack_backend *)backend_;
336 -
337 - 2 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) if (backend->pack_folder == NULL)
338 - 3 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) return 0;
339 -
340 - 4-6 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
341 - 7 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) return git_odb__error_notfound("failed to refresh packfiles", NULL, 0);
342 -
343 - 8 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) git_buf_sets(&path, backend->pack_folder);
344 -
345 - /* reload all packs */
346 - 9 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) error = git_path_direach(&path, 0, packfile_load__cb, backend);
347 -
348 - 10 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) git_buf_dispose(&path);
349 - 11 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) git_vector_sort(&backend->packs);
350 -
351 - 12 suppressed: function cannot be solved pack_backend__refresh (automatic due to inconsistent arc counts in .gcda files) return error;
352 - }
353 -
354 13111 2 static int pack_backend__read_header(
355 - size_t *len_p, git_object_t *type_p,
356 - struct git_odb_backend *backend, const git_oid *oid)
357 - {
358 - struct git_pack_entry e;
359 - int error;
360 -
361 13111 2-6 assert(len_p && type_p && backend && oid);
362 -
363 13111 7,8 if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0)
364 10116 9 return error;
365 -
366 2995 10 return git_packfile_resolve_header(len_p, type_p, e.p, e.offset);
367 - }
368 -
369 7255 2 static int pack_backend__freshen(
370 - git_odb_backend *backend, const git_oid *oid)
371 - {
372 - struct git_pack_entry e;
373 - time_t now;
374 - int error;
375 -
376 7255 2,3 if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0)
377 7199 4 return error;
378 -
379 56 5 now = time(NULL);
380 -
381 56 6 if (e.p->last_freshen > now - FRESHEN_FREQUENCY)
382 51 7 return 0;
383 -
384 5 8,9 if ((error = git_futils_touch(e.p->pack_name, &now)) < 0)
385 ##### 10 return error;
386 -
387 5 11 e.p->last_freshen = now;
388 5 11 return 0;
389 - }
390 -
391 80308 2 static int pack_backend__read(
392 - void **buffer_p, size_t *len_p, git_object_t *type_p,
393 - git_odb_backend *backend, const git_oid *oid)
394 - {
395 - struct git_pack_entry e;
396 80308 2 git_rawobj raw = {NULL};
397 - int error;
398 -
399 80308 2-5 if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0 ||
400 31986 4 (error = git_packfile_unpack(&raw, e.p, &e.offset)) < 0)
401 47661 6 return error;
402 -
403 31986 7 *buffer_p = raw.data;
404 31986 7 *len_p = raw.len;
405 31986 7 *type_p = raw.type;
406 -
407 31986 7 return 0;
408 - }
409 -
410 474 2 static int pack_backend__read_prefix(
411 - git_oid *out_oid,
412 - void **buffer_p,
413 - size_t *len_p,
414 - git_object_t *type_p,
415 - git_odb_backend *backend,
416 - const git_oid *short_oid,
417 - size_t len)
418 - {
419 474 2 int error = 0;
420 -
421 474 2 if (len < GIT_OID_MINPREFIXLEN)
422 ##### 3 error = git_odb__error_ambiguous("prefix length too short");
423 -
424 474 4 else if (len >= GIT_OID_HEXSZ) {
425 - /* We can fall back to regular read method */
426 3 5 error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid);
427 3 6 if (!error)
428 3 7,8 git_oid_cpy(out_oid, short_oid);
429 - } else {
430 - struct git_pack_entry e;
431 471 9 git_rawobj raw = {NULL};
432 -
433 471 9,10 if ((error = pack_entry_find_prefix(
434 157 11,12 &e, (struct pack_backend *)backend, short_oid, len)) == 0 &&
435 157 11 (error = git_packfile_unpack(&raw, e.p, &e.offset)) == 0)
436 - {
437 157 13 *buffer_p = raw.data;
438 157 13 *len_p = raw.len;
439 157 13 *type_p = raw.type;
440 471 13,14 git_oid_cpy(out_oid, &e.sha1);
441 - }
442 - }
443 -
444 474 15 return error;
445 - }
446 -
447 2131 2 static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
448 - {
449 - struct git_pack_entry e;
450 2131 2 return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0;
451 - }
452 -
453 106 2 static int pack_backend__exists_prefix(
454 - git_oid *out, git_odb_backend *backend, const git_oid *short_id, size_t len)
455 - {
456 - int error;
457 106 2 struct pack_backend *pb = (struct pack_backend *)backend;
458 106 2 struct git_pack_entry e = {0};
459 -
460 106 2 error = pack_entry_find_prefix(&e, pb, short_id, len);
461 106 3 git_oid_cpy(out, &e.sha1);
462 106 4 return error;
463 - }
464 -
465 6 2 static int pack_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data)
466 - {
467 - int error;
468 - struct git_pack_file *p;
469 - struct pack_backend *backend;
470 - unsigned int i;
471 -
472 6 2-4 assert(_backend && cb);
473 6 5 backend = (struct pack_backend *)_backend;
474 -
475 - /* Make sure we know about the packfiles */
476 6 5,6 if ((error = pack_backend__refresh(_backend)) < 0)
477 ##### 7 return error;
478 -
479 17 8,12-14 git_vector_foreach(&backend->packs, i, p) {
480 13 9,10 if ((error = git_pack_foreach_entry(p, cb, data)) != 0)
481 2 11 return error;
482 - }
483 -
484 4 15 return 0;
485 - }
486 -
487 4162 2 static int pack_backend__writepack_append(struct git_odb_writepack *_writepack, const void *data, size_t size, git_indexer_progress *stats)
488 - {
489 4162 2 struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
490 -
491 4162 2,3 assert(writepack);
492 -
493 4162 4 return git_indexer_append(writepack->indexer, data, size, stats);
494 - }
495 -
496 69 2 static int pack_backend__writepack_commit(struct git_odb_writepack *_writepack, git_indexer_progress *stats)
497 - {
498 69 2 struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
499 -
500 69 2,3 assert(writepack);
501 -
502 69 4 return git_indexer_commit(writepack->indexer, stats);
503 - }
504 -
505 72 2 static void pack_backend__writepack_free(struct git_odb_writepack *_writepack)
506 - {
507 72 2 struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
508 -
509 72 2,3 assert(writepack);
510 -
511 72 4 git_indexer_free(writepack->indexer);
512 72 5 git__free(writepack);
513 72 6 }
514 -
515 72 2 static int pack_backend__writepack(struct git_odb_writepack **out,
516 - git_odb_backend *_backend,
517 - git_odb *odb,
518 - git_indexer_progress_cb progress_cb,
519 - void *progress_payload)
520 - {
521 72 2 git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
522 - struct pack_backend *backend;
523 - struct pack_writepack *writepack;
524 -
525 72 2-4 assert(out && _backend);
526 -
527 72 5 *out = NULL;
528 -
529 72 5 opts.progress_cb = progress_cb;
530 72 5 opts.progress_cb_payload = progress_payload;
531 -
532 72 5 backend = (struct pack_backend *)_backend;
533 -
534 72 5 writepack = git__calloc(1, sizeof(struct pack_writepack));
535 72 6,7 GIT_ERROR_CHECK_ALLOC(writepack);
536 -
537 72 8,9 if (git_indexer_new(&writepack->indexer,
538 72 8 backend->pack_folder, 0, odb, &opts) < 0) {
539 ##### 10 git__free(writepack);
540 ##### 11 return -1;
541 - }
542 -
543 72 12 writepack->parent.backend = _backend;
544 72 12 writepack->parent.append = pack_backend__writepack_append;
545 72 12 writepack->parent.commit = pack_backend__writepack_commit;
546 72 12 writepack->parent.free = pack_backend__writepack_free;
547 -
548 72 12 *out = (git_odb_writepack *)writepack;
549 -
550 72 12 return 0;
551 - }
552 -
553 3759 2 static void pack_backend__free(git_odb_backend *_backend)
554 - {
555 - struct pack_backend *backend;
556 - size_t i;
557 -
558 3759 2,3 assert(_backend);
559 -
560 3759 4 backend = (struct pack_backend *)_backend;
561 -
562 10326 4,7,8 for (i = 0; i < backend->packs.length; ++i) {
563 6536 5 struct git_pack_file *p = git_vector_get(&backend->packs, i);
564 6528 6 git_mwindow_put_pack(p);
565 - }
566 -
567 3790 9 git_vector_free(&backend->packs);
568 3790 10 git__free(backend->pack_folder);
569 3790 11 git__free(backend);
570 3791 12 }
571 -
572 3791 2 static int pack_backend__alloc(struct pack_backend **out, size_t initial_size)
573 - {
574 3791 2 struct pack_backend *backend = git__calloc(1, sizeof(struct pack_backend));
575 3790 3,4 GIT_ERROR_CHECK_ALLOC(backend);
576 -
577 3792 5,6 if (git_vector_init(&backend->packs, initial_size, packfile_sort__cb) < 0) {
578 ##### 7 git__free(backend);
579 ##### 8 return -1;
580 - }
581 -
582 3792 9 backend->parent.version = GIT_ODB_BACKEND_VERSION;
583 -
584 3792 9 backend->parent.read = &pack_backend__read;
585 3792 9 backend->parent.read_prefix = &pack_backend__read_prefix;
586 3792 9 backend->parent.read_header = &pack_backend__read_header;
587 3792 9 backend->parent.exists = &pack_backend__exists;
588 3792 9 backend->parent.exists_prefix = &pack_backend__exists_prefix;
589 3792 9 backend->parent.refresh = &pack_backend__refresh;
590 3792 9 backend->parent.foreach = &pack_backend__foreach;
591 3792 9 backend->parent.writepack = &pack_backend__writepack;
592 3792 9 backend->parent.freshen = &pack_backend__freshen;
593 3792 9 backend->parent.free = &pack_backend__free;
594 -
595 3792 9 *out = backend;
596 3792 9 return 0;
597 - }
598 -
599 3 2 int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx)
600 - {
601 3 2 struct pack_backend *backend = NULL;
602 3 2 struct git_pack_file *packfile = NULL;
603 -
604 3 2,3 if (pack_backend__alloc(&backend, 1) < 0)
605 ##### 4 return -1;
606 -
607 3 5,6,8 if (git_mwindow_get_pack(&packfile, idx) < 0 ||
608 3 7 git_vector_insert(&backend->packs, packfile) < 0)
609 - {
610 ##### 9 pack_backend__free((git_odb_backend *)backend);
611 ##### 10 return -1;
612 - }
613 -
614 3 11 *backend_out = (git_odb_backend *)backend;
615 3 11 return 0;
616 - }
617 -
618 3788 2 int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
619 - {
620 3788 2 int error = 0;
621 3788 2 struct pack_backend *backend = NULL;
622 3788 2 git_buf path = GIT_BUF_INIT;
623 -
624 3789 2,3 if (pack_backend__alloc(&backend, 8) < 0)
625 ##### 4 return -1;
626 -
627 3789 5,6,9 if (!(error = git_buf_joinpath(&path, objects_dir, "pack")) &&
628 3786 7,8 git_path_isdir(git_buf_cstr(&path)))
629 - {
630 2433 10 backend->pack_folder = git_buf_detach(&path);
631 2432 11 error = pack_backend__refresh((git_odb_backend *)backend);
632 - }
633 -
634 3769 12 if (error < 0) {
635 ##### 13 pack_backend__free((git_odb_backend *)backend);
636 ##### 14 backend = NULL;
637 - }
638 -
639 3769 15 *backend_out = (git_odb_backend *)backend;
640 -
641 3769 15 git_buf_dispose(&path);
642 -
643 3767 16 return error;
644 - }