Browse Source

parse_object: avoid putting whole blob in core

Traditionally, all the callers of check_sha1_signature() first
called read_sha1_file() to prepare the whole object data in core,
and called this function.  The function is used to revalidate what
we read from the object database actually matches the object name we
used to ask for the data from the object database.

Update the API to allow callers to pass NULL as the object data, and
have the function read and hash the object data using streaming API
to recompute the object name, without having to hold everything in
core at the same time.  This is most useful in parse_object() that
parses a blob object, because this caller does not have to keep the
actual blob data around in memory after a "struct blob" is returned.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Nguyễn Thái Ngọc Duy 13 years ago committed by Junio C Hamano
parent
commit
090ea12671
  1. 11
      object.c
  2. 42
      sha1_file.c

11
object.c

@ -198,6 +198,17 @@ struct object *parse_object(const unsigned char *sha1) @@ -198,6 +198,17 @@ struct object *parse_object(const unsigned char *sha1)
if (obj && obj->parsed)
return obj;

if ((obj && obj->type == OBJ_BLOB) ||
(!obj && has_sha1_file(sha1) &&
sha1_object_info(sha1, NULL) == OBJ_BLOB)) {
if (check_sha1_signature(repl, NULL, 0, NULL) < 0) {
error("sha1 mismatch %s\n", sha1_to_hex(repl));
return NULL;
}
parse_blob_buffer(lookup_blob(sha1), NULL, 0);
return lookup_object(sha1);
}

buffer = read_sha1_file(sha1, &type, &size);
if (buffer) {
if (check_sha1_signature(repl, buffer, size, typename(type)) < 0) {

42
sha1_file.c

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
#include "pack-revindex.h"
#include "sha1-lookup.h"
#include "bulk-checkin.h"
#include "streaming.h"

#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@ -1146,10 +1147,47 @@ static const struct packed_git *has_packed_and_bad(const unsigned char *sha1) @@ -1146,10 +1147,47 @@ static const struct packed_git *has_packed_and_bad(const unsigned char *sha1)
return NULL;
}

int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
/*
* With an in-core object data in "map", rehash it to make sure the
* object name actually matches "sha1" to detect object corruption.
* With "map" == NULL, try reading the object named with "sha1" using
* the streaming interface and rehash it to do the same.
*/
int check_sha1_signature(const unsigned char *sha1, void *map,
unsigned long size, const char *type)
{
unsigned char real_sha1[20];
hash_sha1_file(map, size, type, real_sha1);
enum object_type obj_type;
struct git_istream *st;
git_SHA_CTX c;
char hdr[32];
int hdrlen;

if (map) {
hash_sha1_file(map, size, type, real_sha1);
return hashcmp(sha1, real_sha1) ? -1 : 0;
}

st = open_istream(sha1, &obj_type, &size, NULL);
if (!st)
return -1;

/* Generate the header */
hdrlen = sprintf(hdr, "%s %lu", typename(obj_type), size) + 1;

/* Sha1.. */
git_SHA1_Init(&c);
git_SHA1_Update(&c, hdr, hdrlen);
for (;;) {
char buf[1024 * 16];
ssize_t readlen = read_istream(st, buf, sizeof(buf));

if (!readlen)
break;
git_SHA1_Update(&c, buf, readlen);
}
git_SHA1_Final(real_sha1, &c);
close_istream(st);
return hashcmp(sha1, real_sha1) ? -1 : 0;
}


Loading…
Cancel
Save