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