]> git.proxmox.com Git - libgit2.git/blame - src/pack.c
Update `khash.h` to pull request 42
[libgit2.git] / src / pack.c
CommitLineData
7d0cdf82 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
7d0cdf82 3 *
bb742ede
VM
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.
7d0cdf82
CMN
6 */
7
a15c550d 8#include "common.h"
7d0cdf82
CMN
9#include "odb.h"
10#include "pack.h"
11#include "delta-apply.h"
a070f152 12#include "sha1_lookup.h"
a15c550d
VM
13#include "mwindow.h"
14#include "fileops.h"
b7f167da 15#include "oid.h"
7d0cdf82 16
0c3bae62 17#include <zlib.h>
7d0cdf82 18
a070f152 19static int packfile_open(struct git_pack_file *p);
e1de726c 20static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
a070f152
CMN
21int packfile_unpack_compressed(
22 git_rawobj *obj,
23 struct git_pack_file *p,
24 git_mwindow **w_curs,
e1de726c 25 git_off_t *curpos,
a070f152
CMN
26 size_t size,
27 git_otype type);
28
29/* Can find the offset of an object given
30 * a prefix of an identifier.
904b67e6 31 * Throws GIT_EAMBIGUOUSOIDPREFIX if short oid
a070f152
CMN
32 * is ambiguous within the pack.
33 * This method assumes that len is between
34 * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
35 */
36static int pack_entry_find_offset(
e1de726c 37 git_off_t *offset_out,
a070f152
CMN
38 git_oid *found_oid,
39 struct git_pack_file *p,
40 const git_oid *short_oid,
b8457baa 41 size_t len);
a070f152 42
e1de726c
RB
43static int packfile_error(const char *message)
44{
45 giterr_set(GITERR_ODB, "Invalid pack file - %s", message);
46 return -1;
47}
48
c8f79c2b
CMN
49/********************
50 * Delta base cache
51 ********************/
c0f4a011 52
525d961c 53static git_pack_cache_entry *new_cache_object(git_rawobj *source)
c0f4a011 54{
c8f79c2b 55 git_pack_cache_entry *e = git__calloc(1, sizeof(git_pack_cache_entry));
c0f4a011
CMN
56 if (!e)
57 return NULL;
58
c0f4a011
CMN
59 memcpy(&e->raw, source, sizeof(git_rawobj));
60
61 return e;
62}
63
64static void free_cache_object(void *o)
65{
66 git_pack_cache_entry *e = (git_pack_cache_entry *)o;
67
68 if (e != NULL) {
0ed75620 69 assert(e->refcount.val == 0);
c0f4a011
CMN
70 git__free(e->raw.data);
71 git__free(e);
72 }
73}
74
c8f79c2b
CMN
75static void cache_free(git_pack_cache *cache)
76{
77 khiter_t k;
78
79 if (cache->entries) {
80 for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) {
81 if (kh_exist(cache->entries, k))
82 free_cache_object(kh_value(cache->entries, k));
83 }
84
85 git_offmap_free(cache->entries);
649214be 86 cache->entries = NULL;
c8f79c2b
CMN
87 }
88}
89
90static int cache_init(git_pack_cache *cache)
91{
c8f79c2b
CMN
92 cache->entries = git_offmap_alloc();
93 GITERR_CHECK_ALLOC(cache->entries);
f658dc43 94
c8f79c2b 95 cache->memory_limit = GIT_PACK_CACHE_MEMORY_LIMIT;
1a42dd17
RB
96
97 if (git_mutex_init(&cache->lock)) {
98 giterr_set(GITERR_OS, "Failed to initialize pack cache mutex");
99
100 git__free(cache->entries);
101 cache->entries = NULL;
102
103 return -1;
104 }
c8f79c2b
CMN
105
106 return 0;
107}
108
09e29e47 109static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset)
c8f79c2b
CMN
110{
111 khiter_t k;
112 git_pack_cache_entry *entry = NULL;
113
09e29e47
CMN
114 if (git_mutex_lock(&cache->lock) < 0)
115 return NULL;
116
c8f79c2b
CMN
117 k = kh_get(off, cache->entries, offset);
118 if (k != kh_end(cache->entries)) { /* found it */
119 entry = kh_value(cache->entries, k);
120 git_atomic_inc(&entry->refcount);
0ed75620 121 entry->last_usage = cache->use_ctr++;
c8f79c2b
CMN
122 }
123 git_mutex_unlock(&cache->lock);
124
125 return entry;
126}
127
0ed75620
CMN
128/* Run with the cache lock held */
129static void free_lowest_entry(git_pack_cache *cache)
130{
ed6648ba
CMN
131 git_pack_cache_entry *entry;
132 khiter_t k;
133
0ed75620
CMN
134 for (k = kh_begin(cache->entries); k != kh_end(cache->entries); k++) {
135 if (!kh_exist(cache->entries, k))
136 continue;
137
138 entry = kh_value(cache->entries, k);
ed6648ba 139
9c62aaab
CMN
140 if (entry && entry->refcount.val == 0) {
141 cache->memory_used -= entry->raw.len;
142 kh_del(off, cache->entries, k);
143 free_cache_object(entry);
ed6648ba
CMN
144 }
145 }
0ed75620
CMN
146}
147
c8f79c2b
CMN
148static int cache_add(git_pack_cache *cache, git_rawobj *base, git_off_t offset)
149{
150 git_pack_cache_entry *entry;
151 int error, exists = 0;
152 khiter_t k;
153
0ed75620
CMN
154 if (base->len > GIT_PACK_CACHE_SIZE_LIMIT)
155 return -1;
156
c8f79c2b
CMN
157 entry = new_cache_object(base);
158 if (entry) {
09e29e47
CMN
159 if (git_mutex_lock(&cache->lock) < 0) {
160 giterr_set(GITERR_OS, "failed to lock cache");
6f73e026 161 git__free(entry);
09e29e47
CMN
162 return -1;
163 }
c8f79c2b
CMN
164 /* Add it to the cache if nobody else has */
165 exists = kh_get(off, cache->entries, offset) != kh_end(cache->entries);
166 if (!exists) {
0ed75620
CMN
167 while (cache->memory_used + base->len > cache->memory_limit)
168 free_lowest_entry(cache);
169
c8f79c2b
CMN
170 k = kh_put(off, cache->entries, offset, &error);
171 assert(error != 0);
172 kh_value(cache->entries, k) = entry;
0ed75620 173 cache->memory_used += entry->raw.len;
c8f79c2b
CMN
174 }
175 git_mutex_unlock(&cache->lock);
176 /* Somebody beat us to adding it into the cache */
177 if (exists) {
178 git__free(entry);
179 return -1;
180 }
181 }
182
183 return 0;
184}
185
a070f152
CMN
186/***********************************************************
187 *
188 * PACK INDEX METHODS
189 *
190 ***********************************************************/
191
192static void pack_index_free(struct git_pack_file *p)
193{
60ecdf59
DMB
194 if (p->oids) {
195 git__free(p->oids);
196 p->oids = NULL;
197 }
a070f152
CMN
198 if (p->index_map.data) {
199 git_futils_mmap_free(&p->index_map);
200 p->index_map.data = NULL;
201 }
202}
203
87d9869f 204static int pack_index_check(const char *path, struct git_pack_file *p)
a070f152
CMN
205{
206 struct git_pack_idx_header *hdr;
207 uint32_t version, nr, i, *index;
a070f152
CMN
208 void *idx_map;
209 size_t idx_size;
a070f152 210 struct stat st;
a070f152 211 int error;
e1de726c
RB
212 /* TODO: properly open the file without access time using O_NOATIME */
213 git_file fd = git_futils_open_ro(path);
a070f152 214 if (fd < 0)
e1de726c 215 return fd;
a070f152 216
9d2f841a
RB
217 if (p_fstat(fd, &st) < 0) {
218 p_close(fd);
219 giterr_set(GITERR_OS, "Unable to stat pack index '%s'", path);
220 return -1;
221 }
222
223 if (!S_ISREG(st.st_mode) ||
e1de726c
RB
224 !git__is_sizet(st.st_size) ||
225 (idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20)
226 {
a070f152 227 p_close(fd);
9d2f841a 228 giterr_set(GITERR_ODB, "Invalid pack index '%s'", path);
e1de726c 229 return -1;
a070f152
CMN
230 }
231
232 error = git_futils_mmap_ro(&p->index_map, fd, 0, idx_size);
e1de726c 233
a070f152
CMN
234 p_close(fd);
235
e1de726c
RB
236 if (error < 0)
237 return error;
a070f152
CMN
238
239 hdr = idx_map = p->index_map.data;
240
241 if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) {
242 version = ntohl(hdr->idx_version);
243
244 if (version < 2 || version > 2) {
245 git_futils_mmap_free(&p->index_map);
e1de726c 246 return packfile_error("unsupported index version");
a070f152
CMN
247 }
248
249 } else
250 version = 1;
251
252 nr = 0;
253 index = idx_map;
254
255 if (version > 1)
87d9869f 256 index += 2; /* skip index header */
a070f152
CMN
257
258 for (i = 0; i < 256; i++) {
259 uint32_t n = ntohl(index[i]);
260 if (n < nr) {
261 git_futils_mmap_free(&p->index_map);
e1de726c 262 return packfile_error("index is non-monotonic");
a070f152
CMN
263 }
264 nr = n;
265 }
266
267 if (version == 1) {
268 /*
269 * Total size:
87d9869f
VM
270 * - 256 index entries 4 bytes each
271 * - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
272 * - 20-byte SHA1 of the packfile
273 * - 20-byte SHA1 file checksum
a070f152
CMN
274 */
275 if (idx_size != 4*256 + nr * 24 + 20 + 20) {
276 git_futils_mmap_free(&p->index_map);
e1de726c 277 return packfile_error("index is corrupted");
a070f152
CMN
278 }
279 } else if (version == 2) {
280 /*
281 * Minimum size:
87d9869f
VM
282 * - 8 bytes of header
283 * - 256 index entries 4 bytes each
284 * - 20-byte sha1 entry * nr
285 * - 4-byte crc entry * nr
286 * - 4-byte offset entry * nr
287 * - 20-byte SHA1 of the packfile
288 * - 20-byte SHA1 file checksum
a070f152
CMN
289 * And after the 4-byte offset table might be a
290 * variable sized table containing 8-byte entries
291 * for offsets larger than 2^31.
292 */
293 unsigned long min_size = 8 + 4*256 + nr*(20 + 4 + 4) + 20 + 20;
294 unsigned long max_size = min_size;
295
296 if (nr)
297 max_size += (nr - 1)*8;
298
299 if (idx_size < min_size || idx_size > max_size) {
300 git_futils_mmap_free(&p->index_map);
e1de726c 301 return packfile_error("wrong index size");
a070f152 302 }
a070f152
CMN
303 }
304
a070f152 305 p->num_objects = nr;
0ddfcb40 306 p->index_version = version;
e1de726c 307 return 0;
a070f152
CMN
308}
309
310static int pack_index_open(struct git_pack_file *p)
311{
312 char *idx_name;
24c70804
RB
313 int error = 0;
314 size_t name_len, base_len;
315
0ddfcb40 316 if (p->index_version > -1)
53607868 317 return 0;
a070f152 318
24c70804
RB
319 name_len = strlen(p->pack_name);
320 assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */
e1de726c 321
53607868
RB
322 if ((idx_name = git__malloc(name_len)) == NULL)
323 return -1;
44ef8b1b 324
24c70804
RB
325 base_len = name_len - strlen(".pack");
326 memcpy(idx_name, p->pack_name, base_len);
327 memcpy(idx_name + base_len, ".idx", sizeof(".idx"));
a070f152 328
050af8bb
RD
329 if ((error = git_mutex_lock(&p->lock)) < 0) {
330 git__free(idx_name);
53607868 331 return error;
050af8bb 332 }
53607868 333
0ddfcb40 334 if (p->index_version == -1)
53607868 335 error = pack_index_check(idx_name, p);
24c70804 336
3286c408 337 git__free(idx_name);
a070f152 338
24c70804
RB
339 git_mutex_unlock(&p->lock);
340
e1de726c 341 return error;
a070f152
CMN
342}
343
344static unsigned char *pack_window_open(
345 struct git_pack_file *p,
7d0cdf82 346 git_mwindow **w_cursor,
e1de726c 347 git_off_t offset,
7d0cdf82
CMN
348 unsigned int *left)
349{
e1de726c 350 if (p->mwf.fd == -1 && packfile_open(p) < 0)
7d0cdf82
CMN
351 return NULL;
352
353 /* Since packfiles end in a hash of their content and it's
354 * pointless to ask for an offset into the middle of that
355 * hash, and the pack_window_contains function above wouldn't match
356 * don't allow an offset too close to the end of the file.
357 */
358 if (offset > (p->mwf.size - 20))
359 return NULL;
360
361 return git_mwindow_open(&p->mwf, w_cursor, offset, 20, left);
362 }
363
51e82492
CMN
364/*
365 * The per-object header is a pretty dense thing, which is
366 * - first byte: low four bits are "size",
367 * then three bits of "type",
368 * with the high bit being "size continues".
369 * - each byte afterwards: low seven bits are size continuation,
370 * with the high bit being "size continues"
371 */
51a3dfb5 372size_t git_packfile__object_header(unsigned char *hdr, size_t size, git_otype type)
51e82492
CMN
373{
374 unsigned char *hdr_base;
375 unsigned char c;
376
377 assert(type >= GIT_OBJ_COMMIT && type <= GIT_OBJ_REF_DELTA);
378
379 /* TODO: add support for chunked objects; see git.git 6c0d19b1 */
380
381 c = (unsigned char)((type << 4) | (size & 15));
382 size >>= 4;
383 hdr_base = hdr;
384
385 while (size) {
386 *hdr++ = c | 0x80;
387 c = size & 0x7f;
388 size >>= 7;
389 }
390 *hdr++ = c;
391
51a3dfb5 392 return (hdr - hdr_base);
51e82492
CMN
393}
394
395
45d773ef
CMN
396static int packfile_unpack_header1(
397 unsigned long *usedp,
7d0cdf82
CMN
398 size_t *sizep,
399 git_otype *type,
400 const unsigned char *buf,
401 unsigned long len)
402{
403 unsigned shift;
404 unsigned long size, c;
405 unsigned long used = 0;
2aeadb9c 406
7d0cdf82
CMN
407 c = buf[used++];
408 *type = (c >> 4) & 7;
409 size = c & 15;
410 shift = 4;
411 while (c & 0x80) {
ec7e680c
RP
412 if (len <= used) {
413 giterr_set(GITERR_ODB, "buffer too small");
904b67e6 414 return GIT_EBUFS;
ec7e680c 415 }
45d773ef
CMN
416
417 if (bitsizeof(long) <= shift) {
418 *usedp = 0;
ec7e680c 419 giterr_set(GITERR_ODB, "packfile corrupted");
45d773ef
CMN
420 return -1;
421 }
7d0cdf82
CMN
422
423 c = buf[used++];
424 size += (c & 0x7f) << shift;
425 shift += 7;
426 }
427
428 *sizep = (size_t)size;
45d773ef
CMN
429 *usedp = used;
430 return 0;
7d0cdf82
CMN
431}
432
433int git_packfile_unpack_header(
434 size_t *size_p,
435 git_otype *type_p,
436 git_mwindow_file *mwf,
437 git_mwindow **w_curs,
e1de726c 438 git_off_t *curpos)
7d0cdf82
CMN
439{
440 unsigned char *base;
441 unsigned int left;
442 unsigned long used;
45d773ef 443 int ret;
7d0cdf82
CMN
444
445 /* pack_window_open() assures us we have [base, base + 20) available
87d9869f
VM
446 * as a range that we can look at at. (Its actually the hash
447 * size that is assured.) With our object header encoding
7d0cdf82
CMN
448 * the maximum deflated object size is 2^137, which is just
449 * insane, so we know won't exceed what we have been given.
450 */
24c70804 451/* base = pack_window_open(p, w_curs, *curpos, &left); */
7d0cdf82
CMN
452 base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left);
453 if (base == NULL)
904b67e6 454 return GIT_EBUFS;
2aeadb9c 455
9d2f841a 456 ret = packfile_unpack_header1(&used, size_p, type_p, base, left);
45d773ef 457 git_mwindow_close(w_curs);
904b67e6 458 if (ret == GIT_EBUFS)
45d773ef
CMN
459 return ret;
460 else if (ret < 0)
e1de726c 461 return packfile_error("header length is zero");
7d0cdf82
CMN
462
463 *curpos += used;
e1de726c 464 return 0;
7d0cdf82
CMN
465}
466
44f9f547
DMB
467int git_packfile_resolve_header(
468 size_t *size_p,
469 git_otype *type_p,
470 struct git_pack_file *p,
471 git_off_t offset)
472{
473 git_mwindow *w_curs = NULL;
474 git_off_t curpos = offset;
475 size_t size;
476 git_otype type;
477 git_off_t base_offset;
478 int error;
479
480 error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
481 git_mwindow_close(&w_curs);
482 if (error < 0)
483 return error;
484
485 if (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) {
486 size_t base_size;
487 git_rawobj delta;
488 base_offset = get_delta_base(p, &w_curs, &curpos, type, offset);
489 git_mwindow_close(&w_curs);
490 error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, size, type);
491 git_mwindow_close(&w_curs);
492 if (error < 0)
493 return error;
494 error = git__delta_read_header(delta.data, delta.len, &base_size, size_p);
495 git__free(delta.data);
496 if (error < 0)
497 return error;
498 } else
499 *size_p = size;
500
501 while (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) {
502 curpos = base_offset;
503 error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
504 git_mwindow_close(&w_curs);
505 if (error < 0)
506 return error;
507 if (type != GIT_OBJ_OFS_DELTA && type != GIT_OBJ_REF_DELTA)
508 break;
509 base_offset = get_delta_base(p, &w_curs, &curpos, type, base_offset);
510 git_mwindow_close(&w_curs);
511 }
512 *type_p = type;
513
514 return error;
515}
516
15bcced2
CMN
517#define SMALL_STACK_SIZE 64
518
a3ffbf23
CMN
519/**
520 * Generate the chain of dependencies which we need to get to the
521 * object at `off`. `chain` is used a stack, popping gives the right
522 * order to apply deltas on. If an object is found in the pack's base
523 * cache, we stop calculating there.
524 */
15bcced2
CMN
525static int pack_dependency_chain(git_dependency_chain *chain_out,
526 git_pack_cache_entry **cached_out, git_off_t *cached_off,
527 struct pack_chain_elem *small_stack, size_t *stack_sz,
528 struct git_pack_file *p, git_off_t obj_offset)
a3ffbf23
CMN
529{
530 git_dependency_chain chain = GIT_ARRAY_INIT;
531 git_mwindow *w_curs = NULL;
532 git_off_t curpos = obj_offset, base_offset;
15bcced2
CMN
533 int error = 0, use_heap = 0;
534 size_t size, elem_pos;
a3ffbf23
CMN
535 git_otype type;
536
15bcced2 537 elem_pos = 0;
a3ffbf23
CMN
538 while (true) {
539 struct pack_chain_elem *elem;
540 git_pack_cache_entry *cached = NULL;
541
542 /* if we have a base cached, we can stop here instead */
543 if ((cached = cache_get(&p->bases, obj_offset)) != NULL) {
544 *cached_out = cached;
545 *cached_off = obj_offset;
546 break;
547 }
548
15bcced2
CMN
549 /* if we run out of space on the small stack, use the array */
550 if (elem_pos == SMALL_STACK_SIZE) {
551 git_array_init_to_size(chain, elem_pos);
552 GITERR_CHECK_ARRAY(chain);
553 memcpy(chain.ptr, small_stack, elem_pos * sizeof(struct pack_chain_elem));
554 chain.size = elem_pos;
555 use_heap = 1;
556 }
557
a3ffbf23 558 curpos = obj_offset;
15bcced2
CMN
559 if (!use_heap) {
560 elem = &small_stack[elem_pos];
561 } else {
562 elem = git_array_alloc(chain);
563 if (!elem) {
564 error = -1;
565 goto on_error;
566 }
a3ffbf23
CMN
567 }
568
569 elem->base_key = obj_offset;
570
571 error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
572 git_mwindow_close(&w_curs);
573
574 if (error < 0)
575 goto on_error;
576
577 elem->offset = curpos;
578 elem->size = size;
579 elem->type = type;
580 elem->base_key = obj_offset;
581
582 if (type != GIT_OBJ_OFS_DELTA && type != GIT_OBJ_REF_DELTA)
583 break;
584
585 base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
586 git_mwindow_close(&w_curs);
587
588 if (base_offset == 0) {
589 error = packfile_error("delta offset is zero");
590 goto on_error;
591 }
592 if (base_offset < 0) { /* must actually be an error code */
593 error = (int)base_offset;
594 goto on_error;
595 }
596
597 /* we need to pass the pos *after* the delta-base bit */
598 elem->offset = curpos;
599
600 /* go through the loop again, but with the new object */
601 obj_offset = base_offset;
15bcced2 602 elem_pos++;
a3ffbf23
CMN
603 }
604
15bcced2
CMN
605
606 *stack_sz = elem_pos + 1;
a3ffbf23
CMN
607 *chain_out = chain;
608 return error;
609
610on_error:
611 git_array_clear(chain);
612 return error;
613}
614
a070f152 615int git_packfile_unpack(
e1de726c
RB
616 git_rawobj *obj,
617 struct git_pack_file *p,
618 git_off_t *obj_offset)
7d0cdf82
CMN
619{
620 git_mwindow *w_curs = NULL;
e1de726c 621 git_off_t curpos = *obj_offset;
a332e91c
CMN
622 int error, free_base = 0;
623 git_dependency_chain chain = GIT_ARRAY_INIT;
15bcced2 624 struct pack_chain_elem *elem = NULL, *stack;
a332e91c 625 git_pack_cache_entry *cached = NULL;
15bcced2 626 struct pack_chain_elem small_stack[SMALL_STACK_SIZE];
e640a77c 627 size_t stack_size = 0, elem_pos;
2acdf4b8 628 git_otype base_type;
7d0cdf82
CMN
629
630 /*
631 * TODO: optionally check the CRC on the packfile
632 */
633
15bcced2 634 error = pack_dependency_chain(&chain, &cached, obj_offset, small_stack, &stack_size, p, *obj_offset);
2acdf4b8
CMN
635 if (error < 0)
636 return error;
637
7d0cdf82
CMN
638 obj->data = NULL;
639 obj->len = 0;
640 obj->type = GIT_OBJ_BAD;
641
15bcced2
CMN
642 /* let's point to the right stack */
643 stack = chain.ptr ? chain.ptr : small_stack;
644
645 elem_pos = stack_size;
a3ffbf23 646 if (cached) {
a332e91c 647 memcpy(obj, &cached->raw, sizeof(git_rawobj));
a3ffbf23 648 base_type = obj->type;
15bcced2 649 elem_pos--; /* stack_size includes the base, which isn't actually there */
a3ffbf23 650 } else {
15bcced2 651 elem = &stack[--elem_pos];
a3ffbf23 652 base_type = elem->type;
a332e91c 653 }
45d773ef 654
9dbd150f
CMN
655 switch (base_type) {
656 case GIT_OBJ_COMMIT:
657 case GIT_OBJ_TREE:
658 case GIT_OBJ_BLOB:
659 case GIT_OBJ_TAG:
a3ffbf23 660 if (!cached) {
9dbd150f
CMN
661 curpos = elem->offset;
662 error = packfile_unpack_compressed(obj, p, &w_curs, &curpos, elem->size, elem->type);
663 git_mwindow_close(&w_curs);
a3ffbf23 664 base_type = elem->type;
9dbd150f
CMN
665 }
666 if (error < 0)
667 goto cleanup;
668 break;
669 case GIT_OBJ_OFS_DELTA:
670 case GIT_OBJ_REF_DELTA:
671 error = packfile_error("dependency chain ends in a delta");
672 goto cleanup;
673 default:
674 error = packfile_error("invalid packfile type in header");
675 goto cleanup;
676 }
677
a332e91c 678 /*
c968ce2c 679 * Finding the object we want a cached base element is
a332e91c
CMN
680 * problematic, as we need to make sure we don't accidentally
681 * give the caller the cached object, which it would then feel
682 * free to free, so we need to copy the data.
683 */
15bcced2 684 if (cached && stack_size == 1) {
a332e91c 685 void *data = obj->data;
392702ee
ET
686
687 GITERR_CHECK_ALLOC_ADD(obj->len, 1);
a332e91c
CMN
688 obj->data = git__malloc(obj->len + 1);
689 GITERR_CHECK_ALLOC(obj->data);
392702ee 690
a332e91c
CMN
691 memcpy(obj->data, data, obj->len + 1);
692 git_atomic_dec(&cached->refcount);
693 goto cleanup;
694 }
695
2acdf4b8 696 /* we now apply each consecutive delta until we run out */
15bcced2 697 while (elem_pos > 0 && !error) {
2acdf4b8
CMN
698 git_rawobj base, delta;
699
c968ce2c
CMN
700 /*
701 * We can now try to add the base to the cache, as
702 * long as it's not already the cached one.
703 */
704 if (!cached)
705 free_base = !!cache_add(&p->bases, obj, elem->base_key);
706
15bcced2 707 elem = &stack[elem_pos - 1];
2acdf4b8
CMN
708 curpos = elem->offset;
709 error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, elem->size, elem->type);
710 git_mwindow_close(&w_curs);
711
712 if (error < 0)
713 break;
714
715 /* the current object becomes the new base, on which we apply the delta */
716 base = *obj;
717 obj->data = NULL;
718 obj->len = 0;
719 obj->type = GIT_OBJ_BAD;
720
721 error = git__delta_apply(obj, base.data, base.len, delta.data, delta.len);
a332e91c
CMN
722 obj->type = base_type;
723 /*
724 * We usually don't want to free the base at this
725 * point, as we put it into the cache in the previous
726 * iteration. free_base lets us know that we got the
727 * base object directly from the packfile, so we can free it.
728 */
2acdf4b8 729 git__free(delta.data);
a332e91c
CMN
730 if (free_base) {
731 free_base = 0;
732 git__free(base.data);
733 }
734
735 if (cached) {
736 git_atomic_dec(&cached->refcount);
737 cached = NULL;
738 }
2acdf4b8
CMN
739
740 if (error < 0)
741 break;
7d0cdf82 742
15bcced2 743 elem_pos--;
7d0cdf82
CMN
744 }
745
2acdf4b8 746cleanup:
a332e91c
CMN
747 if (error < 0)
748 git__free(obj->data);
749
a3ffbf23 750 if (elem)
b3d3459f 751 *obj_offset = curpos;
a332e91c 752
2acdf4b8 753 git_array_clear(chain);
e1de726c 754 return error;
7d0cdf82
CMN
755}
756
282283ac
RB
757static void *use_git_alloc(void *opaq, unsigned int count, unsigned int size)
758{
759 GIT_UNUSED(opaq);
760 return git__calloc(count, size);
761}
762
763static void use_git_free(void *opaq, void *ptr)
764{
765 GIT_UNUSED(opaq);
766 git__free(ptr);
767}
768
46635339
CMN
769int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, git_off_t curpos)
770{
771 int st;
772
773 memset(obj, 0, sizeof(git_packfile_stream));
774 obj->curpos = curpos;
775 obj->p = p;
776 obj->zstream.zalloc = use_git_alloc;
777 obj->zstream.zfree = use_git_free;
778 obj->zstream.next_in = Z_NULL;
779 obj->zstream.next_out = Z_NULL;
780 st = inflateInit(&obj->zstream);
781 if (st != Z_OK) {
782 git__free(obj);
ae081739 783 giterr_set(GITERR_ZLIB, "failed to init packfile stream");
46635339
CMN
784 return -1;
785 }
786
787 return 0;
788}
789
790ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len)
791{
792 unsigned char *in;
793 size_t written;
794 int st;
795
796 if (obj->done)
797 return 0;
798
799 in = pack_window_open(obj->p, &obj->mw, obj->curpos, &obj->zstream.avail_in);
800 if (in == NULL)
801 return GIT_EBUFS;
802
803 obj->zstream.next_out = buffer;
090d5e1f 804 obj->zstream.avail_out = (unsigned int)len;
46635339
CMN
805 obj->zstream.next_in = in;
806
807 st = inflate(&obj->zstream, Z_SYNC_FLUSH);
808 git_mwindow_close(&obj->mw);
809
810 obj->curpos += obj->zstream.next_in - in;
811 written = len - obj->zstream.avail_out;
812
813 if (st != Z_OK && st != Z_STREAM_END) {
ae081739 814 giterr_set(GITERR_ZLIB, "error reading from the zlib stream");
46635339
CMN
815 return -1;
816 }
817
818 if (st == Z_STREAM_END)
819 obj->done = 1;
820
821
822 /* If we didn't write anything out but we're not done, we need more data */
823 if (!written && st != Z_STREAM_END)
824 return GIT_EBUFS;
825
826 return written;
827
828}
829
830void git_packfile_stream_free(git_packfile_stream *obj)
831{
832 inflateEnd(&obj->zstream);
833}
834
7d0cdf82 835int packfile_unpack_compressed(
e1de726c
RB
836 git_rawobj *obj,
837 struct git_pack_file *p,
838 git_mwindow **w_curs,
839 git_off_t *curpos,
840 size_t size,
841 git_otype type)
7d0cdf82
CMN
842{
843 int st;
844 z_stream stream;
845 unsigned char *buffer, *in;
846
392702ee 847 GITERR_CHECK_ALLOC_ADD(size, 1);
e1de726c
RB
848 buffer = git__calloc(1, size + 1);
849 GITERR_CHECK_ALLOC(buffer);
7d0cdf82
CMN
850
851 memset(&stream, 0, sizeof(stream));
852 stream.next_out = buffer;
1c3fac4d 853 stream.avail_out = (uInt)size + 1;
282283ac
RB
854 stream.zalloc = use_git_alloc;
855 stream.zfree = use_git_free;
7d0cdf82
CMN
856
857 st = inflateInit(&stream);
858 if (st != Z_OK) {
3286c408 859 git__free(buffer);
ae081739 860 giterr_set(GITERR_ZLIB, "failed to init zlib stream on unpack");
45d773ef 861
e1de726c 862 return -1;
7d0cdf82
CMN
863 }
864
865 do {
b5b474dd 866 in = pack_window_open(p, w_curs, *curpos, &stream.avail_in);
7d0cdf82
CMN
867 stream.next_in = in;
868 st = inflate(&stream, Z_FINISH);
45d773ef 869 git_mwindow_close(w_curs);
7d0cdf82
CMN
870
871 if (!stream.avail_out)
872 break; /* the payload is larger than it should be */
873
45d773ef
CMN
874 if (st == Z_BUF_ERROR && in == NULL) {
875 inflateEnd(&stream);
876 git__free(buffer);
904b67e6 877 return GIT_EBUFS;
45d773ef
CMN
878 }
879
b5b474dd 880 *curpos += stream.next_in - in;
7d0cdf82
CMN
881 } while (st == Z_OK || st == Z_BUF_ERROR);
882
883 inflateEnd(&stream);
884
885 if ((st != Z_STREAM_END) || stream.total_out != size) {
3286c408 886 git__free(buffer);
ae081739 887 giterr_set(GITERR_ZLIB, "error inflating zlib stream");
e1de726c 888 return -1;
7d0cdf82
CMN
889 }
890
891 obj->type = type;
892 obj->len = size;
893 obj->data = buffer;
e1de726c 894 return 0;
7d0cdf82
CMN
895}
896
b5b474dd
CMN
897/*
898 * curpos is where the data starts, delta_obj_offset is the where the
899 * header starts
900 */
e1de726c
RB
901git_off_t get_delta_base(
902 struct git_pack_file *p,
903 git_mwindow **w_curs,
904 git_off_t *curpos,
905 git_otype type,
906 git_off_t delta_obj_offset)
7d0cdf82 907{
45d773ef
CMN
908 unsigned int left = 0;
909 unsigned char *base_info;
e1de726c 910 git_off_t base_offset;
7d0cdf82
CMN
911 git_oid unused;
912
45d773ef
CMN
913 base_info = pack_window_open(p, w_curs, *curpos, &left);
914 /* Assumption: the only reason this would fail is because the file is too small */
915 if (base_info == NULL)
904b67e6 916 return GIT_EBUFS;
7d0cdf82
CMN
917 /* pack_window_open() assured us we have [base_info, base_info + 20)
918 * as a range that we can look at without walking off the
87d9869f
VM
919 * end of the mapped window. Its actually the hash size
920 * that is assured. An OFS_DELTA longer than the hash size
7d0cdf82
CMN
921 * is stupid, as then a REF_DELTA would be smaller to store.
922 */
923 if (type == GIT_OBJ_OFS_DELTA) {
924 unsigned used = 0;
925 unsigned char c = base_info[used++];
926 base_offset = c & 127;
927 while (c & 128) {
45d773ef 928 if (left <= used)
904b67e6 929 return GIT_EBUFS;
7d0cdf82
CMN
930 base_offset += 1;
931 if (!base_offset || MSB(base_offset, 7))
87d9869f 932 return 0; /* overflow */
7d0cdf82
CMN
933 c = base_info[used++];
934 base_offset = (base_offset << 7) + (c & 127);
935 }
936 base_offset = delta_obj_offset - base_offset;
937 if (base_offset <= 0 || base_offset >= delta_obj_offset)
87d9869f 938 return 0; /* out of bound */
7d0cdf82
CMN
939 *curpos += used;
940 } else if (type == GIT_OBJ_REF_DELTA) {
c1af5a39
CMN
941 /* If we have the cooperative cache, search in it first */
942 if (p->has_cache) {
0e040c03
CMN
943 khiter_t k;
944 git_oid oid;
c1af5a39 945
0e040c03
CMN
946 git_oid_fromraw(&oid, base_info);
947 k = kh_get(oid, p->idx_cache, &oid);
948 if (k != kh_end(p->idx_cache)) {
c1af5a39 949 *curpos += 20;
0e040c03 950 return ((struct git_pack_entry *)kh_value(p->idx_cache, k))->offset;
c1af5a39
CMN
951 }
952 }
7d0cdf82 953 /* The base entry _must_ be in the same pack */
e1de726c
RB
954 if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < 0)
955 return packfile_error("base entry delta is not in the same pack");
7d0cdf82
CMN
956 *curpos += 20;
957 } else
958 return 0;
959
960 return base_offset;
961}
a070f152
CMN
962
963/***********************************************************
964 *
965 * PACKFILE METHODS
966 *
967 ***********************************************************/
968
96c9b9f0 969void git_packfile_free(struct git_pack_file *p)
a070f152 970{
24c70804
RB
971 if (!p)
972 return;
973
c8f79c2b 974 cache_free(&p->bases);
c0f4a011 975
5e0f47c3
CMN
976 if (p->mwf.fd >= 0) {
977 git_mwindow_free_all_locked(&p->mwf);
a070f152 978 p_close(p->mwf.fd);
5e0f47c3 979 }
a070f152
CMN
980
981 pack_index_free(p);
982
3286c408 983 git__free(p->bad_object_sha1);
24c70804 984
24c70804 985 git_mutex_free(&p->lock);
649214be 986 git_mutex_free(&p->bases.lock);
3286c408 987 git__free(p);
a070f152
CMN
988}
989
990static int packfile_open(struct git_pack_file *p)
991{
992 struct stat st;
993 struct git_pack_header hdr;
994 git_oid sha1;
995 unsigned char *idx_sha1;
996
0ddfcb40 997 if (p->index_version == -1 && pack_index_open(p) < 0)
282283ac 998 return git_odb__error_notfound("failed to open packfile", NULL);
a070f152 999
9d2f841a
RB
1000 /* if mwf opened by another thread, return now */
1001 if (git_mutex_lock(&p->lock) < 0)
1002 return packfile_error("failed to get lock for open");
1003
1004 if (p->mwf.fd >= 0) {
1005 git_mutex_unlock(&p->lock);
1006 return 0;
1007 }
1008
a070f152 1009 /* TODO: open with noatime */
e1de726c 1010 p->mwf.fd = git_futils_open_ro(p->pack_name);
9d2f841a
RB
1011 if (p->mwf.fd < 0)
1012 goto cleanup;
a070f152 1013
e1de726c
RB
1014 if (p_fstat(p->mwf.fd, &st) < 0 ||
1015 git_mwindow_file_register(&p->mwf) < 0)
1016 goto cleanup;
a070f152
CMN
1017
1018 /* If we created the struct before we had the pack we lack size. */
1019 if (!p->mwf.size) {
1020 if (!S_ISREG(st.st_mode))
1021 goto cleanup;
e1de726c 1022 p->mwf.size = (git_off_t)st.st_size;
a070f152
CMN
1023 } else if (p->mwf.size != st.st_size)
1024 goto cleanup;
1025
1026#if 0
1027 /* We leave these file descriptors open with sliding mmap;
1028 * there is no point keeping them open across exec(), though.
1029 */
1030 fd_flag = fcntl(p->mwf.fd, F_GETFD, 0);
1031 if (fd_flag < 0)
e1de726c 1032 goto cleanup;
a070f152
CMN
1033
1034 fd_flag |= FD_CLOEXEC;
1035 if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
e1de726c 1036 goto cleanup;
a070f152
CMN
1037#endif
1038
1039 /* Verify we recognize this pack file format. */
e1de726c
RB
1040 if (p_read(p->mwf.fd, &hdr, sizeof(hdr)) < 0 ||
1041 hdr.hdr_signature != htonl(PACK_SIGNATURE) ||
1042 !pack_version_ok(hdr.hdr_version))
a070f152
CMN
1043 goto cleanup;
1044
1045 /* Verify the pack matches its index. */
e1de726c
RB
1046 if (p->num_objects != ntohl(hdr.hdr_entries) ||
1047 p_lseek(p->mwf.fd, p->mwf.size - GIT_OID_RAWSZ, SEEK_SET) == -1 ||
1048 p_read(p->mwf.fd, sha1.id, GIT_OID_RAWSZ) < 0)
a070f152
CMN
1049 goto cleanup;
1050
1051 idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40;
1052
9d2f841a
RB
1053 if (git_oid__cmp(&sha1, (git_oid *)idx_sha1) != 0)
1054 goto cleanup;
1055
1056 git_mutex_unlock(&p->lock);
1057 return 0;
a070f152
CMN
1058
1059cleanup:
e1de726c 1060 giterr_set(GITERR_OS, "Invalid packfile '%s'", p->pack_name);
9d2f841a 1061
3a2d48d5
SS
1062 if (p->mwf.fd >= 0)
1063 p_close(p->mwf.fd);
a070f152 1064 p->mwf.fd = -1;
9d2f841a
RB
1065
1066 git_mutex_unlock(&p->lock);
1067
e1de726c 1068 return -1;
a070f152
CMN
1069}
1070
b3b66c57
CMN
1071int git_packfile__name(char **out, const char *path)
1072{
1073 size_t path_len;
1074 git_buf buf = GIT_BUF_INIT;
1075
1076 path_len = strlen(path);
1077
1078 if (path_len < strlen(".idx"))
1079 return git_odb__error_notfound("invalid packfile path", NULL);
1080
1081 if (git_buf_printf(&buf, "%.*s.pack", (int)(path_len - strlen(".idx")), path) < 0)
1082 return -1;
1083
1084 *out = git_buf_detach(&buf);
1085 return 0;
1086}
1087
5d2d21e5 1088int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
a070f152
CMN
1089{
1090 struct stat st;
1091 struct git_pack_file *p;
38eef611 1092 size_t path_len = path ? strlen(path) : 0;
a070f152
CMN
1093
1094 *pack_out = NULL;
24c70804 1095
38eef611 1096 if (path_len < strlen(".idx"))
24c70804
RB
1097 return git_odb__error_notfound("invalid packfile path", NULL);
1098
392702ee
ET
1099 GITERR_CHECK_ALLOC_ADD(sizeof(*p), path_len);
1100 GITERR_CHECK_ALLOC_ADD(sizeof(*p) + path_len, 2);
1101
38eef611 1102 p = git__calloc(1, sizeof(*p) + path_len + 2);
e1de726c 1103 GITERR_CHECK_ALLOC(p);
a070f152 1104
38eef611
RB
1105 memcpy(p->pack_name, path, path_len + 1);
1106
a070f152
CMN
1107 /*
1108 * Make sure a corresponding .pack file exists and that
1109 * the index looks sane.
1110 */
38eef611
RB
1111 if (git__suffixcmp(path, ".idx") == 0) {
1112 size_t root_len = path_len - strlen(".idx");
1113
1114 memcpy(p->pack_name + root_len, ".keep", sizeof(".keep"));
1115 if (git_path_exists(p->pack_name) == true)
1116 p->pack_keep = 1;
a070f152 1117
38eef611 1118 memcpy(p->pack_name + root_len, ".pack", sizeof(".pack"));
38eef611 1119 }
a070f152 1120
e1de726c 1121 if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) {
3286c408 1122 git__free(p);
282283ac 1123 return git_odb__error_notfound("packfile not found", NULL);
a070f152
CMN
1124 }
1125
1126 /* ok, it looks sane as far as we can check without
1127 * actually mapping the pack file.
1128 */
38eef611 1129 p->mwf.fd = -1;
1af56d7d 1130 p->mwf.size = st.st_size;
a070f152
CMN
1131 p->pack_local = 1;
1132 p->mtime = (git_time_t)st.st_mtime;
0ddfcb40 1133 p->index_version = -1;
a070f152 1134
1a42dd17
RB
1135 if (git_mutex_init(&p->lock)) {
1136 giterr_set(GITERR_OS, "Failed to initialize packfile mutex");
1137 git__free(p);
1138 return -1;
1139 }
38eef611 1140
649214be
CMN
1141 if (cache_init(&p->bases) < 0) {
1142 git__free(p);
1143 return -1;
1144 }
1145
a070f152 1146 *pack_out = p;
e1de726c
RB
1147
1148 return 0;
a070f152
CMN
1149}
1150
1151/***********************************************************
1152 *
1153 * PACKFILE ENTRY SEARCH INTERNALS
1154 *
1155 ***********************************************************/
1156
e1de726c 1157static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n)
a070f152
CMN
1158{
1159 const unsigned char *index = p->index_map.data;
1160 index += 4 * 256;
1161 if (p->index_version == 1) {
1162 return ntohl(*((uint32_t *)(index + 24 * n)));
1163 } else {
1164 uint32_t off;
1165 index += 8 + p->num_objects * (20 + 4);
1166 off = ntohl(*((uint32_t *)(index + 4 * n)));
1167 if (!(off & 0x80000000))
1168 return off;
1169 index += p->num_objects * 4 + (off & 0x7fffffff) * 8;
1170 return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
87d9869f 1171 ntohl(*((uint32_t *)(index + 4)));
a070f152
CMN
1172 }
1173}
1174
60ecdf59
DMB
1175static int git__memcmp4(const void *a, const void *b) {
1176 return memcmp(a, b, 4);
1177}
1178
521aedad 1179int git_pack_foreach_entry(
5dca2010 1180 struct git_pack_file *p,
c3fb7d04 1181 git_odb_foreach_cb cb,
5dca2010 1182 void *data)
521aedad
CMN
1183{
1184 const unsigned char *index = p->index_map.data, *current;
521aedad 1185 uint32_t i;
dab89f9b 1186 int error = 0;
521aedad
CMN
1187
1188 if (index == NULL) {
521aedad
CMN
1189 if ((error = pack_index_open(p)) < 0)
1190 return error;
1191
1192 assert(p->index_map.data);
1193
1194 index = p->index_map.data;
1195 }
1196
1197 if (p->index_version > 1) {
1198 index += 8;
1199 }
1200
1201 index += 4 * 256;
1202
60ecdf59
DMB
1203 if (p->oids == NULL) {
1204 git_vector offsets, oids;
521aedad 1205
60ecdf59
DMB
1206 if ((error = git_vector_init(&oids, p->num_objects, NULL)))
1207 return error;
1208
1209 if ((error = git_vector_init(&offsets, p->num_objects, git__memcmp4)))
1210 return error;
5dca2010 1211
60ecdf59
DMB
1212 if (p->index_version > 1) {
1213 const unsigned char *off = index + 24 * p->num_objects;
1214 for (i = 0; i < p->num_objects; i++)
1215 git_vector_insert(&offsets, (void*)&off[4 * i]);
1216 git_vector_sort(&offsets);
1217 git_vector_foreach(&offsets, i, current)
1218 git_vector_insert(&oids, (void*)&index[5 * (current - off)]);
1219 } else {
1220 for (i = 0; i < p->num_objects; i++)
1221 git_vector_insert(&offsets, (void*)&index[24 * i]);
1222 git_vector_sort(&offsets);
1223 git_vector_foreach(&offsets, i, current)
1224 git_vector_insert(&oids, (void*)&current[4]);
1225 }
25e0b157 1226
60ecdf59 1227 git_vector_free(&offsets);
25e0b157 1228 p->oids = (git_oid **)git_vector_detach(NULL, NULL, &oids);
521aedad
CMN
1229 }
1230
60ecdf59 1231 for (i = 0; i < p->num_objects; i++)
26c1cb91
RB
1232 if ((error = cb(p->oids[i], data)) != 0)
1233 return giterr_set_after_callback(error);
60ecdf59 1234
25e0b157 1235 return error;
521aedad
CMN
1236}
1237
a070f152 1238static int pack_entry_find_offset(
e1de726c
RB
1239 git_off_t *offset_out,
1240 git_oid *found_oid,
1241 struct git_pack_file *p,
1242 const git_oid *short_oid,
b8457baa 1243 size_t len)
a070f152 1244{
34bd5999
CMN
1245 const uint32_t *level1_ofs = p->index_map.data;
1246 const unsigned char *index = p->index_map.data;
a070f152
CMN
1247 unsigned hi, lo, stride;
1248 int pos, found = 0;
1249 const unsigned char *current = 0;
1250
1251 *offset_out = 0;
1252
0ddfcb40 1253 if (p->index_version == -1) {
34bd5999 1254 int error;
a070f152 1255
34bd5999
CMN
1256 if ((error = pack_index_open(p)) < 0)
1257 return error;
1258 assert(p->index_map.data);
8c535f3f 1259
34bd5999
CMN
1260 index = p->index_map.data;
1261 level1_ofs = p->index_map.data;
1262 }
a070f152
CMN
1263
1264 if (p->index_version > 1) {
1265 level1_ofs += 2;
1266 index += 8;
1267 }
1268
1269 index += 4 * 256;
1270 hi = ntohl(level1_ofs[(int)short_oid->id[0]]);
1271 lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(level1_ofs[(int)short_oid->id[0] - 1]));
1272
1273 if (p->index_version > 1) {
1274 stride = 20;
1275 } else {
1276 stride = 24;
1277 index += 4;
1278 }
1279
1280#ifdef INDEX_DEBUG_LOOKUP
1281 printf("%02x%02x%02x... lo %u hi %u nr %d\n",
1282 short_oid->id[0], short_oid->id[1], short_oid->id[2], lo, hi, p->num_objects);
1283#endif
1284
67591c8c 1285#ifdef GIT_USE_LOOKUP
87d9869f 1286 pos = sha1_entry_pos(index, stride, 0, lo, hi, p->num_objects, short_oid->id);
67591c8c
VM
1287#else
1288 pos = sha1_position(index, stride, lo, hi, short_oid->id);
1289#endif
a070f152
CMN
1290
1291 if (pos >= 0) {
1292 /* An object matching exactly the oid was found */
1293 found = 1;
1294 current = index + pos * stride;
1295 } else {
1296 /* No object was found */
1297 /* pos refers to the object with the "closest" oid to short_oid */
1298 pos = - 1 - pos;
1299 if (pos < (int)p->num_objects) {
1300 current = index + pos * stride;
1301
282283ac 1302 if (!git_oid_ncmp(short_oid, (const git_oid *)current, len))
a070f152 1303 found = 1;
a070f152
CMN
1304 }
1305 }
1306
b2a2702d 1307 if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)p->num_objects) {
a070f152
CMN
1308 /* Check for ambiguousity */
1309 const unsigned char *next = current + stride;
1310
1311 if (!git_oid_ncmp(short_oid, (const git_oid *)next, len)) {
1312 found = 2;
1313 }
1314 }
1315
e1de726c 1316 if (!found)
282283ac 1317 return git_odb__error_notfound("failed to find offset for pack entry", short_oid);
e1de726c
RB
1318 if (found > 1)
1319 return git_odb__error_ambiguous("found multiple offsets for pack entry");
24c70804 1320
e1de726c
RB
1321 *offset_out = nth_packed_object_offset(p, pos);
1322 git_oid_fromraw(found_oid, current);
a070f152
CMN
1323
1324#ifdef INDEX_DEBUG_LOOKUP
e1de726c 1325 {
a070f152
CMN
1326 unsigned char hex_sha1[GIT_OID_HEXSZ + 1];
1327 git_oid_fmt(hex_sha1, found_oid);
1328 hex_sha1[GIT_OID_HEXSZ] = '\0';
1329 printf("found lo=%d %s\n", lo, hex_sha1);
a070f152 1330 }
e1de726c 1331#endif
24c70804 1332
e1de726c 1333 return 0;
a070f152
CMN
1334}
1335
1336int git_pack_entry_find(
1337 struct git_pack_entry *e,
1338 struct git_pack_file *p,
1339 const git_oid *short_oid,
b8457baa 1340 size_t len)
a070f152 1341{
e1de726c 1342 git_off_t offset;
a070f152
CMN
1343 git_oid found_oid;
1344 int error;
1345
1346 assert(p);
1347
1348 if (len == GIT_OID_HEXSZ && p->num_bad_objects) {
1349 unsigned i;
1350 for (i = 0; i < p->num_bad_objects; i++)
b7f167da 1351 if (git_oid__cmp(short_oid, &p->bad_object_sha1[i]) == 0)
e1de726c 1352 return packfile_error("bad object found in packfile");
a070f152
CMN
1353 }
1354
1355 error = pack_entry_find_offset(&offset, &found_oid, p, short_oid, len);
e1de726c
RB
1356 if (error < 0)
1357 return error;
a070f152
CMN
1358
1359 /* we found a unique entry in the index;
1360 * make sure the packfile backing the index
1361 * still exists on disk */
e1de726c
RB
1362 if (p->mwf.fd == -1 && (error = packfile_open(p)) < 0)
1363 return error;
a070f152
CMN
1364
1365 e->offset = offset;
1366 e->p = p;
1367
1368 git_oid_cpy(&e->sha1, &found_oid);
e1de726c 1369 return 0;
a070f152 1370}