]> git.proxmox.com Git - libgit2.git/blob - src/odb_pack.c
Merge pull request #269 from schu/infinite-append
[libgit2.git] / src / odb_pack.c
1 /*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 #include "common.h"
27 #include "git2/zlib.h"
28 #include "git2/repository.h"
29 #include "git2/oid.h"
30 #include "fileops.h"
31 #include "hash.h"
32 #include "odb.h"
33 #include "delta-apply.h"
34 #include "sha1_lookup.h"
35
36 #include "git2/odb_backend.h"
37
38 #define DEFAULT_WINDOW_SIZE \
39 (sizeof(void*) >= 8 \
40 ? 1 * 1024 * 1024 * 1024 \
41 : 32 * 1024 * 1024)
42
43 #define DEFAULT_MAPPED_LIMIT \
44 ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
45
46 #define PACK_SIGNATURE 0x5041434b /* "PACK" */
47 #define PACK_VERSION 2
48 #define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3))
49 struct pack_header {
50 uint32_t hdr_signature;
51 uint32_t hdr_version;
52 uint32_t hdr_entries;
53 };
54
55 /*
56 * The first four bytes of index formats later than version 1 should
57 * start with this signature, as all older git binaries would find this
58 * value illegal and abort reading the file.
59 *
60 * This is the case because the number of objects in a packfile
61 * cannot exceed 1,431,660,000 as every object would need at least
62 * 3 bytes of data and the overall packfile cannot exceed 4 GiB with
63 * version 1 of the index file due to the offsets limited to 32 bits.
64 * Clearly the signature exceeds this maximum.
65 *
66 * Very old git binaries will also compare the first 4 bytes to the
67 * next 4 bytes in the index and abort with a "non-monotonic index"
68 * error if the second 4 byte word is smaller than the first 4
69 * byte word. This would be true in the proposed future index
70 * format as idx_signature would be greater than idx_version.
71 */
72 #define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */
73
74 struct pack_idx_header {
75 uint32_t idx_signature;
76 uint32_t idx_version;
77 };
78
79 struct pack_window {
80 struct pack_window *next;
81 git_map window_map;
82 off_t offset;
83 unsigned int last_used;
84 unsigned int inuse_cnt;
85 };
86
87 struct pack_file {
88 struct pack_window *windows;
89 off_t pack_size;
90
91 git_map index_map;
92
93 uint32_t num_objects;
94 uint32_t num_bad_objects;
95 git_oid *bad_object_sha1; /* array of git_oid */
96
97 int index_version;
98 git_time_t mtime;
99 int pack_fd;
100 unsigned pack_local:1, pack_keep:1;
101 git_oid sha1;
102
103 /* something like ".git/objects/pack/xxxxx.pack" */
104 char pack_name[GIT_FLEX_ARRAY]; /* more */
105 };
106
107 struct pack_entry {
108 off_t offset;
109 git_oid sha1;
110 struct pack_file *p;
111 };
112
113 struct pack_backend {
114 git_odb_backend parent;
115 git_vector packs;
116 struct pack_file *last_found;
117 char *pack_folder;
118 time_t pack_folder_mtime;
119
120 size_t window_size; /* needs default value */
121
122 size_t mapped_limit; /* needs default value */
123 size_t peak_mapped;
124 size_t mapped;
125
126 size_t used_ctr;
127
128 unsigned int peak_open_windows;
129 unsigned int open_windows;
130
131 unsigned int mmap_calls;
132 };
133
134 /**
135 * The wonderful tale of a Packed Object lookup query
136 * ===================================================
137 * A riveting and epic story of epicness and ASCII
138 * art, presented by yours truly,
139 * Sir Vicent of Marti
140 *
141 *
142 * Chapter 1: Once upon a time...
143 * Initialization of the Pack Backend
144 * --------------------------------------------------
145 *
146 * # git_odb_backend_pack
147 * | Creates the pack backend structure, initializes the
148 * | callback pointers to our default read() and exist() methods,
149 * | and tries to preload all the known packfiles in the ODB.
150 * |
151 * |-# packfile_load_all
152 * | Tries to find the `pack` folder, if it exists. ODBs without
153 * | a pack folder are ignored altogether. If there's a `pack` folder
154 * | we run a `dirent` callback through every file in the pack folder
155 * | to find our packfiles. The packfiles are then sorted according
156 * | to a sorting callback.
157 * |
158 * |-# packfile_load__cb
159 * | | This callback is called from `dirent` with every single file
160 * | | inside the pack folder. We find the packs by actually locating
161 * | | their index (ends in ".idx"). From that index, we verify that
162 * | | the corresponding packfile exists and is valid, and if so, we
163 * | | add it to the pack list.
164 * | |
165 * | |-# packfile_check
166 * | Make sure that there's a packfile to back this index, and store
167 * | some very basic information regarding the packfile itself,
168 * | such as the full path, the size, and the modification time.
169 * | We don't actually open the packfile to check for internal consistency.
170 * |
171 * |-# packfile_sort__cb
172 * Sort all the preloaded packs according to some specific criteria:
173 * we prioritize the "newer" packs because it's more likely they
174 * contain the objects we are looking for, and we prioritize local
175 * packs over remote ones.
176 *
177 *
178 *
179 * Chapter 2: To be, or not to be...
180 * A standard packed `exist` query for an OID
181 * --------------------------------------------------
182 *
183 * # pack_backend__exists
184 * | Check if the given SHA1 oid exists in any of the packs
185 * | that have been loaded for our ODB.
186 * |
187 * |-# pack_entry_find
188 * | Iterate through all the packs that have been preloaded
189 * | (starting by the pack where the latest object was found)
190 * | to try to find the OID in one of them.
191 * |
192 * |-# pack_entry_find1
193 * | Check the index of an individual pack to see if the SHA1
194 * | OID can be found. If we can find the offset to that SHA1
195 * | inside of the index, that means the object is contained
196 * | inside of the packfile and we can stop searching.
197 * | Before returning, we verify that the packfile behing the
198 * | index we are searching still exists on disk.
199 * |
200 * |-# pack_entry_find_offset
201 * | | Mmap the actual index file to disk if it hasn't been opened
202 * | | yet, and run a binary search through it to find the OID.
203 * | | See <http://book.git-scm.com/7_the_packfile.html> for specifics
204 * | | on the Packfile Index format and how do we find entries in it.
205 * | |
206 * | |-# pack_index_open
207 * | | Guess the name of the index based on the full path to the
208 * | | packfile, open it and verify its contents. Only if the index
209 * | | has not been opened already.
210 * | |
211 * | |-# pack_index_check
212 * | Mmap the index file and do a quick run through the header
213 * | to guess the index version (right now we support v1 and v2),
214 * | and to verify that the size of the index makes sense.
215 * |
216 * |-# packfile_open
217 * See `packfile_open` in Chapter 3
218 *
219 *
220 *
221 * Chapter 3: The neverending story...
222 * A standard packed `lookup` query for an OID
223 * --------------------------------------------------
224 * TODO
225 *
226 */
227
228
229
230
231 /***********************************************************
232 *
233 * FORWARD DECLARATIONS
234 *
235 ***********************************************************/
236
237 static void pack_window_free_all(struct pack_backend *backend, struct pack_file *p);
238 static int pack_window_contains(struct pack_window *win, off_t offset);
239
240 static void pack_window_scan_lru(struct pack_file *p, struct pack_file **lru_p,
241 struct pack_window **lru_w, struct pack_window **lru_l);
242
243 static int pack_window_close_lru( struct pack_backend *backend,
244 struct pack_file *current, git_file keep_fd);
245
246 static void pack_window_close(struct pack_window **w_cursor);
247
248 static unsigned char *pack_window_open( struct pack_backend *backend,
249 struct pack_file *p, struct pack_window **w_cursor, off_t offset,
250 unsigned int *left);
251
252 static int packfile_sort__cb(const void *a_, const void *b_);
253
254 static void pack_index_free(struct pack_file *p);
255
256 static int pack_index_check(const char *path, struct pack_file *p);
257 static int pack_index_open(struct pack_file *p);
258
259 static struct pack_file *packfile_alloc(int extra);
260 static int packfile_open(struct pack_file *p);
261 static int packfile_check(struct pack_file **pack_out, const char *path);
262 static int packfile_load__cb(void *_data, char *path);
263 static int packfile_refresh_all(struct pack_backend *backend);
264
265 static off_t nth_packed_object_offset(const struct pack_file *p, uint32_t n);
266
267 /* Can find the offset of an object given
268 * a prefix of an identifier.
269 * Throws GIT_EAMBIGUOUSOIDPREFIX if short oid
270 * is ambiguous within the pack.
271 * This method assumes that len is between
272 * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
273 */
274 static int pack_entry_find_offset(
275 off_t *offset_out,
276 git_oid *found_oid,
277 struct pack_file *p,
278 const git_oid *short_oid,
279 unsigned int len);
280
281 static int pack_entry_find1(
282 struct pack_entry *e,
283 struct pack_file *p,
284 const git_oid *short_oid,
285 unsigned int len);
286
287 static int pack_entry_find(struct pack_entry *e,
288 struct pack_backend *backend, const git_oid *oid);
289
290 /* Can find the offset of an object given
291 * a prefix of an identifier.
292 * Throws GIT_EAMBIGUOUSOIDPREFIX if short oid
293 * is ambiguous.
294 * This method assumes that len is between
295 * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
296 */
297 static int pack_entry_find_prefix(struct pack_entry *e,
298 struct pack_backend *backend,
299 const git_oid *short_oid,
300 unsigned int len);
301
302 static off_t get_delta_base(struct pack_backend *backend,
303 struct pack_file *p, struct pack_window **w_curs,
304 off_t *curpos, git_otype type,
305 off_t delta_obj_offset);
306
307 static unsigned long packfile_unpack_header1(
308 size_t *sizep,
309 git_otype *type,
310 const unsigned char *buf,
311 unsigned long len);
312
313 static int packfile_unpack_header(
314 size_t *size_p,
315 git_otype *type_p,
316 struct pack_backend *backend,
317 struct pack_file *p,
318 struct pack_window **w_curs,
319 off_t *curpos);
320
321 static int packfile_unpack_compressed(
322 git_rawobj *obj,
323 struct pack_backend *backend,
324 struct pack_file *p,
325 struct pack_window **w_curs,
326 off_t curpos,
327 size_t size,
328 git_otype type);
329
330 static int packfile_unpack_delta(
331 git_rawobj *obj,
332 struct pack_backend *backend,
333 struct pack_file *p,
334 struct pack_window **w_curs,
335 off_t curpos,
336 size_t delta_size,
337 git_otype delta_type,
338 off_t obj_offset);
339
340 static int packfile_unpack(git_rawobj *obj, struct pack_backend *backend,
341 struct pack_file *p, off_t obj_offset);
342
343
344
345
346
347 /***********************************************************
348 *
349 * PACK WINDOW MANAGEMENT
350 *
351 ***********************************************************/
352
353 void pack_window_free_all(struct pack_backend *backend, struct pack_file *p)
354 {
355 while (p->windows) {
356 struct pack_window *w = p->windows;
357 assert(w->inuse_cnt == 0);
358
359 backend->mapped -= w->window_map.len;
360 backend->open_windows--;
361
362 gitfo_free_map(&w->window_map);
363
364 p->windows = w->next;
365 free(w);
366 }
367 }
368
369 GIT_INLINE(int) pack_window_contains(struct pack_window *win, off_t offset)
370 {
371 /* We must promise at least 20 bytes (one hash) after the
372 * offset is available from this window, otherwise the offset
373 * is not actually in this window and a different window (which
374 * has that one hash excess) must be used. This is to support
375 * the object header and delta base parsing routines below.
376 */
377 off_t win_off = win->offset;
378 return win_off <= offset
379 && (offset + 20) <= (off_t)(win_off + win->window_map.len);
380 }
381
382 static void pack_window_scan_lru(
383 struct pack_file *p,
384 struct pack_file **lru_p,
385 struct pack_window **lru_w,
386 struct pack_window **lru_l)
387 {
388 struct pack_window *w, *w_l;
389
390 for (w_l = NULL, w = p->windows; w; w = w->next) {
391 if (!w->inuse_cnt) {
392 if (!*lru_w || w->last_used < (*lru_w)->last_used) {
393 *lru_p = p;
394 *lru_w = w;
395 *lru_l = w_l;
396 }
397 }
398 w_l = w;
399 }
400 }
401
402 static int pack_window_close_lru(
403 struct pack_backend *backend,
404 struct pack_file *current,
405 git_file keep_fd)
406 {
407 struct pack_file *lru_p = NULL;
408 struct pack_window *lru_w = NULL, *lru_l = NULL;
409 size_t i;
410
411 if (current)
412 pack_window_scan_lru(current, &lru_p, &lru_w, &lru_l);
413
414 for (i = 0; i < backend->packs.length; ++i)
415 pack_window_scan_lru(git_vector_get(&backend->packs, i), &lru_p, &lru_w, &lru_l);
416
417 if (lru_p) {
418 backend->mapped -= lru_w->window_map.len;
419 gitfo_free_map(&lru_w->window_map);
420
421 if (lru_l)
422 lru_l->next = lru_w->next;
423 else {
424 lru_p->windows = lru_w->next;
425 if (!lru_p->windows && lru_p->pack_fd != keep_fd) {
426 gitfo_close(lru_p->pack_fd);
427 lru_p->pack_fd = -1;
428 }
429 }
430
431 free(lru_w);
432 backend->open_windows--;
433 return GIT_SUCCESS;
434 }
435
436 return git__throw(GIT_ERROR, "Failed to close pack window");
437 }
438
439 static void pack_window_close(struct pack_window **w_cursor)
440 {
441 struct pack_window *w = *w_cursor;
442 if (w) {
443 w->inuse_cnt--;
444 *w_cursor = NULL;
445 }
446 }
447
448 static unsigned char *pack_window_open(
449 struct pack_backend *backend,
450 struct pack_file *p,
451 struct pack_window **w_cursor,
452 off_t offset,
453 unsigned int *left)
454 {
455 struct pack_window *win = *w_cursor;
456
457 if (p->pack_fd == -1 && packfile_open(p) < GIT_SUCCESS)
458 return NULL;
459
460 /* Since packfiles end in a hash of their content and it's
461 * pointless to ask for an offset into the middle of that
462 * hash, and the pack_window_contains function above wouldn't match
463 * don't allow an offset too close to the end of the file.
464 */
465 if (offset > (p->pack_size - 20))
466 return NULL;
467
468 if (!win || !pack_window_contains(win, offset)) {
469
470 if (win)
471 win->inuse_cnt--;
472
473 for (win = p->windows; win; win = win->next) {
474 if (pack_window_contains(win, offset))
475 break;
476 }
477
478 if (!win) {
479 size_t window_align = backend->window_size / 2;
480 size_t len;
481
482 win = git__calloc(1, sizeof(*win));
483 win->offset = (offset / window_align) * window_align;
484
485 len = (size_t)(p->pack_size - win->offset);
486 if (len > backend->window_size)
487 len = backend->window_size;
488
489 backend->mapped += len;
490
491 while (backend->mapped_limit < backend->mapped &&
492 pack_window_close_lru(backend, p, p->pack_fd) == GIT_SUCCESS) {}
493
494 if (gitfo_map_ro(&win->window_map, p->pack_fd,
495 win->offset, len) < GIT_SUCCESS)
496 return NULL;
497
498 backend->mmap_calls++;
499 backend->open_windows++;
500
501 if (backend->mapped > backend->peak_mapped)
502 backend->peak_mapped = backend->mapped;
503
504 if (backend->open_windows > backend->peak_open_windows)
505 backend->peak_open_windows = backend->open_windows;
506
507 win->next = p->windows;
508 p->windows = win;
509 }
510 }
511
512 if (win != *w_cursor) {
513 win->last_used = backend->used_ctr++;
514 win->inuse_cnt++;
515 *w_cursor = win;
516 }
517
518 offset -= win->offset;
519 assert(git__is_sizet(offset));
520
521 if (left)
522 *left = win->window_map.len - (size_t)offset;
523
524 return (unsigned char *)win->window_map.data + offset;
525 }
526
527
528
529
530
531
532
533 /***********************************************************
534 *
535 * PACK INDEX METHODS
536 *
537 ***********************************************************/
538
539 static void pack_index_free(struct pack_file *p)
540 {
541 if (p->index_map.data) {
542 gitfo_free_map(&p->index_map);
543 p->index_map.data = NULL;
544 }
545 }
546
547 static int pack_index_check(const char *path, struct pack_file *p)
548 {
549 struct pack_idx_header *hdr;
550 uint32_t version, nr, i, *index;
551
552 void *idx_map;
553 size_t idx_size;
554
555 struct stat st;
556
557 /* TODO: properly open the file without access time */
558 git_file fd = gitfo_open(path, O_RDONLY /*| O_NOATIME */);
559
560 int error;
561
562 if (fd < 0)
563 return git__throw(GIT_EOSERR, "Failed to check index. File missing or corrupted");
564
565 if (gitfo_fstat(fd, &st) < GIT_SUCCESS) {
566 gitfo_close(fd);
567 return git__throw(GIT_EOSERR, "Failed to check index. File appears to be corrupted");
568 }
569
570 if (!git__is_sizet(st.st_size))
571 return GIT_ENOMEM;
572
573 idx_size = (size_t)st.st_size;
574
575 if (idx_size < 4 * 256 + 20 + 20) {
576 gitfo_close(fd);
577 return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Object is corrupted");
578 }
579
580 error = gitfo_map_ro(&p->index_map, fd, 0, idx_size);
581 gitfo_close(fd);
582
583 if (error < GIT_SUCCESS)
584 return git__rethrow(error, "Failed to check index");
585
586 hdr = idx_map = p->index_map.data;
587
588 if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) {
589 version = ntohl(hdr->idx_version);
590
591 if (version < 2 || version > 2) {
592 gitfo_free_map(&p->index_map);
593 return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Unsupported index version");
594 }
595
596 } else
597 version = 1;
598
599 nr = 0;
600 index = idx_map;
601
602 if (version > 1)
603 index += 2; /* skip index header */
604
605 for (i = 0; i < 256; i++) {
606 uint32_t n = ntohl(index[i]);
607 if (n < nr) {
608 gitfo_free_map(&p->index_map);
609 return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Index is non-monotonic");
610 }
611 nr = n;
612 }
613
614 if (version == 1) {
615 /*
616 * Total size:
617 * - 256 index entries 4 bytes each
618 * - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
619 * - 20-byte SHA1 of the packfile
620 * - 20-byte SHA1 file checksum
621 */
622 if (idx_size != 4*256 + nr * 24 + 20 + 20) {
623 gitfo_free_map(&p->index_map);
624 return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Object is corrupted");
625 }
626 } else if (version == 2) {
627 /*
628 * Minimum size:
629 * - 8 bytes of header
630 * - 256 index entries 4 bytes each
631 * - 20-byte sha1 entry * nr
632 * - 4-byte crc entry * nr
633 * - 4-byte offset entry * nr
634 * - 20-byte SHA1 of the packfile
635 * - 20-byte SHA1 file checksum
636 * And after the 4-byte offset table might be a
637 * variable sized table containing 8-byte entries
638 * for offsets larger than 2^31.
639 */
640 unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20;
641 unsigned long max_size = min_size;
642
643 if (nr)
644 max_size += (nr - 1)*8;
645
646 if (idx_size < min_size || idx_size > max_size) {
647 gitfo_free_map(&p->index_map);
648 return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Wrong index size");
649 }
650
651 /* Make sure that off_t is big enough to access the whole pack...
652 * Is this an issue in libgit2? It shouldn't. */
653 if (idx_size != min_size && (sizeof(off_t) <= 4)) {
654 gitfo_free_map(&p->index_map);
655 return git__throw(GIT_EOSERR, "Failed to check index. off_t not big enough to access the whole pack");
656 }
657 }
658
659 p->index_version = version;
660 p->num_objects = nr;
661 return GIT_SUCCESS;
662 }
663
664 static int pack_index_open(struct pack_file *p)
665 {
666 char *idx_name;
667 int error;
668
669 if (p->index_map.data)
670 return GIT_SUCCESS;
671
672 idx_name = git__strdup(p->pack_name);
673 strcpy(idx_name + strlen(idx_name) - STRLEN(".pack"), ".idx");
674
675 error = pack_index_check(idx_name, p);
676 free(idx_name);
677
678 return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to open index");
679 }
680
681
682
683
684
685
686
687
688
689 /***********************************************************
690 *
691 * PACKFILE METHODS
692 *
693 ***********************************************************/
694
695 static int packfile_sort__cb(const void *a_, const void *b_)
696 {
697 struct pack_file *a = *((struct pack_file **)a_);
698 struct pack_file *b = *((struct pack_file **)b_);
699 int st;
700
701 /*
702 * Local packs tend to contain objects specific to our
703 * variant of the project than remote ones. In addition,
704 * remote ones could be on a network mounted filesystem.
705 * Favor local ones for these reasons.
706 */
707 st = a->pack_local - b->pack_local;
708 if (st)
709 return -st;
710
711 /*
712 * Younger packs tend to contain more recent objects,
713 * and more recent objects tend to get accessed more
714 * often.
715 */
716 if (a->mtime < b->mtime)
717 return 1;
718 else if (a->mtime == b->mtime)
719 return 0;
720
721 return -1;
722 }
723
724 static struct pack_file *packfile_alloc(int extra)
725 {
726 struct pack_file *p = git__malloc(sizeof(*p) + extra);
727 memset(p, 0, sizeof(*p));
728 p->pack_fd = -1;
729 return p;
730 }
731
732
733 static void packfile_free(struct pack_backend *backend, struct pack_file *p)
734 {
735 assert(p);
736
737 /* clear_delta_base_cache(); */
738 pack_window_free_all(backend, p);
739
740 if (p->pack_fd != -1)
741 gitfo_close(p->pack_fd);
742
743 pack_index_free(p);
744
745 free(p->bad_object_sha1);
746 free(p);
747 }
748
749 static int packfile_open(struct pack_file *p)
750 {
751 struct stat st;
752 struct pack_header hdr;
753 git_oid sha1;
754 unsigned char *idx_sha1;
755
756 if (!p->index_map.data && pack_index_open(p) < GIT_SUCCESS)
757 return git__throw(GIT_ENOTFOUND, "Failed to open packfile. File not found");
758
759 /* TODO: open with noatime */
760 p->pack_fd = gitfo_open(p->pack_name, O_RDONLY);
761 if (p->pack_fd < 0 || gitfo_fstat(p->pack_fd, &st) < GIT_SUCCESS)
762 return git__throw(GIT_EOSERR, "Failed to open packfile. File appears to be corrupted");
763
764 /* If we created the struct before we had the pack we lack size. */
765 if (!p->pack_size) {
766 if (!S_ISREG(st.st_mode))
767 goto cleanup;
768 p->pack_size = (off_t)st.st_size;
769 } else if (p->pack_size != st.st_size)
770 goto cleanup;
771
772 #if 0
773 /* We leave these file descriptors open with sliding mmap;
774 * there is no point keeping them open across exec(), though.
775 */
776 fd_flag = fcntl(p->pack_fd, F_GETFD, 0);
777 if (fd_flag < 0)
778 return error("cannot determine file descriptor flags");
779
780 fd_flag |= FD_CLOEXEC;
781 if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
782 return GIT_EOSERR;
783 #endif
784
785 /* Verify we recognize this pack file format. */
786 if (gitfo_read(p->pack_fd, &hdr, sizeof(hdr)) < GIT_SUCCESS)
787 goto cleanup;
788
789 if (hdr.hdr_signature != htonl(PACK_SIGNATURE))
790 goto cleanup;
791
792 if (!pack_version_ok(hdr.hdr_version))
793 goto cleanup;
794
795 /* Verify the pack matches its index. */
796 if (p->num_objects != ntohl(hdr.hdr_entries))
797 goto cleanup;
798
799 if (gitfo_lseek(p->pack_fd, p->pack_size - GIT_OID_RAWSZ, SEEK_SET) == -1)
800 goto cleanup;
801
802 if (gitfo_read(p->pack_fd, sha1.id, GIT_OID_RAWSZ) < GIT_SUCCESS)
803 goto cleanup;
804
805 idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40;
806
807 if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) != 0)
808 goto cleanup;
809
810 return GIT_SUCCESS;
811
812 cleanup:
813 gitfo_close(p->pack_fd);
814 p->pack_fd = -1;
815 return git__throw(GIT_EPACKCORRUPTED, "Failed to packfile. Pack is corrupted");
816 }
817
818 static int packfile_check(struct pack_file **pack_out, const char *path)
819 {
820 struct stat st;
821 struct pack_file *p;
822 size_t path_len;
823
824 *pack_out = NULL;
825 path_len = strlen(path);
826 p = packfile_alloc(path_len + 2);
827
828 /*
829 * Make sure a corresponding .pack file exists and that
830 * the index looks sane.
831 */
832 path_len -= STRLEN(".idx");
833 if (path_len < 1) {
834 free(p);
835 return git__throw(GIT_ENOTFOUND, "Failed to check packfile. Wrong path name");
836 }
837
838 memcpy(p->pack_name, path, path_len);
839
840 strcpy(p->pack_name + path_len, ".keep");
841 if (gitfo_exists(p->pack_name) == GIT_SUCCESS)
842 p->pack_keep = 1;
843
844 strcpy(p->pack_name + path_len, ".pack");
845 if (gitfo_stat(p->pack_name, &st) < GIT_SUCCESS || !S_ISREG(st.st_mode)) {
846 free(p);
847 return git__throw(GIT_ENOTFOUND, "Failed to check packfile. File not found");
848 }
849
850 /* ok, it looks sane as far as we can check without
851 * actually mapping the pack file.
852 */
853 p->pack_size = (off_t)st.st_size;
854 p->pack_local = 1;
855 p->mtime = (git_time_t)st.st_mtime;
856
857 /* see if we can parse the sha1 oid in the packfile name */
858 if (path_len < 40 ||
859 git_oid_fromstr(&p->sha1, path + path_len - GIT_OID_HEXSZ) < GIT_SUCCESS)
860 memset(&p->sha1, 0x0, GIT_OID_RAWSZ);
861
862 *pack_out = p;
863 return GIT_SUCCESS;
864 }
865
866 static int packfile_load__cb(void *_data, char *path)
867 {
868 struct pack_backend *backend = (struct pack_backend *)_data;
869 struct pack_file *pack;
870 int error;
871 size_t i;
872
873 if (git__suffixcmp(path, ".idx") != 0)
874 return GIT_SUCCESS; /* not an index */
875
876 for (i = 0; i < backend->packs.length; ++i) {
877 struct pack_file *p = git_vector_get(&backend->packs, i);
878 if (memcmp(p->pack_name, path, strlen(path) - STRLEN(".idx")) == 0)
879 return GIT_SUCCESS;
880 }
881
882 error = packfile_check(&pack, path);
883 if (error < GIT_SUCCESS)
884 return git__rethrow(error, "Failed to load packfile");
885
886 if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) {
887 free(pack);
888 return GIT_ENOMEM;
889 }
890
891 return GIT_SUCCESS;
892 }
893
894 static int packfile_refresh_all(struct pack_backend *backend)
895 {
896 int error;
897 struct stat st;
898
899 if (backend->pack_folder == NULL)
900 return GIT_SUCCESS;
901
902 if (gitfo_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
903 return git__throw(GIT_ENOTFOUND, "Failed to refresh packfiles. Backend not found");
904
905 if (st.st_mtime != backend->pack_folder_mtime) {
906 char path[GIT_PATH_MAX];
907 strcpy(path, backend->pack_folder);
908
909 /* reload all packs */
910 error = gitfo_dirent(path, GIT_PATH_MAX, packfile_load__cb, (void *)backend);
911 if (error < GIT_SUCCESS)
912 return git__rethrow(error, "Failed to refresh packfiles");
913
914 git_vector_sort(&backend->packs);
915 backend->pack_folder_mtime = st.st_mtime;
916 }
917
918 return GIT_SUCCESS;
919 }
920
921
922
923
924
925
926
927
928 /***********************************************************
929 *
930 * PACKFILE ENTRY SEARCH INTERNALS
931 *
932 ***********************************************************/
933
934 static off_t nth_packed_object_offset(const struct pack_file *p, uint32_t n)
935 {
936 const unsigned char *index = p->index_map.data;
937 index += 4 * 256;
938 if (p->index_version == 1) {
939 return ntohl(*((uint32_t *)(index + 24 * n)));
940 } else {
941 uint32_t off;
942 index += 8 + p->num_objects * (20 + 4);
943 off = ntohl(*((uint32_t *)(index + 4 * n)));
944 if (!(off & 0x80000000))
945 return off;
946 index += p->num_objects * 4 + (off & 0x7fffffff) * 8;
947 return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
948 ntohl(*((uint32_t *)(index + 4)));
949 }
950 }
951
952 static int pack_entry_find_offset(
953 off_t *offset_out,
954 git_oid *found_oid,
955 struct pack_file *p,
956 const git_oid *short_oid,
957 unsigned int len)
958 {
959 const uint32_t *level1_ofs = p->index_map.data;
960 const unsigned char *index = p->index_map.data;
961 unsigned hi, lo, stride;
962 int pos, found = 0;
963 const unsigned char *current = 0;
964
965 *offset_out = 0;
966
967 if (index == NULL) {
968 int error;
969
970 if ((error = pack_index_open(p)) < GIT_SUCCESS)
971 return git__rethrow(error, "Failed to find offset for pack entry");
972
973 assert(p->index_map.data);
974
975 index = p->index_map.data;
976 level1_ofs = p->index_map.data;
977 }
978
979 if (p->index_version > 1) {
980 level1_ofs += 2;
981 index += 8;
982 }
983
984 index += 4 * 256;
985 hi = ntohl(level1_ofs[(int)short_oid->id[0]]);
986 lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(level1_ofs[(int)short_oid->id[0] - 1]));
987
988 if (p->index_version > 1) {
989 stride = 20;
990 } else {
991 stride = 24;
992 index += 4;
993 }
994
995 #ifdef INDEX_DEBUG_LOOKUP
996 printf("%02x%02x%02x... lo %u hi %u nr %d\n",
997 short_oid->id[0], short_oid->id[1], short_oid->id[2], lo, hi, p->num_objects);
998 #endif
999
1000 /* Use git.git lookup code */
1001 pos = sha1_entry_pos(index, stride, 0, lo, hi, p->num_objects, short_oid->id);
1002
1003 if (pos >= 0) {
1004 /* An object matching exactly the oid was found */
1005 found = 1;
1006 current = index + pos * stride;
1007 } else {
1008 /* No object was found */
1009 /* pos refers to the object with the "closest" oid to short_oid */
1010 pos = - 1 - pos;
1011 if (pos < (int)p->num_objects) {
1012 current = index + pos * stride;
1013
1014 if (!git_oid_ncmp(short_oid, (const git_oid *)current, len)) {
1015 found = 1;
1016 }
1017 }
1018 }
1019
1020 if (found && pos + 1 < (int)p->num_objects) {
1021 /* Check for ambiguousity */
1022 const unsigned char *next = current + stride;
1023
1024 if (!git_oid_ncmp(short_oid, (const git_oid *)next, len)) {
1025 found = 2;
1026 }
1027 }
1028
1029 if (!found) {
1030 return git__throw(GIT_ENOTFOUND, "Failed to find offset for pack entry. Entry not found");
1031 } else if (found > 1) {
1032 return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find offset for pack entry. Ambiguous sha1 prefix within pack");
1033 } else {
1034 *offset_out = nth_packed_object_offset(p, pos);
1035 git_oid_fromraw(found_oid, current);
1036
1037 #ifdef INDEX_DEBUG_LOOKUP
1038 unsigned char hex_sha1[GIT_OID_HEXSZ + 1];
1039 git_oid_fmt(hex_sha1, found_oid);
1040 hex_sha1[GIT_OID_HEXSZ] = '\0';
1041 printf("found lo=%d %s\n", lo, hex_sha1);
1042 #endif
1043 return GIT_SUCCESS;
1044 }
1045 }
1046
1047 static int pack_entry_find1(
1048 struct pack_entry *e,
1049 struct pack_file *p,
1050 const git_oid *short_oid,
1051 unsigned int len)
1052 {
1053 off_t offset;
1054 git_oid found_oid;
1055 int error;
1056
1057 assert(p);
1058
1059 if (len == GIT_OID_HEXSZ && p->num_bad_objects) {
1060 unsigned i;
1061 for (i = 0; i < p->num_bad_objects; i++)
1062 if (git_oid_cmp(short_oid, &p->bad_object_sha1[i]) == 0)
1063 return git__throw(GIT_ERROR, "Failed to find pack entry. Bad object found");
1064 }
1065
1066 error = pack_entry_find_offset(&offset, &found_oid, p, short_oid, len);
1067 if (error < GIT_SUCCESS)
1068 return git__rethrow(error, "Failed to find pack entry. Couldn't find offset");
1069
1070 /* we found a unique entry in the index;
1071 * make sure the packfile backing the index
1072 * still exists on disk */
1073 if (p->pack_fd == -1 && packfile_open(p) < GIT_SUCCESS)
1074 return git__throw(GIT_EOSERR, "Failed to find pack entry. Packfile doesn't exist on disk");
1075
1076 e->offset = offset;
1077 e->p = p;
1078
1079 git_oid_cpy(&e->sha1, &found_oid);
1080 return GIT_SUCCESS;
1081 }
1082
1083 static int pack_entry_find(struct pack_entry *e, struct pack_backend *backend, const git_oid *oid)
1084 {
1085 int error;
1086 size_t i;
1087
1088 if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS)
1089 return git__rethrow(error, "Failed to find pack entry");
1090
1091 if (backend->last_found &&
1092 pack_entry_find1(e, backend->last_found, oid, GIT_OID_HEXSZ) == GIT_SUCCESS)
1093 return GIT_SUCCESS;
1094
1095 for (i = 0; i < backend->packs.length; ++i) {
1096 struct pack_file *p;
1097
1098 p = git_vector_get(&backend->packs, i);
1099 if (p == backend->last_found)
1100 continue;
1101
1102 if (pack_entry_find1(e, p, oid, GIT_OID_HEXSZ) == GIT_SUCCESS) {
1103 backend->last_found = p;
1104 return GIT_SUCCESS;
1105 }
1106 }
1107
1108 return git__throw(GIT_ENOTFOUND, "Failed to find pack entry");
1109 }
1110
1111 static int pack_entry_find_prefix(
1112 struct pack_entry *e,
1113 struct pack_backend *backend,
1114 const git_oid *short_oid,
1115 unsigned int len)
1116 {
1117 int error;
1118 size_t i;
1119 unsigned found = 0;
1120
1121 if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS)
1122 return git__rethrow(error, "Failed to find pack entry");
1123
1124 if (backend->last_found) {
1125 error = pack_entry_find1(e, backend->last_found, short_oid, len);
1126 if (error == GIT_EAMBIGUOUSOIDPREFIX) {
1127 return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix");
1128 } else if (error == GIT_SUCCESS) {
1129 found = 1;
1130 }
1131 }
1132
1133 for (i = 0; i < backend->packs.length; ++i) {
1134 struct pack_file *p;
1135
1136 p = git_vector_get(&backend->packs, i);
1137 if (p == backend->last_found)
1138 continue;
1139
1140 error = pack_entry_find1(e, p, short_oid, len);
1141 if (error == GIT_EAMBIGUOUSOIDPREFIX) {
1142 return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix");
1143 } else if (error == GIT_SUCCESS) {
1144 found++;
1145 if (found > 1)
1146 break;
1147 backend->last_found = p;
1148 }
1149 }
1150
1151 if (!found) {
1152 return git__rethrow(GIT_ENOTFOUND, "Failed to find pack entry");
1153 } else if (found > 1) {
1154 return git__rethrow(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find pack entry. Ambiguous sha1 prefix");
1155 } else {
1156 return GIT_SUCCESS;
1157 }
1158
1159 }
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172 /***********************************************************
1173 *
1174 * PACKFILE ENTRY UNPACK INTERNALS
1175 *
1176 ***********************************************************/
1177
1178 static unsigned long packfile_unpack_header1(
1179 size_t *sizep,
1180 git_otype *type,
1181 const unsigned char *buf,
1182 unsigned long len)
1183 {
1184 unsigned shift;
1185 unsigned long size, c;
1186 unsigned long used = 0;
1187
1188 c = buf[used++];
1189 *type = (c >> 4) & 7;
1190 size = c & 15;
1191 shift = 4;
1192 while (c & 0x80) {
1193 if (len <= used || bitsizeof(long) <= shift)
1194 return 0;
1195
1196 c = buf[used++];
1197 size += (c & 0x7f) << shift;
1198 shift += 7;
1199 }
1200
1201 *sizep = (size_t)size;
1202 return used;
1203 }
1204
1205 static int packfile_unpack_header(
1206 size_t *size_p,
1207 git_otype *type_p,
1208 struct pack_backend *backend,
1209 struct pack_file *p,
1210 struct pack_window **w_curs,
1211 off_t *curpos)
1212 {
1213 unsigned char *base;
1214 unsigned int left;
1215 unsigned long used;
1216
1217 /* pack_window_open() assures us we have [base, base + 20) available
1218 * as a range that we can look at at. (Its actually the hash
1219 * size that is assured.) With our object header encoding
1220 * the maximum deflated object size is 2^137, which is just
1221 * insane, so we know won't exceed what we have been given.
1222 */
1223 base = pack_window_open(backend, p, w_curs, *curpos, &left);
1224 if (base == NULL)
1225 return GIT_ENOMEM;
1226
1227 used = packfile_unpack_header1(size_p, type_p, base, left);
1228
1229 if (used == 0)
1230 return git__throw(GIT_EOBJCORRUPTED, "Header length is zero");
1231
1232 *curpos += used;
1233 return GIT_SUCCESS;
1234 }
1235
1236 static int packfile_unpack_compressed(
1237 git_rawobj *obj,
1238 struct pack_backend *backend,
1239 struct pack_file *p,
1240 struct pack_window **w_curs,
1241 off_t curpos,
1242 size_t size,
1243 git_otype type)
1244 {
1245 int st;
1246 z_stream stream;
1247 unsigned char *buffer, *in;
1248
1249 buffer = git__malloc(size + 1);
1250 memset(buffer, 0x0, size + 1);
1251
1252 memset(&stream, 0, sizeof(stream));
1253 stream.next_out = buffer;
1254 stream.avail_out = size + 1;
1255
1256 st = inflateInit(&stream);
1257 if (st != Z_OK) {
1258 free(buffer);
1259 return git__throw(GIT_EZLIB, "Error in zlib");
1260 }
1261
1262 do {
1263 in = pack_window_open(backend, p, w_curs, curpos, &stream.avail_in);
1264 stream.next_in = in;
1265 st = inflate(&stream, Z_FINISH);
1266
1267 if (!stream.avail_out)
1268 break; /* the payload is larger than it should be */
1269
1270 curpos += stream.next_in - in;
1271 } while (st == Z_OK || st == Z_BUF_ERROR);
1272
1273 inflateEnd(&stream);
1274
1275 if ((st != Z_STREAM_END) || stream.total_out != size) {
1276 free(buffer);
1277 return git__throw(GIT_EZLIB, "Error in zlib");
1278 }
1279
1280 obj->type = type;
1281 obj->len = size;
1282 obj->data = buffer;
1283 return GIT_SUCCESS;
1284 }
1285
1286 static off_t get_delta_base(
1287 struct pack_backend *backend,
1288 struct pack_file *p,
1289 struct pack_window **w_curs,
1290 off_t *curpos,
1291 git_otype type,
1292 off_t delta_obj_offset)
1293 {
1294 unsigned char *base_info = pack_window_open(backend, p, w_curs, *curpos, NULL);
1295 off_t base_offset;
1296 git_oid unused;
1297
1298 /* pack_window_open() assured us we have [base_info, base_info + 20)
1299 * as a range that we can look at without walking off the
1300 * end of the mapped window. Its actually the hash size
1301 * that is assured. An OFS_DELTA longer than the hash size
1302 * is stupid, as then a REF_DELTA would be smaller to store.
1303 */
1304 if (type == GIT_OBJ_OFS_DELTA) {
1305 unsigned used = 0;
1306 unsigned char c = base_info[used++];
1307 base_offset = c & 127;
1308 while (c & 128) {
1309 base_offset += 1;
1310 if (!base_offset || MSB(base_offset, 7))
1311 return 0; /* overflow */
1312 c = base_info[used++];
1313 base_offset = (base_offset << 7) + (c & 127);
1314 }
1315 base_offset = delta_obj_offset - base_offset;
1316 if (base_offset <= 0 || base_offset >= delta_obj_offset)
1317 return 0; /* out of bound */
1318 *curpos += used;
1319 } else if (type == GIT_OBJ_REF_DELTA) {
1320 /* The base entry _must_ be in the same pack */
1321 if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < GIT_SUCCESS)
1322 return git__throw(GIT_EPACKCORRUPTED, "Base entry delta is not in the same pack");
1323 *curpos += 20;
1324 } else
1325 return 0;
1326
1327 return base_offset;
1328 }
1329
1330 static int packfile_unpack_delta(
1331 git_rawobj *obj,
1332 struct pack_backend *backend,
1333 struct pack_file *p,
1334 struct pack_window **w_curs,
1335 off_t curpos,
1336 size_t delta_size,
1337 git_otype delta_type,
1338 off_t obj_offset)
1339 {
1340 off_t base_offset;
1341 git_rawobj base, delta;
1342 int error;
1343
1344 base_offset = get_delta_base(backend, p, w_curs, &curpos, delta_type, obj_offset);
1345 if (base_offset == 0)
1346 return git__throw(GIT_EOBJCORRUPTED, "Delta offset is zero");
1347
1348 pack_window_close(w_curs);
1349 error = packfile_unpack(&base, backend, p, base_offset);
1350
1351 /* TODO: git.git tries to load the base from other packfiles
1352 * or loose objects */
1353 if (error < GIT_SUCCESS)
1354 return git__rethrow(error, "Corrupted delta");
1355
1356 error = packfile_unpack_compressed(&delta, backend, p, w_curs, curpos, delta_size, delta_type);
1357 if (error < GIT_SUCCESS) {
1358 free(base.data);
1359 return git__rethrow(error, "Corrupted delta");
1360 }
1361
1362 obj->type = base.type;
1363 error = git__delta_apply(obj,
1364 base.data, base.len,
1365 delta.data, delta.len);
1366
1367 free(base.data);
1368 free(delta.data);
1369
1370 /* TODO: we might want to cache this shit. eventually */
1371 //add_delta_base_cache(p, base_offset, base, base_size, *type);
1372 return error; /* error set by git__delta_apply */
1373 }
1374
1375 static int packfile_unpack(
1376 git_rawobj *obj,
1377 struct pack_backend *backend,
1378 struct pack_file *p,
1379 off_t obj_offset)
1380 {
1381 struct pack_window *w_curs = NULL;
1382 off_t curpos = obj_offset;
1383 int error;
1384
1385 size_t size = 0;
1386 git_otype type;
1387
1388 /*
1389 * TODO: optionally check the CRC on the packfile
1390 */
1391
1392 obj->data = NULL;
1393 obj->len = 0;
1394 obj->type = GIT_OBJ_BAD;
1395
1396 error = packfile_unpack_header(&size, &type, backend, p, &w_curs, &curpos);
1397 if (error < GIT_SUCCESS)
1398 return git__rethrow(error, "Failed to unpack packfile");
1399
1400 switch (type) {
1401 case GIT_OBJ_OFS_DELTA:
1402 case GIT_OBJ_REF_DELTA:
1403 error = packfile_unpack_delta(
1404 obj, backend, p, &w_curs, curpos,
1405 size, type, obj_offset);
1406 break;
1407
1408 case GIT_OBJ_COMMIT:
1409 case GIT_OBJ_TREE:
1410 case GIT_OBJ_BLOB:
1411 case GIT_OBJ_TAG:
1412 error = packfile_unpack_compressed(
1413 obj, backend, p, &w_curs, curpos,
1414 size, type);
1415 break;
1416
1417 default:
1418 error = GIT_EOBJCORRUPTED;
1419 break;
1420 }
1421
1422 pack_window_close(&w_curs);
1423 return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to unpack packfile");
1424 }
1425
1426
1427
1428
1429
1430 /***********************************************************
1431 *
1432 * PACKED BACKEND PUBLIC API
1433 *
1434 * Implement the git_odb_backend API calls
1435 *
1436 ***********************************************************/
1437
1438 /*
1439 int pack_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
1440 {
1441 pack_location location;
1442
1443 assert(obj && backend && oid);
1444
1445 if (locate_packfile(&location, (struct pack_backend *)backend, oid) < 0)
1446 return GIT_ENOTFOUND;
1447
1448 return read_header_packed(obj, &location);
1449 }
1450 */
1451
1452 int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
1453 {
1454 struct pack_entry e;
1455 git_rawobj raw;
1456 int error;
1457
1458 if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < GIT_SUCCESS)
1459 return git__rethrow(error, "Failed to read pack backend");
1460
1461 if ((error = packfile_unpack(&raw, (struct pack_backend *)backend, e.p, e.offset)) < GIT_SUCCESS)
1462 return git__rethrow(error, "Failed to read pack backend");
1463
1464 *buffer_p = raw.data;
1465 *len_p = raw.len;
1466 *type_p = raw.type;
1467
1468 return GIT_SUCCESS;
1469 }
1470
1471 int pack_backend__read_prefix(
1472 git_oid *out_oid,
1473 void **buffer_p,
1474 size_t *len_p,
1475 git_otype *type_p,
1476 git_odb_backend *backend,
1477 const git_oid *short_oid,
1478 unsigned int len)
1479 {
1480 if (len < GIT_OID_MINPREFIXLEN)
1481 return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read pack backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
1482
1483 if (len >= GIT_OID_HEXSZ) {
1484 /* We can fall back to regular read method */
1485 int error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid);
1486 if (error == GIT_SUCCESS)
1487 git_oid_cpy(out_oid, short_oid);
1488
1489 return error;
1490 } else {
1491 struct pack_entry e;
1492 git_rawobj raw;
1493 int error;
1494
1495 if ((error = pack_entry_find_prefix(&e, (struct pack_backend *)backend, short_oid, len)) < GIT_SUCCESS)
1496 return git__rethrow(error, "Failed to read pack backend");
1497
1498 if ((error = packfile_unpack(&raw, (struct pack_backend *)backend, e.p, e.offset)) < GIT_SUCCESS)
1499 return git__rethrow(error, "Failed to read pack backend");
1500
1501 *buffer_p = raw.data;
1502 *len_p = raw.len;
1503 *type_p = raw.type;
1504 git_oid_cpy(out_oid, &e.sha1);
1505 }
1506
1507 return GIT_SUCCESS;
1508 }
1509
1510 int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
1511 {
1512 struct pack_entry e;
1513 return pack_entry_find(&e, (struct pack_backend *)backend, oid) == GIT_SUCCESS;
1514 }
1515
1516 void pack_backend__free(git_odb_backend *_backend)
1517 {
1518 struct pack_backend *backend;
1519 size_t i;
1520
1521 assert(_backend);
1522
1523 backend = (struct pack_backend *)_backend;
1524
1525 for (i = 0; i < backend->packs.length; ++i) {
1526 struct pack_file *p = git_vector_get(&backend->packs, i);
1527 packfile_free(backend, p);
1528 }
1529
1530 git_vector_free(&backend->packs);
1531 free(backend->pack_folder);
1532 free(backend);
1533 }
1534
1535 int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
1536 {
1537 struct pack_backend *backend;
1538 char path[GIT_PATH_MAX];
1539
1540 backend = git__calloc(1, sizeof(struct pack_backend));
1541 if (backend == NULL)
1542 return GIT_ENOMEM;
1543
1544 if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < GIT_SUCCESS) {
1545 free(backend);
1546 return GIT_ENOMEM;
1547 }
1548
1549 backend->window_size = DEFAULT_WINDOW_SIZE;
1550 backend->mapped_limit = DEFAULT_MAPPED_LIMIT;
1551
1552 git__joinpath(path, objects_dir, "pack");
1553 if (gitfo_isdir(path) == GIT_SUCCESS) {
1554 backend->pack_folder = git__strdup(path);
1555 backend->pack_folder_mtime = 0;
1556
1557 if (backend->pack_folder == NULL) {
1558 free(backend);
1559 return GIT_ENOMEM;
1560 }
1561 }
1562
1563 backend->parent.read = &pack_backend__read;
1564 backend->parent.read_prefix = &pack_backend__read_prefix;
1565 backend->parent.read_header = NULL;
1566 backend->parent.exists = &pack_backend__exists;
1567 backend->parent.free = &pack_backend__free;
1568
1569 *backend_out = (git_odb_backend *)backend;
1570 return GIT_SUCCESS;
1571 }