2005-06-27 05:27:56 +02:00
|
|
|
/*
|
|
|
|
* csum-file.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005 Linus Torvalds
|
|
|
|
*
|
|
|
|
* Simple file write infrastructure for writing SHA1-summed
|
|
|
|
* files. Useful when you write a file that you want to be
|
|
|
|
* able to verify hasn't been messed with afterwards.
|
|
|
|
*/
|
|
|
|
#include "cache.h"
|
2007-10-30 22:06:21 +01:00
|
|
|
#include "progress.h"
|
2005-06-27 05:27:56 +02:00
|
|
|
#include "csum-file.h"
|
|
|
|
|
2011-02-03 02:29:01 +01:00
|
|
|
static void flush(struct sha1file *f, void *buf, unsigned int count)
|
2005-06-27 05:27:56 +02:00
|
|
|
{
|
2011-02-03 02:29:01 +01:00
|
|
|
if (0 <= f->check_fd && count) {
|
|
|
|
unsigned char check_buffer[8192];
|
|
|
|
ssize_t ret = read_in_full(f->check_fd, check_buffer, count);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
die_errno("%s: sha1 file read error", f->name);
|
|
|
|
if (ret < count)
|
|
|
|
die("%s: sha1 file truncated", f->name);
|
|
|
|
if (memcmp(buf, check_buffer, count))
|
|
|
|
die("sha1 file '%s' validation error", f->name);
|
|
|
|
}
|
|
|
|
|
2005-06-27 05:27:56 +02:00
|
|
|
for (;;) {
|
2005-12-20 01:18:28 +01:00
|
|
|
int ret = xwrite(f->fd, buf, count);
|
2005-06-27 05:27:56 +02:00
|
|
|
if (ret > 0) {
|
2007-11-05 04:15:41 +01:00
|
|
|
f->total += ret;
|
|
|
|
display_throughput(f->tp, f->total);
|
2006-06-18 17:18:09 +02:00
|
|
|
buf = (char *) buf + ret;
|
2005-06-27 05:27:56 +02:00
|
|
|
count -= ret;
|
|
|
|
if (count)
|
|
|
|
continue;
|
2006-08-14 22:32:01 +02:00
|
|
|
return;
|
2005-06-27 05:27:56 +02:00
|
|
|
}
|
|
|
|
if (!ret)
|
2005-06-27 07:01:46 +02:00
|
|
|
die("sha1 file '%s' write error. Out of diskspace", f->name);
|
2009-06-27 17:58:46 +02:00
|
|
|
die_errno("sha1 file '%s' write error", f->name);
|
2005-06-27 05:27:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 04:08:51 +02:00
|
|
|
void sha1flush(struct sha1file *f)
|
2005-06-27 05:27:56 +02:00
|
|
|
{
|
|
|
|
unsigned offset = f->offset;
|
2008-05-30 17:42:16 +02:00
|
|
|
|
2005-06-27 05:27:56 +02:00
|
|
|
if (offset) {
|
2008-10-01 20:05:20 +02:00
|
|
|
git_SHA1_Update(&f->ctx, f->buffer, offset);
|
2008-10-10 17:39:20 +02:00
|
|
|
flush(f, f->buffer, offset);
|
2007-05-13 20:28:19 +02:00
|
|
|
f->offset = 0;
|
2005-06-27 05:27:56 +02:00
|
|
|
}
|
2008-10-10 04:08:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
sha1flush(f);
|
2008-10-01 20:05:20 +02:00
|
|
|
git_SHA1_Final(f->buffer, &f->ctx);
|
2008-08-29 22:08:00 +02:00
|
|
|
if (result)
|
|
|
|
hashcpy(result, f->buffer);
|
2008-05-30 17:42:16 +02:00
|
|
|
if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
|
2007-10-17 03:55:48 +02:00
|
|
|
/* write checksum and close fd */
|
2008-10-10 17:39:20 +02:00
|
|
|
flush(f, f->buffer, 20);
|
2008-05-30 17:42:16 +02:00
|
|
|
if (flags & CSUM_FSYNC)
|
|
|
|
fsync_or_die(f->fd, f->name);
|
2007-10-17 03:55:48 +02:00
|
|
|
if (close(f->fd))
|
2009-06-27 17:58:46 +02:00
|
|
|
die_errno("%s: sha1 file error on close", f->name);
|
2007-10-17 03:55:48 +02:00
|
|
|
fd = 0;
|
|
|
|
} else
|
|
|
|
fd = f->fd;
|
2011-02-03 02:29:01 +01:00
|
|
|
if (0 <= f->check_fd) {
|
|
|
|
char discard;
|
|
|
|
int cnt = read_in_full(f->check_fd, &discard, 1);
|
|
|
|
if (cnt < 0)
|
|
|
|
die_errno("%s: error when reading the tail of sha1 file",
|
|
|
|
f->name);
|
|
|
|
if (cnt)
|
|
|
|
die("%s: sha1 file has trailing garbage", f->name);
|
|
|
|
if (close(f->check_fd))
|
|
|
|
die_errno("%s: sha1 file error on close", f->name);
|
|
|
|
}
|
2005-08-08 20:46:13 +02:00
|
|
|
free(f);
|
2007-10-17 03:55:48 +02:00
|
|
|
return fd;
|
2005-06-27 05:27:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int sha1write(struct sha1file *f, void *buf, unsigned int count)
|
|
|
|
{
|
|
|
|
while (count) {
|
|
|
|
unsigned offset = f->offset;
|
|
|
|
unsigned left = sizeof(f->buffer) - offset;
|
|
|
|
unsigned nr = count > left ? left : count;
|
2008-09-02 16:22:20 +02:00
|
|
|
void *data;
|
|
|
|
|
|
|
|
if (f->do_crc)
|
|
|
|
f->crc32 = crc32(f->crc32, buf, nr);
|
|
|
|
|
|
|
|
if (nr == sizeof(f->buffer)) {
|
|
|
|
/* process full buffer directly without copy */
|
|
|
|
data = buf;
|
|
|
|
} else {
|
|
|
|
memcpy(f->buffer + offset, buf, nr);
|
|
|
|
data = f->buffer;
|
|
|
|
}
|
2005-06-27 05:27:56 +02:00
|
|
|
|
|
|
|
count -= nr;
|
|
|
|
offset += nr;
|
2006-06-18 17:18:09 +02:00
|
|
|
buf = (char *) buf + nr;
|
2005-06-27 05:27:56 +02:00
|
|
|
left -= nr;
|
|
|
|
if (!left) {
|
2008-10-01 20:05:20 +02:00
|
|
|
git_SHA1_Update(&f->ctx, data, offset);
|
2008-10-10 17:39:20 +02:00
|
|
|
flush(f, data, offset);
|
2005-06-27 05:27:56 +02:00
|
|
|
offset = 0;
|
|
|
|
}
|
|
|
|
f->offset = offset;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-28 20:10:06 +02:00
|
|
|
struct sha1file *sha1fd(int fd, const char *name)
|
2007-10-30 22:06:21 +01:00
|
|
|
{
|
|
|
|
return sha1fd_throughput(fd, name, NULL);
|
|
|
|
}
|
|
|
|
|
2011-02-03 02:29:01 +01:00
|
|
|
struct sha1file *sha1fd_check(const char *name)
|
|
|
|
{
|
|
|
|
int sink, check;
|
|
|
|
struct sha1file *f;
|
|
|
|
|
|
|
|
sink = open("/dev/null", O_WRONLY);
|
|
|
|
if (sink < 0)
|
|
|
|
return NULL;
|
|
|
|
check = open(name, O_RDONLY);
|
|
|
|
if (check < 0) {
|
|
|
|
int saved_errno = errno;
|
|
|
|
close(sink);
|
|
|
|
errno = saved_errno;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
f = sha1fd(sink, name);
|
|
|
|
f->check_fd = check;
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2007-10-30 22:06:21 +01:00
|
|
|
struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
|
2005-06-28 20:10:06 +02:00
|
|
|
{
|
2007-11-05 04:54:50 +01:00
|
|
|
struct sha1file *f = xmalloc(sizeof(*f));
|
2005-06-28 20:10:06 +02:00
|
|
|
f->fd = fd;
|
2011-02-03 02:29:01 +01:00
|
|
|
f->check_fd = -1;
|
2005-06-28 20:10:06 +02:00
|
|
|
f->offset = 0;
|
2007-11-05 04:15:41 +01:00
|
|
|
f->total = 0;
|
2007-10-30 22:06:21 +01:00
|
|
|
f->tp = tp;
|
2007-11-05 04:54:50 +01:00
|
|
|
f->name = name;
|
compute a CRC32 for each object as stored in a pack
The most important optimization for performance when repacking is the
ability to reuse data from a previous pack as is and bypass any delta
or even SHA1 computation by simply copying the raw data from one pack
to another directly.
The problem with this is that any data corruption within a copied object
would go unnoticed and the new (repacked) pack would be self-consistent
with its own checksum despite containing a corrupted object. This is a
real issue that already happened at least once in the past.
In some attempt to prevent this, we validate the copied data by inflating
it and making sure no error is signaled by zlib. But this is still not
perfect as a significant portion of a pack content is made of object
headers and references to delta base objects which are not deflated and
therefore not validated when repacking actually making the pack data reuse
still not as safe as it could be.
Of course a full SHA1 validation could be performed, but that implies
full data inflating and delta replaying which is extremely costly, which
cost the data reuse optimization was designed to avoid in the first place.
So the best solution to this is simply to store a CRC32 of the raw pack
data for each object in the pack index. This way any object in a pack can
be validated before being copied as is in another pack, including header
and any other non deflated data.
Why CRC32 instead of a faster checksum like Adler32? Quoting Wikipedia:
Jonathan Stone discovered in 2001 that Adler-32 has a weakness for very
short messages. He wrote "Briefly, the problem is that, for very short
packets, Adler32 is guaranteed to give poor coverage of the available
bits. Don't take my word for it, ask Mark Adler. :-)" The problem is
that sum A does not wrap for short messages. The maximum value of A for
a 128-byte message is 32640, which is below the value 65521 used by the
modulo operation. An extended explanation can be found in RFC 3309,
which mandates the use of CRC32 instead of Adler-32 for SCTP, the
Stream Control Transmission Protocol.
In the context of a GIT pack, we have lots of small objects, especially
deltas, which are likely to be quite small and in a size range for which
Adler32 is dimed not to be sufficient. Another advantage of CRC32 is the
possibility for recovery from certain types of small corruptions like
single bit errors which are the most probable type of corruptions.
OK what this patch does is to compute the CRC32 of each object written to
a pack within pack-objects. It is not written to the index yet and it is
obviously not validated when reusing pack data yet either.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-09 07:06:31 +02:00
|
|
|
f->do_crc = 0;
|
2008-10-01 20:05:20 +02:00
|
|
|
git_SHA1_Init(&f->ctx);
|
2005-06-28 20:10:06 +02:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
compute a CRC32 for each object as stored in a pack
The most important optimization for performance when repacking is the
ability to reuse data from a previous pack as is and bypass any delta
or even SHA1 computation by simply copying the raw data from one pack
to another directly.
The problem with this is that any data corruption within a copied object
would go unnoticed and the new (repacked) pack would be self-consistent
with its own checksum despite containing a corrupted object. This is a
real issue that already happened at least once in the past.
In some attempt to prevent this, we validate the copied data by inflating
it and making sure no error is signaled by zlib. But this is still not
perfect as a significant portion of a pack content is made of object
headers and references to delta base objects which are not deflated and
therefore not validated when repacking actually making the pack data reuse
still not as safe as it could be.
Of course a full SHA1 validation could be performed, but that implies
full data inflating and delta replaying which is extremely costly, which
cost the data reuse optimization was designed to avoid in the first place.
So the best solution to this is simply to store a CRC32 of the raw pack
data for each object in the pack index. This way any object in a pack can
be validated before being copied as is in another pack, including header
and any other non deflated data.
Why CRC32 instead of a faster checksum like Adler32? Quoting Wikipedia:
Jonathan Stone discovered in 2001 that Adler-32 has a weakness for very
short messages. He wrote "Briefly, the problem is that, for very short
packets, Adler32 is guaranteed to give poor coverage of the available
bits. Don't take my word for it, ask Mark Adler. :-)" The problem is
that sum A does not wrap for short messages. The maximum value of A for
a 128-byte message is 32640, which is below the value 65521 used by the
modulo operation. An extended explanation can be found in RFC 3309,
which mandates the use of CRC32 instead of Adler-32 for SCTP, the
Stream Control Transmission Protocol.
In the context of a GIT pack, we have lots of small objects, especially
deltas, which are likely to be quite small and in a size range for which
Adler32 is dimed not to be sufficient. Another advantage of CRC32 is the
possibility for recovery from certain types of small corruptions like
single bit errors which are the most probable type of corruptions.
OK what this patch does is to compute the CRC32 of each object written to
a pack within pack-objects. It is not written to the index yet and it is
obviously not validated when reusing pack data yet either.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-09 07:06:31 +02:00
|
|
|
void crc32_begin(struct sha1file *f)
|
|
|
|
{
|
|
|
|
f->crc32 = crc32(0, Z_NULL, 0);
|
|
|
|
f->do_crc = 1;
|
|
|
|
}
|
2005-06-27 05:27:56 +02:00
|
|
|
|
compute a CRC32 for each object as stored in a pack
The most important optimization for performance when repacking is the
ability to reuse data from a previous pack as is and bypass any delta
or even SHA1 computation by simply copying the raw data from one pack
to another directly.
The problem with this is that any data corruption within a copied object
would go unnoticed and the new (repacked) pack would be self-consistent
with its own checksum despite containing a corrupted object. This is a
real issue that already happened at least once in the past.
In some attempt to prevent this, we validate the copied data by inflating
it and making sure no error is signaled by zlib. But this is still not
perfect as a significant portion of a pack content is made of object
headers and references to delta base objects which are not deflated and
therefore not validated when repacking actually making the pack data reuse
still not as safe as it could be.
Of course a full SHA1 validation could be performed, but that implies
full data inflating and delta replaying which is extremely costly, which
cost the data reuse optimization was designed to avoid in the first place.
So the best solution to this is simply to store a CRC32 of the raw pack
data for each object in the pack index. This way any object in a pack can
be validated before being copied as is in another pack, including header
and any other non deflated data.
Why CRC32 instead of a faster checksum like Adler32? Quoting Wikipedia:
Jonathan Stone discovered in 2001 that Adler-32 has a weakness for very
short messages. He wrote "Briefly, the problem is that, for very short
packets, Adler32 is guaranteed to give poor coverage of the available
bits. Don't take my word for it, ask Mark Adler. :-)" The problem is
that sum A does not wrap for short messages. The maximum value of A for
a 128-byte message is 32640, which is below the value 65521 used by the
modulo operation. An extended explanation can be found in RFC 3309,
which mandates the use of CRC32 instead of Adler-32 for SCTP, the
Stream Control Transmission Protocol.
In the context of a GIT pack, we have lots of small objects, especially
deltas, which are likely to be quite small and in a size range for which
Adler32 is dimed not to be sufficient. Another advantage of CRC32 is the
possibility for recovery from certain types of small corruptions like
single bit errors which are the most probable type of corruptions.
OK what this patch does is to compute the CRC32 of each object written to
a pack within pack-objects. It is not written to the index yet and it is
obviously not validated when reusing pack data yet either.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-09 07:06:31 +02:00
|
|
|
uint32_t crc32_end(struct sha1file *f)
|
|
|
|
{
|
|
|
|
f->do_crc = 0;
|
|
|
|
return f->crc32;
|
|
|
|
}
|