builtin-apply: use strbuf's instead of buffer_desc's.
Signed-off-by: Pierre Habouzit <madcoder@debian.org> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
ba3ed09728
commit
c7f9cb1428
212
builtin-apply.c
212
builtin-apply.c
@ -1441,37 +1441,28 @@ static void show_stats(struct patch *patch)
|
||||
free(qname);
|
||||
}
|
||||
|
||||
static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p)
|
||||
static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
|
||||
{
|
||||
int fd;
|
||||
unsigned long got;
|
||||
struct strbuf nbuf;
|
||||
unsigned long size = *size_p;
|
||||
char *buf = *buf_p;
|
||||
|
||||
switch (st->st_mode & S_IFMT) {
|
||||
case S_IFLNK:
|
||||
return readlink(path, buf, size) != size;
|
||||
strbuf_grow(buf, st->st_size);
|
||||
if (readlink(path, buf->buf, st->st_size) != st->st_size)
|
||||
return -1;
|
||||
strbuf_setlen(buf, st->st_size);
|
||||
return 0;
|
||||
case S_IFREG:
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return error("unable to open %s", path);
|
||||
got = 0;
|
||||
for (;;) {
|
||||
ssize_t ret = xread(fd, buf + got, size - got);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
got += ret;
|
||||
if (strbuf_read(buf, fd, st->st_size) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
strbuf_init(&nbuf, 0);
|
||||
if (convert_to_git(path, buf, size, &nbuf)) {
|
||||
free(buf);
|
||||
*buf_p = nbuf.buf;
|
||||
*alloc_p = nbuf.alloc;
|
||||
*size_p = nbuf.len;
|
||||
}
|
||||
return got != size;
|
||||
convert_to_git(path, buf->buf, buf->len, buf);
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -1576,12 +1567,6 @@ static void remove_last_line(const char **rbuf, int *rsize)
|
||||
*rsize = offset + 1;
|
||||
}
|
||||
|
||||
struct buffer_desc {
|
||||
char *buffer;
|
||||
unsigned long size;
|
||||
unsigned long alloc;
|
||||
};
|
||||
|
||||
static int apply_line(char *output, const char *patch, int plen)
|
||||
{
|
||||
/* plen is number of bytes to be copied from patch,
|
||||
@ -1651,10 +1636,9 @@ static int apply_line(char *output, const char *patch, int plen)
|
||||
return output + plen - buf;
|
||||
}
|
||||
|
||||
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
|
||||
static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int inaccurate_eof)
|
||||
{
|
||||
int match_beginning, match_end;
|
||||
char *buf = desc->buffer;
|
||||
const char *patch = frag->patch;
|
||||
int offset, size = frag->size;
|
||||
char *old = xmalloc(size);
|
||||
@ -1765,24 +1749,17 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
|
||||
lines = 0;
|
||||
pos = frag->newpos;
|
||||
for (;;) {
|
||||
offset = find_offset(buf, desc->size,
|
||||
offset = find_offset(buf->buf, buf->len,
|
||||
oldlines, oldsize, pos, &lines);
|
||||
if (match_end && offset + oldsize != desc->size)
|
||||
if (match_end && offset + oldsize != buf->len)
|
||||
offset = -1;
|
||||
if (match_beginning && offset)
|
||||
offset = -1;
|
||||
if (offset >= 0) {
|
||||
int diff;
|
||||
unsigned long size, alloc;
|
||||
|
||||
if (new_whitespace == strip_whitespace &&
|
||||
(desc->size - oldsize - offset == 0)) /* end of file? */
|
||||
(buf->len - oldsize - offset == 0)) /* end of file? */
|
||||
newsize -= new_blank_lines_at_end;
|
||||
|
||||
diff = newsize - oldsize;
|
||||
size = desc->size + diff;
|
||||
alloc = desc->alloc;
|
||||
|
||||
/* Warn if it was necessary to reduce the number
|
||||
* of context lines.
|
||||
*/
|
||||
@ -1792,19 +1769,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
|
||||
" to apply fragment at %d\n",
|
||||
leading, trailing, pos + lines);
|
||||
|
||||
if (size > alloc) {
|
||||
alloc = size + 8192;
|
||||
desc->alloc = alloc;
|
||||
buf = xrealloc(buf, alloc);
|
||||
desc->buffer = buf;
|
||||
}
|
||||
desc->size = size;
|
||||
memmove(buf + offset + newsize,
|
||||
buf + offset + oldsize,
|
||||
size - offset - newsize);
|
||||
memcpy(buf + offset, newlines, newsize);
|
||||
strbuf_splice(buf, offset, oldsize, newlines, newsize);
|
||||
offset = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1840,12 +1806,11 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
|
||||
static int apply_binary_fragment(struct strbuf *buf, struct patch *patch)
|
||||
{
|
||||
unsigned long dst_size;
|
||||
struct fragment *fragment = patch->fragments;
|
||||
void *data;
|
||||
void *result;
|
||||
unsigned long len;
|
||||
void *dst;
|
||||
|
||||
/* Binary patch is irreversible without the optional second hunk */
|
||||
if (apply_in_reverse) {
|
||||
@ -1856,29 +1821,24 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
|
||||
? patch->new_name : patch->old_name);
|
||||
fragment = fragment->next;
|
||||
}
|
||||
data = (void*) fragment->patch;
|
||||
switch (fragment->binary_patch_method) {
|
||||
case BINARY_DELTA_DEFLATED:
|
||||
result = patch_delta(desc->buffer, desc->size,
|
||||
data,
|
||||
fragment->size,
|
||||
&dst_size);
|
||||
free(desc->buffer);
|
||||
desc->buffer = result;
|
||||
break;
|
||||
dst = patch_delta(buf->buf, buf->len, fragment->patch,
|
||||
fragment->size, &len);
|
||||
if (!dst)
|
||||
return -1;
|
||||
/* XXX patch_delta NUL-terminates */
|
||||
strbuf_attach(buf, dst, len, len + 1);
|
||||
return 0;
|
||||
case BINARY_LITERAL_DEFLATED:
|
||||
free(desc->buffer);
|
||||
desc->buffer = data;
|
||||
dst_size = fragment->size;
|
||||
break;
|
||||
strbuf_reset(buf);
|
||||
strbuf_add(buf, fragment->patch, fragment->size);
|
||||
return 0;
|
||||
}
|
||||
if (!desc->buffer)
|
||||
return -1;
|
||||
desc->size = desc->alloc = dst_size;
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int apply_binary(struct buffer_desc *desc, struct patch *patch)
|
||||
static int apply_binary(struct strbuf *buf, struct patch *patch)
|
||||
{
|
||||
const char *name = patch->old_name ? patch->old_name : patch->new_name;
|
||||
unsigned char sha1[20];
|
||||
@ -1897,7 +1857,7 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
|
||||
/* See if the old one matches what the patch
|
||||
* applies to.
|
||||
*/
|
||||
hash_sha1_file(desc->buffer, desc->size, blob_type, sha1);
|
||||
hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
|
||||
if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
|
||||
return error("the patch applies to '%s' (%s), "
|
||||
"which does not match the "
|
||||
@ -1906,16 +1866,14 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
|
||||
}
|
||||
else {
|
||||
/* Otherwise, the old one must be empty. */
|
||||
if (desc->size)
|
||||
if (buf->len)
|
||||
return error("the patch applies to an empty "
|
||||
"'%s' but it is not empty", name);
|
||||
}
|
||||
|
||||
get_sha1_hex(patch->new_sha1_prefix, sha1);
|
||||
if (is_null_sha1(sha1)) {
|
||||
free(desc->buffer);
|
||||
desc->alloc = desc->size = 0;
|
||||
desc->buffer = NULL;
|
||||
strbuf_release(buf);
|
||||
return 0; /* deletion patch */
|
||||
}
|
||||
|
||||
@ -1923,43 +1881,44 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
|
||||
/* We already have the postimage */
|
||||
enum object_type type;
|
||||
unsigned long size;
|
||||
char *result;
|
||||
|
||||
free(desc->buffer);
|
||||
desc->buffer = read_sha1_file(sha1, &type, &size);
|
||||
if (!desc->buffer)
|
||||
result = read_sha1_file(sha1, &type, &size);
|
||||
if (!result)
|
||||
return error("the necessary postimage %s for "
|
||||
"'%s' cannot be read",
|
||||
patch->new_sha1_prefix, name);
|
||||
desc->alloc = desc->size = size;
|
||||
}
|
||||
else {
|
||||
/* We have verified desc matches the preimage;
|
||||
/* XXX read_sha1_file NUL-terminates */
|
||||
strbuf_attach(buf, result, size, size + 1);
|
||||
} else {
|
||||
/* We have verified buf matches the preimage;
|
||||
* apply the patch data to it, which is stored
|
||||
* in the patch->fragments->{patch,size}.
|
||||
*/
|
||||
if (apply_binary_fragment(desc, patch))
|
||||
if (apply_binary_fragment(buf, patch))
|
||||
return error("binary patch does not apply to '%s'",
|
||||
name);
|
||||
|
||||
/* verify that the result matches */
|
||||
hash_sha1_file(desc->buffer, desc->size, blob_type, sha1);
|
||||
hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
|
||||
if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
|
||||
return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", name, patch->new_sha1_prefix, sha1_to_hex(sha1));
|
||||
return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)",
|
||||
name, patch->new_sha1_prefix, sha1_to_hex(sha1));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
|
||||
static int apply_fragments(struct strbuf *buf, struct patch *patch)
|
||||
{
|
||||
struct fragment *frag = patch->fragments;
|
||||
const char *name = patch->old_name ? patch->old_name : patch->new_name;
|
||||
|
||||
if (patch->is_binary)
|
||||
return apply_binary(desc, patch);
|
||||
return apply_binary(buf, patch);
|
||||
|
||||
while (frag) {
|
||||
if (apply_one_fragment(desc, frag, patch->inaccurate_eof)) {
|
||||
if (apply_one_fragment(buf, frag, patch->inaccurate_eof)) {
|
||||
error("patch failed: %s:%ld", name, frag->oldpos);
|
||||
if (!apply_with_reject)
|
||||
return -1;
|
||||
@ -1970,76 +1929,57 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_file_or_gitlink(struct cache_entry *ce, char **buf_p,
|
||||
unsigned long *size_p)
|
||||
static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
|
||||
{
|
||||
if (!ce)
|
||||
return 0;
|
||||
|
||||
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
|
||||
*buf_p = xmalloc(100);
|
||||
*size_p = snprintf(*buf_p, 100,
|
||||
"Subproject commit %s\n", sha1_to_hex(ce->sha1));
|
||||
strbuf_grow(buf, 100);
|
||||
strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
|
||||
} else {
|
||||
enum object_type type;
|
||||
*buf_p = read_sha1_file(ce->sha1, &type, size_p);
|
||||
if (!*buf_p)
|
||||
unsigned long sz;
|
||||
char *result;
|
||||
|
||||
result = read_sha1_file(ce->sha1, &type, &sz);
|
||||
if (!result)
|
||||
return -1;
|
||||
/* XXX read_sha1_file NUL-terminates */
|
||||
strbuf_attach(buf, result, sz, sz + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
|
||||
{
|
||||
char *buf;
|
||||
unsigned long size, alloc;
|
||||
struct buffer_desc desc;
|
||||
struct strbuf buf;
|
||||
|
||||
size = 0;
|
||||
alloc = 0;
|
||||
buf = NULL;
|
||||
strbuf_init(&buf, 0);
|
||||
if (cached) {
|
||||
if (read_file_or_gitlink(ce, &buf, &size))
|
||||
if (read_file_or_gitlink(ce, &buf))
|
||||
return error("read of %s failed", patch->old_name);
|
||||
alloc = size;
|
||||
} else if (patch->old_name) {
|
||||
if (S_ISGITLINK(patch->old_mode)) {
|
||||
if (ce)
|
||||
read_file_or_gitlink(ce, &buf, &size);
|
||||
else {
|
||||
if (ce) {
|
||||
read_file_or_gitlink(ce, &buf);
|
||||
} else {
|
||||
/*
|
||||
* There is no way to apply subproject
|
||||
* patch without looking at the index.
|
||||
*/
|
||||
patch->fragments = NULL;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
size = xsize_t(st->st_size);
|
||||
alloc = size + 8192;
|
||||
buf = xmalloc(alloc);
|
||||
if (read_old_data(st, patch->old_name,
|
||||
&buf, &alloc, &size))
|
||||
return error("read of %s failed",
|
||||
patch->old_name);
|
||||
} else {
|
||||
if (read_old_data(st, patch->old_name, &buf))
|
||||
return error("read of %s failed", patch->old_name);
|
||||
}
|
||||
}
|
||||
|
||||
desc.size = size;
|
||||
desc.alloc = alloc;
|
||||
desc.buffer = buf;
|
||||
|
||||
if (apply_fragments(&desc, patch) < 0)
|
||||
if (apply_fragments(&buf, patch) < 0)
|
||||
return -1; /* note with --reject this succeeds. */
|
||||
|
||||
/* NUL terminate the result */
|
||||
if (desc.alloc <= desc.size)
|
||||
desc.buffer = xrealloc(desc.buffer, desc.size + 1);
|
||||
desc.buffer[desc.size] = 0;
|
||||
|
||||
patch->result = desc.buffer;
|
||||
patch->resultsize = desc.size;
|
||||
patch->result = buf.buf;
|
||||
patch->resultsize = buf.len;
|
||||
|
||||
if (0 < patch->is_delete && patch->resultsize)
|
||||
return error("removal patch leaves file contents");
|
||||
@ -2460,19 +2400,11 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
|
||||
size = nbuf.len;
|
||||
buf = nbuf.buf;
|
||||
}
|
||||
write_or_die(fd, buf, size);
|
||||
strbuf_release(&nbuf);
|
||||
|
||||
while (size) {
|
||||
int written = xwrite(fd, buf, size);
|
||||
if (written < 0)
|
||||
die("writing file %s: %s", path, strerror(errno));
|
||||
if (!written)
|
||||
die("out of space writing file %s", path);
|
||||
buf += written;
|
||||
size -= written;
|
||||
}
|
||||
if (close(fd) < 0)
|
||||
die("closing file %s: %s", path, strerror(errno));
|
||||
strbuf_release(&nbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user