1670
return -1;
1671
}
1672
1673
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
1673
+/*
1674
+ * Map the loose object at "path" if it is not NULL, or the path found by
1675
+ * searching for a loose object named "sha1".
1676
+ */
1677
+static void *map_sha1_file_1(const char *path,
1678
+ const unsigned char *sha1,
1679
+ unsigned long *size)
1680
{
1675
- const char *path;
1681
void *map;
1682
int fd;
1683
1679
- fd = open_sha1_file(sha1, &path);
1684
+ if (path)
1685
+ fd = git_open(path);
1686
+ else
1687
+ fd = open_sha1_file(sha1, &path);
1688
map = NULL;
1689
if (fd >= 0) {
1690
struct stat st;
1703
return map;
1704
}
1705
1706
+void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
1707
+{
1708
+ return map_sha1_file_1(NULL, sha1, size);
1709
+}
1710
+
1711
unsigned long unpack_object_header_buffer(const unsigned char *buf,
1712
unsigned long len, enum object_type *type, unsigned long *sizep)
1713
{
3805
}
3806
return r ? r : pack_errors;
3807
}
3808
+
3809
+static int check_stream_sha1(git_zstream *stream,
3810
+ const char *hdr,
3811
+ unsigned long size,
3812
+ const char *path,
3813
+ const unsigned char *expected_sha1)
3814
+{
3815
+ git_SHA_CTX c;
3816
+ unsigned char real_sha1[GIT_SHA1_RAWSZ];
3817
+ unsigned char buf[4096];
3818
+ unsigned long total_read;
3819
+ int status = Z_OK;
3820
+
3821
+ git_SHA1_Init(&c);
3822
+ git_SHA1_Update(&c, hdr, stream->total_out);
3823
+
3824
+ /*
3825
+ * We already read some bytes into hdr, but the ones up to the NUL
3826
+ * do not count against the object's content size.
3827
+ */
3828
+ total_read = stream->total_out - strlen(hdr) - 1;
3829
+
3830
+ /*
3831
+ * This size comparison must be "<=" to read the final zlib packets;
3832
+ * see the comment in unpack_sha1_rest for details.
3833
+ */
3834
+ while (total_read <= size &&
3835
+ (status == Z_OK || status == Z_BUF_ERROR)) {
3836
+ stream->next_out = buf;
3837
+ stream->avail_out = sizeof(buf);
3838
+ if (size - total_read < stream->avail_out)
3839
+ stream->avail_out = size - total_read;
3840
+ status = git_inflate(stream, Z_FINISH);
3841
+ git_SHA1_Update(&c, buf, stream->next_out - buf);
3842
+ total_read += stream->next_out - buf;
3843
+ }
3844
+ git_inflate_end(stream);
3845
+
3846
+ if (status != Z_STREAM_END) {
3847
+ error("corrupt loose object '%s'", sha1_to_hex(expected_sha1));
3848
+ return -1;
3849
+ }
3850
+
3851
+ git_SHA1_Final(real_sha1, &c);
3852
+ if (hashcmp(expected_sha1, real_sha1)) {
3853
+ error("sha1 mismatch for %s (expected %s)", path,
3854
+ sha1_to_hex(expected_sha1));
3855
+ return -1;
3856
+ }
3857
+
3858
+ return 0;
3859
+}
3860
+
3861
+int read_loose_object(const char *path,
3862
+ const unsigned char *expected_sha1,
3863
+ enum object_type *type,
3864
+ unsigned long *size,
3865
+ void **contents)
3866
+{
3867
+ int ret = -1;
3868
+ int fd = -1;
3869
+ void *map = NULL;
3870
+ unsigned long mapsize;
3871
+ git_zstream stream;
3872
+ char hdr[32];
3873
+
3874
+ *contents = NULL;
3875
+
3876
+ map = map_sha1_file_1(path, NULL, &mapsize);
3877
+ if (!map) {
3878
+ error_errno("unable to mmap %s", path);
3879
+ goto out;
3880
+ }
3881
+
3882
+ if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
3883
+ error("unable to unpack header of %s", path);
3884
+ goto out;
3885
+ }
3886
+
3887
+ *type = parse_sha1_header(hdr, size);
3888
+ if (*type < 0) {
3889
+ error("unable to parse header of %s", path);
3890
+ git_inflate_end(&stream);
3891
+ goto out;
3892
+ }
3893
+
3894
+ if (*type == OBJ_BLOB) {
3895
+ if (check_stream_sha1(&stream, hdr, *size, path, expected_sha1) < 0)
3896
+ goto out;
3897
+ } else {
3898
+ *contents = unpack_sha1_rest(&stream, hdr, *size, expected_sha1);
3899
+ if (!*contents) {
3900
+ error("unable to unpack contents of %s", path);
3901
+ git_inflate_end(&stream);
3902
+ goto out;
3903
+ }
3904
+ if (check_sha1_signature(expected_sha1, *contents,
3905
+ *size, typename(*type))) {
3906
+ error("sha1 mismatch for %s (expected %s)", path,
3907
+ sha1_to_hex(expected_sha1));
3908
+ free(*contents);
3909
+ goto out;
3910
+ }
3911
+ }
3912
+
3913
+ ret = 0; /* everything checks out */
3914
+
3915
+out:
3916
+ if (map)
3917
+ munmap(map, mapsize);
3918
+ if (fd >= 0)
3919
+ close(fd);
3920
+ return ret;
3921
+}