]>
git.proxmox.com Git - libgit2.git/blob - src/odb.c
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.
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.)
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.
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.
33 #define GIT_PACK_NAME_MAX (5 + 40 + 1)
46 /** Functions to access idx_map. */
51 int (*idx_search_offset
)(
60 /** The .idx file, mapped into memory. */
64 unsigned char *im_oid
;
66 uint32_t *im_offset32
;
67 uint32_t *im_offset64
;
69 uint32_t *im_off_next
;
71 /** Number of objects in this pack. */
74 /** The size of the .pack file. */
77 /** The mtime of the .pack file. */
80 /** Number of git_packlist we appear in. */
83 /** Number of active users of the idx_map data. */
86 invalid
:1 /* the pack is unable to be read by libgit2 */
89 /** Name of the pack file(s), without extension ("pack-abc"). */
90 char pack_name
[GIT_PACK_NAME_MAX
];
92 typedef struct git_pack git_pack
;
97 git_pack
*packs
[GIT_FLEX_ARRAY
];
103 /** Path to the "objects" directory. */
106 /** Known pack files from ${objects_dir}/packs. */
107 git_packlist
*packlist
;
109 /** Alternate databases to search. */
110 git_odb
**alternates
;
113 /** loose object zlib compression level. */
114 int object_zlib_level
;
115 /** loose object file fsync flag. */
116 int fsync_object_files
;
119 typedef struct { /* object header data */
120 git_otype type
; /* object type */
121 size_t size
; /* object size */
125 const char *str
; /* type name string */
126 int loose
; /* valid loose object type flag */
127 } obj_type_table
[] = {
128 { "", 0 }, /* 0 = GIT_OBJ__EXT1 */
129 { "commit", 1 }, /* 1 = GIT_OBJ_COMMIT */
130 { "tree", 1 }, /* 2 = GIT_OBJ_TREE */
131 { "blob", 1 }, /* 3 = GIT_OBJ_BLOB */
132 { "tag", 1 }, /* 4 = GIT_OBJ_TAG */
133 { "", 0 }, /* 5 = GIT_OBJ__EXT2 */
134 { "OFS_DELTA", 0 }, /* 6 = GIT_OBJ_OFS_DELTA */
135 { "REF_DELTA", 0 } /* 7 = GIT_OBJ_REF_DELTA */
138 GIT_INLINE(uint32_t) decode32(void *b
)
140 return ntohl(*((uint32_t *)b
));
143 GIT_INLINE(uint64_t) decode64(void *b
)
146 return (((uint64_t)ntohl(p
[0])) << 32) | ntohl(p
[1]);
149 const char *git_obj_type_to_string(git_otype type
)
151 if (type
< 0 || ((size_t) type
) >= ARRAY_SIZE(obj_type_table
))
153 return obj_type_table
[type
].str
;
156 git_otype
git_obj_string_to_type(const char *str
)
163 for (i
= 0; i
< ARRAY_SIZE(obj_type_table
); i
++)
164 if (!strcmp(str
, obj_type_table
[i
].str
))
165 return (git_otype
) i
;
170 int git_obj__loose_object_type(git_otype type
)
172 if (type
< 0 || ((size_t) type
) >= ARRAY_SIZE(obj_type_table
))
174 return obj_type_table
[type
].loose
;
177 static int format_object_header(char *hdr
, size_t n
, git_obj
*obj
)
179 const char *type_str
= git_obj_type_to_string(obj
->type
);
180 int len
= snprintf(hdr
, n
, "%s %"PRIuZ
, type_str
, obj
->len
);
182 assert(len
> 0); /* otherwise snprintf() is broken */
183 assert(((size_t) len
) < n
); /* otherwise the caller is broken! */
185 if (len
< 0 || ((size_t) len
) >= n
)
190 static int hash_obj(git_oid
*id
, char *hdr
, size_t n
, int *len
, git_obj
*obj
)
195 assert(id
&& hdr
&& len
&& obj
);
197 if (!git_obj__loose_object_type(obj
->type
))
200 if (!obj
->data
&& obj
->len
!= 0)
203 if ((hdrlen
= format_object_header(hdr
, n
, obj
)) < 0)
210 vec
[1].data
= obj
->data
;
211 vec
[1].len
= obj
->len
;
213 git_hash_vec(id
, vec
, 2);
218 int git_obj_hash(git_oid
*id
, git_obj
*obj
)
225 return hash_obj(id
, hdr
, sizeof(hdr
), &hdrlen
, obj
);
228 static size_t object_file_name(char *name
, size_t n
, char *dir
, const git_oid
*id
)
230 size_t len
= strlen(dir
);
232 /* check length: 43 = 40 hex sha1 chars + 2 * '/' + '\0' */
236 /* the object dir: eg $GIT_DIR/objects */
238 if (name
[len
-1] != '/')
241 /* loose object filename: aa/aaa... (41 bytes) */
242 git_oid_pathfmt(&name
[len
], id
);
248 static int is_zlib_compressed_data(unsigned char *data
)
252 w
= ((unsigned int)(data
[0]) << 8) + data
[1];
253 return data
[0] == 0x78 && !(w
% 31);
256 static size_t get_binary_object_header(obj_hdr
*hdr
, gitfo_buf
*obj
)
259 unsigned char *data
= obj
->data
;
260 size_t shift
, size
, used
= 0;
266 hdr
->type
= (c
>> 4) & 7;
271 if (obj
->len
<= used
)
273 if (sizeof(size_t) * 8 <= shift
)
276 size
+= (c
& 0x7f) << shift
;
284 static size_t get_object_header(obj_hdr
*hdr
, unsigned char *data
)
286 char c
, typename
[10];
287 size_t size
, used
= 0;
290 * type name string followed by space.
292 while ((c
= data
[used
]) != ' ') {
293 typename
[used
++] = c
;
294 if (used
>= sizeof(typename
))
300 hdr
->type
= git_obj_string_to_type(typename
);
301 used
++; /* consume the space */
304 * length follows immediately in decimal (without
307 size
= data
[used
++] - '0';
311 while ((c
= data
[used
]) != '\0') {
316 size
= size
* 10 + d
;
322 * the length must be followed by a zero byte
324 if (data
[used
++] != '\0')
330 static void init_stream(z_stream
*s
, void *out
, size_t len
)
332 memset(s
, 0, sizeof(*s
));
337 static void set_stream_input(z_stream
*s
, void *in
, size_t len
)
343 static void set_stream_output(z_stream
*s
, void *out
, size_t len
)
349 static int start_inflate(z_stream
*s
, gitfo_buf
*obj
, void *out
, size_t len
)
353 init_stream(s
, out
, len
);
354 set_stream_input(s
, obj
->data
, obj
->len
);
356 if ((status
= inflateInit(s
)) < Z_OK
)
359 return inflate(s
, 0);
362 static int finish_inflate(z_stream
*s
)
366 while (status
== Z_OK
)
367 status
= inflate(s
, Z_FINISH
);
371 if ((status
!= Z_STREAM_END
) || (s
->avail_in
!= 0))
377 static void *inflate_tail(z_stream
*s
, void *hb
, size_t used
, obj_hdr
*hdr
)
379 unsigned char *buf
, *head
= hb
;
383 * allocate a buffer to hold the inflated data and copy the
384 * initial sequence of inflated data from the tail of the
385 * head buffer, if any.
387 if ((buf
= git__malloc(hdr
->size
+ 1)) == NULL
) {
391 tail
= s
->total_out
- used
;
392 if (used
> 0 && tail
> 0) {
393 if (tail
> hdr
->size
)
395 memcpy(buf
, head
+ used
, tail
);
400 * inflate the remainder of the object data, if any
402 if (hdr
->size
< used
)
405 set_stream_output(s
, buf
+ used
, hdr
->size
- used
);
406 if (finish_inflate(s
)) {
415 static int inflate_buffer(void *in
, size_t inlen
, void *out
, size_t outlen
)
420 init_stream(&zs
, out
, outlen
);
421 set_stream_input(&zs
, in
, inlen
);
423 if (inflateInit(&zs
) < Z_OK
)
426 while (status
== Z_OK
)
427 status
= inflate(&zs
, Z_FINISH
);
431 if ((status
!= Z_STREAM_END
) || (zs
.avail_in
!= 0))
434 if (zs
.total_out
!= outlen
)
441 * At one point, there was a loose object format that was intended to
442 * mimic the format used in pack-files. This was to allow easy copying
443 * of loose object data into packs. This format is no longer used, but
444 * we must still read it.
446 static int inflate_packlike_loose_disk_obj(git_obj
*out
, gitfo_buf
*obj
)
448 unsigned char *in
, *buf
;
453 * read the object header, which is an (uncompressed)
454 * binary encoding of the object type and size.
456 if ((used
= get_binary_object_header(&hdr
, obj
)) == 0)
459 if (!git_obj__loose_object_type(hdr
.type
))
463 * allocate a buffer and inflate the data into it
465 buf
= git__malloc(hdr
.size
+ 1);
469 in
= ((unsigned char *)obj
->data
) + used
;
470 len
= obj
->len
- used
;
471 if (inflate_buffer(in
, len
, buf
, hdr
.size
)) {
475 buf
[hdr
.size
] = '\0';
479 out
->type
= hdr
.type
;
484 static int inflate_disk_obj(git_obj
*out
, gitfo_buf
*obj
)
486 unsigned char head
[64], *buf
;
493 * check for a pack-like loose object
495 if (!is_zlib_compressed_data(obj
->data
))
496 return inflate_packlike_loose_disk_obj(out
, obj
);
499 * inflate the initial part of the io buffer in order
500 * to parse the object header (type and size).
502 if ((z_status
= start_inflate(&zs
, obj
, head
, sizeof(head
))) < Z_OK
)
505 if ((used
= get_object_header(&hdr
, head
)) == 0)
508 if (!git_obj__loose_object_type(hdr
.type
))
512 * allocate a buffer and inflate the object data into it
513 * (including the initial sequence in the head buffer).
515 if ((buf
= inflate_tail(&zs
, head
, used
, &hdr
)) == NULL
)
517 buf
[hdr
.size
] = '\0';
521 out
->type
= hdr
.type
;
526 static int make_temp_file(git_file
*fd
, char *tmp
, size_t n
, char *file
)
528 char *template = "/tmp_obj_XXXXXX";
529 size_t tmplen
= strlen(template);
532 if ((dirlen
= git__dirname(tmp
, n
, file
)) < 0)
535 if ((dirlen
+ tmplen
) >= n
)
538 strcpy(tmp
+ dirlen
, (dirlen
) ? template : template + 1);
540 *fd
= gitfo_mkstemp(tmp
);
541 if (*fd
< 0 && dirlen
) {
542 /* create directory if it doesn't exist */
544 if ((gitfo_exists(tmp
) < 0) && gitfo_mkdir(tmp
, 0755))
547 strcpy(tmp
+ dirlen
, template);
548 *fd
= gitfo_mkstemp(tmp
);
556 static int deflate_buf(z_stream
*s
, void *in
, size_t len
, int flush
)
560 set_stream_input(s
, in
, len
);
561 while (status
== Z_OK
) {
562 status
= deflate(s
, flush
);
563 if (s
->avail_in
== 0)
569 static int deflate_obj(gitfo_buf
*buf
, char *hdr
, int hdrlen
, git_obj
*obj
, int level
)
575 assert(buf
&& !buf
->data
&& hdr
&& obj
);
576 assert(level
== Z_DEFAULT_COMPRESSION
|| (level
>= 0 && level
<= 9));
580 init_stream(&zs
, NULL
, 0);
582 if (deflateInit(&zs
, level
) < Z_OK
)
585 size
= deflateBound(&zs
, hdrlen
+ obj
->len
);
587 if ((buf
->data
= git__malloc(size
)) == NULL
) {
592 set_stream_output(&zs
, buf
->data
, size
);
594 /* compress the header */
595 status
= deflate_buf(&zs
, hdr
, hdrlen
, Z_NO_FLUSH
);
597 /* if header compressed OK, compress the object */
599 status
= deflate_buf(&zs
, obj
->data
, obj
->len
, Z_FINISH
);
601 if (status
!= Z_STREAM_END
) {
608 buf
->len
= zs
.total_out
;
614 static int write_obj(gitfo_buf
*buf
, git_oid
*id
, git_odb
*db
)
616 char file
[GIT_PATH_MAX
];
617 char temp
[GIT_PATH_MAX
];
620 if (object_file_name(file
, sizeof(file
), db
->objects_dir
, id
))
623 if (make_temp_file(&fd
, temp
, sizeof(temp
), file
) < 0)
626 if (gitfo_write(fd
, buf
->data
, buf
->len
) < 0) {
632 if (db
->fsync_object_files
)
635 gitfo_chmod(temp
, 0444);
637 if (gitfo_move_file(temp
, file
) < 0) {
645 static int open_alternates(git_odb
*db
)
649 gitlck_lock(&db
->lock
);
650 if (db
->alternates
) {
651 gitlck_unlock(&db
->lock
);
655 db
->alternates
= git__malloc(sizeof(*db
->alternates
) * (n
+ 1));
656 if (!db
->alternates
) {
657 gitlck_unlock(&db
->lock
);
661 db
->alternates
[n
] = NULL
;
662 db
->n_alternates
= n
;
663 gitlck_unlock(&db
->lock
);
667 static int pack_openidx_map(git_pack
*p
)
669 char pb
[GIT_PATH_MAX
];
672 if (git__fmt(pb
, sizeof(pb
), "%s/pack/%s.idx",
677 if ((p
->idx_fd
= gitfo_open(pb
, O_RDONLY
)) < 0)
680 if ((len
= gitfo_size(p
->idx_fd
)) < 0
681 || !git__is_sizet(len
)
682 || gitfo_map_ro(&p
->idx_map
, p
->idx_fd
, 0, (size_t)len
)) {
683 gitfo_close(p
->idx_fd
);
695 static int cmp_offset_idx_info(const void *lhs
, const void *rhs
)
697 const offset_idx_info
*a
= lhs
;
698 const offset_idx_info
*b
= rhs
;
699 return (a
->offset
< b
->offset
) ? -1 : (a
->offset
> b
->offset
) ? 1 : 0;
702 static int make_offset_index(git_pack
*p
, offset_idx_info
*data
)
704 off_t min_off
= 3 * 4, max_off
= p
->pack_size
- GIT_OID_RAWSZ
;
705 uint32_t *idx
, *next
;
708 qsort(data
, p
->obj_cnt
, sizeof(*data
), cmp_offset_idx_info
);
710 if (data
[0].offset
< min_off
|| data
[p
->obj_cnt
].offset
> max_off
)
713 if ((idx
= git__malloc(sizeof(*idx
) * (p
->obj_cnt
+1))) == NULL
)
715 if ((next
= git__malloc(sizeof(*next
) * p
->obj_cnt
)) == NULL
) {
720 for (j
= 0; j
< p
->obj_cnt
+1; j
++)
723 for (j
= 0; j
< p
->obj_cnt
; j
++) {
724 assert(idx
[j
] < p
->obj_cnt
);
725 assert(idx
[j
+1] < p
->obj_cnt
+1);
727 next
[idx
[j
]] = idx
[j
+1];
731 p
->im_off_next
= next
;
735 static int idxv1_search(uint32_t *out
, git_pack
*p
, const git_oid
*id
)
737 unsigned char *data
= p
->im_oid
;
738 uint32_t lo
= id
->id
[0] ? p
->im_fanout
[id
->id
[0] - 1] : 0;
739 uint32_t hi
= p
->im_fanout
[id
->id
[0]];
742 uint32_t mid
= (lo
+ hi
) >> 1;
743 uint32_t pos
= 24 * mid
;
744 int cmp
= memcmp(id
->id
, data
+ pos
+ 4, 20);
753 return GIT_ENOTFOUND
;
756 static int idxv1_search_offset(uint32_t *out
, git_pack
*p
, off_t offset
)
758 if (offset
> 0 && offset
< (p
->pack_size
- GIT_OID_RAWSZ
)) {
759 uint32_t lo
= 0, hi
= p
->obj_cnt
+1;
760 unsigned char *data
= p
->im_oid
;
761 uint32_t *idx
= p
->im_off_idx
;
763 uint32_t mid
= (lo
+ hi
) >> 1;
764 uint32_t n
= idx
[mid
];
765 uint32_t pos
= n
* (GIT_OID_RAWSZ
+ 4);
766 off_t here
= decode32(data
+ pos
);
769 else if (offset
== here
) {
776 return GIT_ENOTFOUND
;
779 static int idxv1_get(index_entry
*e
, git_pack
*p
, uint32_t n
)
781 unsigned char *data
= p
->im_oid
;
782 uint32_t *next
= p
->im_off_next
;
784 if (n
< p
->obj_cnt
) {
785 uint32_t pos
= n
* (GIT_OID_RAWSZ
+ 4);
786 off_t next_off
= p
->pack_size
- GIT_OID_RAWSZ
;
788 e
->oid
= data
+ pos
+ 4;
789 e
->offset
= decode32(data
+ pos
);
790 if (next
[n
] < p
->obj_cnt
) {
791 pos
= next
[n
] * (GIT_OID_RAWSZ
+ 4);
792 next_off
= decode32(data
+ pos
);
794 e
->size
= next_off
- e
->offset
;
797 return GIT_ENOTFOUND
;
800 static int pack_openidx_v1(git_pack
*p
)
802 uint32_t *src_fanout
= p
->idx_map
.data
;
804 offset_idx_info
*info
;
809 if ((im_fanout
= git__malloc(sizeof(*im_fanout
) * 256)) == NULL
)
812 im_fanout
[0] = decode32(&src_fanout
[0]);
813 for (j
= 1; j
< 256; j
++) {
814 im_fanout
[j
] = decode32(&src_fanout
[j
]);
815 if (im_fanout
[j
] < im_fanout
[j
- 1]) {
820 p
->obj_cnt
= im_fanout
[255];
822 expsz
= 4 * 256 + 24 * p
->obj_cnt
+ 2 * 20;
823 if (expsz
!= p
->idx_map
.len
) {
828 p
->idx_search
= idxv1_search
;
829 p
->idx_search_offset
= idxv1_search_offset
;
830 p
->idx_get
= idxv1_get
;
831 p
->im_fanout
= im_fanout
;
832 p
->im_oid
= (unsigned char *)(src_fanout
+ 256);
834 if ((info
= git__malloc(sizeof(*info
) * (p
->obj_cnt
+1))) == NULL
) {
839 for (j
= 0; j
< p
->obj_cnt
; j
++) {
840 uint32_t pos
= j
* (GIT_OID_RAWSZ
+ 4);
841 info
[j
].offset
= decode32(p
->im_oid
+ pos
);
844 info
[p
->obj_cnt
].offset
= p
->pack_size
- GIT_OID_RAWSZ
;
845 info
[p
->obj_cnt
].n
= p
->obj_cnt
;
847 if (make_offset_index(p
, info
)) {
857 static int idxv2_search(uint32_t *out
, git_pack
*p
, const git_oid
*id
)
859 unsigned char *data
= p
->im_oid
;
860 uint32_t lo
= id
->id
[0] ? p
->im_fanout
[id
->id
[0] - 1] : 0;
861 uint32_t hi
= p
->im_fanout
[id
->id
[0]];
864 uint32_t mid
= (lo
+ hi
) >> 1;
865 uint32_t pos
= 20 * mid
;
866 int cmp
= memcmp(id
->id
, data
+ pos
, 20);
875 return GIT_ENOTFOUND
;
878 static int idxv2_search_offset(uint32_t *out
, git_pack
*p
, off_t offset
)
880 if (offset
> 0 && offset
< (p
->pack_size
- GIT_OID_RAWSZ
)) {
881 uint32_t lo
= 0, hi
= p
->obj_cnt
+1;
882 uint32_t *idx
= p
->im_off_idx
;
884 uint32_t mid
= (lo
+ hi
) >> 1;
885 uint32_t n
= idx
[mid
];
886 uint32_t o32
= decode32(p
->im_offset32
+ n
);
889 if (o32
& 0x80000000) {
890 uint32_t o64_idx
= (o32
& ~0x80000000);
891 here
= decode64(p
->im_offset64
+ 2*o64_idx
);
896 else if (offset
== here
) {
903 return GIT_ENOTFOUND
;
906 static int idxv2_get(index_entry
*e
, git_pack
*p
, uint32_t n
)
908 unsigned char *data
= p
->im_oid
;
909 uint32_t *next
= p
->im_off_next
;
911 if (n
< p
->obj_cnt
) {
912 uint32_t o32
= decode32(p
->im_offset32
+ n
);
913 off_t next_off
= p
->pack_size
- GIT_OID_RAWSZ
;
915 e
->oid
= data
+ n
* GIT_OID_RAWSZ
;
917 if (o32
& 0x80000000) {
918 uint32_t o64_idx
= (o32
& ~0x80000000);
919 e
->offset
= decode64(p
->im_offset64
+ 2*o64_idx
);
921 if (next
[n
] < p
->obj_cnt
) {
922 o32
= decode32(p
->im_offset32
+ next
[n
]);
924 if (o32
& 0x80000000) {
925 uint32_t o64_idx
= (o32
& ~0x80000000);
926 next_off
= decode64(p
->im_offset64
+ 2*o64_idx
);
929 e
->size
= next_off
- e
->offset
;
932 return GIT_ENOTFOUND
;
935 static int pack_openidx_v2(git_pack
*p
)
937 unsigned char *data
= p
->idx_map
.data
;
938 uint32_t *src_fanout
= (uint32_t *)(data
+ 8);
940 offset_idx_info
*info
;
941 size_t sz
, o64_sz
, o64_len
;
944 if ((im_fanout
= git__malloc(sizeof(*im_fanout
) * 256)) == NULL
)
947 im_fanout
[0] = decode32(&src_fanout
[0]);
948 for (j
= 1; j
< 256; j
++) {
949 im_fanout
[j
] = decode32(&src_fanout
[j
]);
950 if (im_fanout
[j
] < im_fanout
[j
- 1]) {
955 p
->obj_cnt
= im_fanout
[255];
957 /* minimum size of .idx file (with empty 64-bit offsets table): */
958 sz
= 4 + 4 + 256 * 4 + p
->obj_cnt
* (20 + 4 + 4) + 2 * 20;
959 if (p
->idx_map
.len
< sz
) {
964 p
->idx_search
= idxv2_search
;
965 p
->idx_search_offset
= idxv2_search_offset
;
966 p
->idx_get
= idxv2_get
;
967 p
->im_fanout
= im_fanout
;
968 p
->im_oid
= (unsigned char *)(src_fanout
+ 256);
969 p
->im_crc
= (uint32_t *)(p
->im_oid
+ 20 * p
->obj_cnt
);
970 p
->im_offset32
= p
->im_crc
+ p
->obj_cnt
;
971 p
->im_offset64
= p
->im_offset32
+ p
->obj_cnt
;
973 if ((info
= git__malloc(sizeof(*info
) * (p
->obj_cnt
+1))) == NULL
) {
978 /* check 64-bit offset table index values are within bounds */
979 o64_sz
= p
->idx_map
.len
- sz
;
980 o64_len
= o64_sz
/ 8;
981 for (j
= 0; j
< p
->obj_cnt
; j
++) {
982 uint32_t o32
= decode32(p
->im_offset32
+ j
);
984 if (o32
& 0x80000000) {
985 uint32_t o64_idx
= (o32
& ~0x80000000);
986 if (o64_idx
>= o64_len
) {
991 offset
= decode64(p
->im_offset64
+ 2*o64_idx
);
993 info
[j
].offset
= offset
;
996 info
[p
->obj_cnt
].offset
= p
->pack_size
- GIT_OID_RAWSZ
;
997 info
[p
->obj_cnt
].n
= p
->obj_cnt
;
999 if (make_offset_index(p
, info
)) {
1009 static int pack_stat(git_pack
*p
)
1011 char pb
[GIT_PATH_MAX
];
1014 if (git__fmt(pb
, sizeof(pb
), "%s/pack/%s.pack",
1019 if (stat(pb
, &sb
) || !S_ISREG(sb
.st_mode
))
1022 if (sb
.st_size
< (3 * 4 + GIT_OID_RAWSZ
))
1025 p
->pack_size
= sb
.st_size
;
1026 p
->pack_mtime
= sb
.st_mtime
;
1031 static int pack_openidx(git_pack
*p
)
1033 gitlck_lock(&p
->lock
);
1036 gitlck_unlock(&p
->lock
);
1040 if (++p
->idxcnt
== 1 && !p
->idx_search
) {
1041 int status
, version
;
1044 if (pack_stat(p
) || pack_openidx_map(p
)) {
1047 gitlck_unlock(&p
->lock
);
1050 data
= p
->idx_map
.data
;
1051 status
= GIT_SUCCESS
;
1054 if (decode32(&data
[0]) == PACK_TOC
)
1055 version
= decode32(&data
[1]);
1059 status
= pack_openidx_v1(p
);
1062 status
= pack_openidx_v2(p
);
1068 if (status
!= GIT_SUCCESS
) {
1069 gitfo_free_map(&p
->idx_map
);
1072 gitlck_unlock(&p
->lock
);
1077 gitlck_unlock(&p
->lock
);
1081 static void pack_decidx(git_pack
*p
)
1083 gitlck_lock(&p
->lock
);
1085 gitlck_unlock(&p
->lock
);
1088 static void pack_dec(git_pack
*p
)
1092 gitlck_lock(&p
->lock
);
1093 need_free
= !--p
->refcnt
;
1094 gitlck_unlock(&p
->lock
);
1097 if (p
->idx_search
) {
1098 gitfo_free_map(&p
->idx_map
);
1099 gitfo_close(p
->idx_fd
);
1103 gitlck_free(&p
->lock
);
1108 static void packlist_dec(git_odb
*db
, git_packlist
*pl
)
1114 gitlck_lock(&db
->lock
);
1115 need_free
= !--pl
->refcnt
;
1116 gitlck_unlock(&db
->lock
);
1120 for (j
= 0; j
< pl
->n_packs
; j
++)
1121 pack_dec(pl
->packs
[j
]);
1126 static git_pack
*alloc_pack(const char *pack_name
)
1128 git_pack
*p
= git__calloc(1, sizeof(*p
));
1132 gitlck_init(&p
->lock
);
1133 strcpy(p
->pack_name
, pack_name
);
1138 struct scanned_pack
{
1139 struct scanned_pack
*next
;
1143 static int scan_one_pack(void *state
, char *name
)
1145 struct scanned_pack
**ret
= state
, *r
;
1146 char *s
= strrchr(name
, '/'), *d
;
1148 if (git__prefixcmp(s
+ 1, "pack-")
1149 || git__suffixcmp(s
, ".pack")
1150 || strlen(s
+ 1) != GIT_PACK_NAME_MAX
+ 4)
1153 d
= strrchr(s
+ 1, '.');
1154 strcpy(d
+ 1, "idx"); /* "pack-abc.pack" -> "pack-abc.idx" */
1155 if (gitfo_exists(name
))
1158 if ((r
= git__malloc(sizeof(*r
))) == NULL
)
1161 *d
= '\0'; /* "pack-abc.pack" -_> "pack-abc" */
1162 if ((r
->pack
= alloc_pack(s
+ 1)) == NULL
) {
1172 static git_packlist
*scan_packs(git_odb
*db
)
1174 char pb
[GIT_PATH_MAX
];
1175 struct scanned_pack
*state
= NULL
, *c
;
1177 git_packlist
*new_list
;
1179 if (git__fmt(pb
, sizeof(pb
), "%s/pack", db
->objects_dir
) < 0)
1181 gitfo_dirent(pb
, sizeof(pb
), scan_one_pack
, &state
);
1183 /* TODO - merge old entries into the new array */
1184 for (cnt
= 0, c
= state
; c
; c
= c
->next
)
1186 new_list
= git__malloc(sizeof(*new_list
)
1187 + (sizeof(new_list
->packs
[0]) * cnt
));
1191 for (cnt
= 0, c
= state
; c
; ) {
1192 struct scanned_pack
*n
= c
->next
;
1194 new_list
->packs
[cnt
++] = c
->pack
;
1198 new_list
->n_packs
= cnt
;
1199 new_list
->refcnt
= 2;
1200 db
->packlist
= new_list
;
1205 struct scanned_pack
*n
= state
->next
;
1206 pack_dec(state
->pack
);
1213 static git_packlist
*packlist_get(git_odb
*db
)
1217 gitlck_lock(&db
->lock
);
1218 if ((pl
= db
->packlist
) != NULL
)
1221 pl
= scan_packs(db
);
1222 gitlck_unlock(&db
->lock
);
1226 static int search_packs(git_pack
**p
, uint32_t *n
, git_odb
*db
, const git_oid
*id
)
1228 git_packlist
*pl
= packlist_get(db
);
1232 return GIT_ENOTFOUND
;
1234 for (j
= 0; j
< pl
->n_packs
; j
++) {
1236 git_pack
*pack
= pl
->packs
[j
];
1240 if (pack_openidx(pack
))
1242 res
= pack
->idx_search(&pos
, pack
, id
);
1246 packlist_dec(db
, pl
);
1256 packlist_dec(db
, pl
);
1257 return GIT_ENOTFOUND
;
1260 static int exists_packed(git_odb
*db
, const git_oid
*id
)
1262 return !search_packs(NULL
, NULL
, db
, id
);
1265 static int exists_loose(git_odb
*db
, const git_oid
*id
)
1267 char file
[GIT_PATH_MAX
];
1269 if (object_file_name(file
, sizeof(file
), db
->objects_dir
, id
))
1272 if (gitfo_exists(file
) < 0)
1278 int git_odb_exists(git_odb
*db
, const git_oid
*id
)
1280 /* TODO: extend to search alternate db's */
1281 if (exists_packed(db
, id
))
1283 return exists_loose(db
, id
);
1286 int git_odb_open(git_odb
**out
, const char *objects_dir
)
1288 git_odb
*db
= git__calloc(1, sizeof(*db
));
1292 db
->objects_dir
= git__strdup(objects_dir
);
1293 if (!db
->objects_dir
) {
1298 gitlck_init(&db
->lock
);
1300 db
->object_zlib_level
= Z_BEST_SPEED
;
1301 db
->fsync_object_files
= 0;
1307 void git_odb_close(git_odb
*db
)
1314 gitlck_lock(&db
->lock
);
1317 db
->packlist
= NULL
;
1319 if (db
->alternates
) {
1321 for (alt
= db
->alternates
; *alt
; alt
++)
1322 git_odb_close(*alt
);
1323 free(db
->alternates
);
1326 free(db
->objects_dir
);
1328 gitlck_unlock(&db
->lock
);
1330 packlist_dec(db
, pl
);
1331 gitlck_free(&db
->lock
);
1341 if (!git_odb__read_packed(out
, db
, id
))
1343 if (!git_odb__read_loose(out
, db
, id
))
1345 if (!open_alternates(db
))
1349 return GIT_ENOTFOUND
;
1352 int git_odb__read_loose(git_obj
*out
, git_odb
*db
, const git_oid
*id
)
1354 char file
[GIT_PATH_MAX
];
1355 gitfo_buf obj
= GITFO_BUF_INIT
;
1357 assert(out
&& db
&& id
);
1361 out
->type
= GIT_OBJ_BAD
;
1363 if (object_file_name(file
, sizeof(file
), db
->objects_dir
, id
))
1364 return GIT_ENOTFOUND
; /* TODO: error handling */
1366 if (gitfo_read_file(&obj
, file
))
1367 return GIT_ENOTFOUND
; /* TODO: error handling */
1369 if (inflate_disk_obj(out
, &obj
)) {
1370 gitfo_free_buf(&obj
);
1371 return GIT_ENOTFOUND
; /* TODO: error handling */
1374 gitfo_free_buf(&obj
);
1379 static int read_packed(git_obj
*out
, git_pack
*p
, const git_oid
*id
)
1384 assert(out
&& p
&& id
);
1386 if (pack_openidx(p
))
1388 res
= p
->idx_search(&n
, p
, id
);
1392 /* TODO unpack object */
1399 int git_odb__read_packed(git_obj
*out
, git_odb
*db
, const git_oid
*id
)
1401 git_packlist
*pl
= packlist_get(db
);
1404 assert(out
&& db
&& id
);
1408 out
->type
= GIT_OBJ_BAD
;
1411 return GIT_ENOTFOUND
;
1413 for (j
= 0; j
< pl
->n_packs
; j
++) {
1414 if (!read_packed(out
, pl
->packs
[j
], id
)) {
1415 packlist_dec(db
, pl
);
1420 packlist_dec(db
, pl
);
1421 return GIT_ENOTFOUND
;
1424 int git_odb_write(git_oid
*id
, git_odb
*db
, git_obj
*obj
)
1428 gitfo_buf buf
= GITFO_BUF_INIT
;
1430 assert(id
&& db
&& obj
);
1432 if (hash_obj(id
, hdr
, sizeof(hdr
), &hdrlen
, obj
) < 0)
1435 if (git_odb_exists(db
, id
))
1438 if (deflate_obj(&buf
, hdr
, hdrlen
, obj
, db
->object_zlib_level
) < 0)
1441 if (write_obj(&buf
, id
, db
) < 0) {
1442 gitfo_free_buf(&buf
);
1446 gitfo_free_buf(&buf
);