2005-05-19 18:27:14 +04:00
|
|
|
/*
|
|
|
|
* test-delta.c: test code to exercise diff-delta.c and patch-delta.c
|
|
|
|
*
|
2009-09-14 10:41:16 +04:00
|
|
|
* (C) 2005 Nicolas Pitre <nico@fluxnic.net>
|
2005-05-19 18:27:14 +04:00
|
|
|
*
|
|
|
|
* This code is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
|
2018-03-24 10:44:37 +03:00
|
|
|
#include "test-tool.h"
|
2006-12-20 01:34:12 +03:00
|
|
|
#include "git-compat-util.h"
|
2005-05-19 18:27:14 +04:00
|
|
|
#include "delta.h"
|
2007-05-01 13:47:55 +04:00
|
|
|
#include "cache.h"
|
2005-05-19 18:27:14 +04:00
|
|
|
|
2007-05-01 13:47:55 +04:00
|
|
|
static const char usage_str[] =
|
2018-03-24 10:44:37 +03:00
|
|
|
"test-tool delta (-d|-p) <from_file> <data_file> <out_file>";
|
2005-05-19 18:27:14 +04:00
|
|
|
|
2018-03-24 10:44:37 +03:00
|
|
|
int cmd__delta(int argc, const char **argv)
|
2005-05-19 18:27:14 +04:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
struct stat st;
|
|
|
|
void *from_buf, *data_buf, *out_buf;
|
|
|
|
unsigned long from_size, data_size, out_size;
|
|
|
|
|
|
|
|
if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p"))) {
|
2013-02-25 02:48:39 +04:00
|
|
|
fprintf(stderr, "usage: %s\n", usage_str);
|
2005-05-19 18:27:14 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = open(argv[2], O_RDONLY);
|
|
|
|
if (fd < 0 || fstat(fd, &st)) {
|
|
|
|
perror(argv[2]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
from_size = st.st_size;
|
test-delta: read input into a heap buffer
We currently read the input to test-delta by mmap()-ing it.
However, memory-checking tools like valgrind and ASan are
less able to detect reads/writes past the end of an mmap'd
buffer, because the OS is likely to give us extra bytes to
pad out the final page size. So instead, let's read into a
heap buffer.
As a bonus, this also makes it possible to write tests with
empty bases, as mmap() will complain about a zero-length
map.
This is based on a patch by Jann Horn <jannh@google.com>
which actually aligned the data at the end of a page, and
followed it with another page marked with mprotect(). That
would detect problems even without a tool like ASan, but it
was significantly more complex and may have introduced
portability problems. By comparison, this approach pushes
the complexity onto existing memory-checking tools.
Note that this could be done even more simply by using
strbuf_read_file(), but that would defeat the purpose:
strbufs generally overallocate (and at the very least
include a trailing NUL which we do not care about), which
would defeat most memory checkers.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Nicolas Pitre <nico@fluxnic.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-30 10:07:52 +03:00
|
|
|
from_buf = xmalloc(from_size);
|
|
|
|
if (read_in_full(fd, from_buf, from_size) < 0) {
|
2005-05-19 18:27:14 +04:00
|
|
|
perror(argv[2]);
|
2005-07-29 18:49:14 +04:00
|
|
|
close(fd);
|
2005-05-19 18:27:14 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
fd = open(argv[3], O_RDONLY);
|
|
|
|
if (fd < 0 || fstat(fd, &st)) {
|
|
|
|
perror(argv[3]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
data_size = st.st_size;
|
test-delta: read input into a heap buffer
We currently read the input to test-delta by mmap()-ing it.
However, memory-checking tools like valgrind and ASan are
less able to detect reads/writes past the end of an mmap'd
buffer, because the OS is likely to give us extra bytes to
pad out the final page size. So instead, let's read into a
heap buffer.
As a bonus, this also makes it possible to write tests with
empty bases, as mmap() will complain about a zero-length
map.
This is based on a patch by Jann Horn <jannh@google.com>
which actually aligned the data at the end of a page, and
followed it with another page marked with mprotect(). That
would detect problems even without a tool like ASan, but it
was significantly more complex and may have introduced
portability problems. By comparison, this approach pushes
the complexity onto existing memory-checking tools.
Note that this could be done even more simply by using
strbuf_read_file(), but that would defeat the purpose:
strbufs generally overallocate (and at the very least
include a trailing NUL which we do not care about), which
would defeat most memory checkers.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Nicolas Pitre <nico@fluxnic.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-30 10:07:52 +03:00
|
|
|
data_buf = xmalloc(data_size);
|
|
|
|
if (read_in_full(fd, data_buf, data_size) < 0) {
|
2005-05-19 18:27:14 +04:00
|
|
|
perror(argv[3]);
|
2005-07-29 18:49:14 +04:00
|
|
|
close(fd);
|
2005-05-19 18:27:14 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (argv[1][1] == 'd')
|
|
|
|
out_buf = diff_delta(from_buf, from_size,
|
2005-06-26 06:30:20 +04:00
|
|
|
data_buf, data_size,
|
2005-06-29 11:32:11 +04:00
|
|
|
&out_size, 0);
|
2005-05-19 18:27:14 +04:00
|
|
|
else
|
|
|
|
out_buf = patch_delta(from_buf, from_size,
|
2005-06-26 06:30:20 +04:00
|
|
|
data_buf, data_size,
|
|
|
|
&out_size);
|
2005-05-19 18:27:14 +04:00
|
|
|
if (!out_buf) {
|
|
|
|
fprintf(stderr, "delta operation failed (returned NULL)\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666);
|
avoid "write_in_full(fd, buf, len) != len" pattern
The return value of write_in_full() is either "-1", or the
requested number of bytes[1]. If we make a partial write
before seeing an error, we still return -1, not a partial
value. This goes back to f6aa66cb95 (write_in_full: really
write in full or return error on disk full., 2007-01-11).
So checking anything except "was the return value negative"
is pointless. And there are a couple of reasons not to do
so:
1. It can do a funny signed/unsigned comparison. If your
"len" is signed (e.g., a size_t) then the compiler will
promote the "-1" to its unsigned variant.
This works out for "!= len" (unless you really were
trying to write the maximum size_t bytes), but is a
bug if you check "< len" (an example of which was fixed
recently in config.c).
We should avoid promoting the mental model that you
need to check the length at all, so that new sites are
not tempted to copy us.
2. Checking for a negative value is shorter to type,
especially when the length is an expression.
3. Linus says so. In d34cf19b89 (Clean up write_in_full()
users, 2007-01-11), right after the write_in_full()
semantics were changed, he wrote:
I really wish every "write_in_full()" user would just
check against "<0" now, but this fixes the nasty and
stupid ones.
Appeals to authority aside, this makes it clear that
writing it this way does not have an intentional
benefit. It's a historical curiosity that we never
bothered to clean up (and which was undoubtedly
cargo-culted into new sites).
So let's convert these obviously-correct cases (this
includes write_str_in_full(), which is just a wrapper for
write_in_full()).
[1] A careful reader may notice there is one way that
write_in_full() can return a different value. If we ask
write() to write N bytes and get a return value that is
_larger_ than N, we could return a larger total. But
besides the fact that this would imply a totally broken
version of write(), it would already invoke undefined
behavior. Our internal remaining counter is an unsigned
size_t, which means that subtracting too many byte will
wrap it around to a very large number. So we'll instantly
begin reading off the end of the buffer, trying to write
gigabytes (or petabytes) of data.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-13 20:16:03 +03:00
|
|
|
if (fd < 0 || write_in_full(fd, out_buf, out_size) < 0) {
|
2005-05-19 18:27:14 +04:00
|
|
|
perror(argv[4]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|