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:
Pierre Habouzit 2007-09-16 18:54:42 +02:00 committed by Junio C Hamano
parent ba3ed09728
commit c7f9cb1428

View File

@ -1441,37 +1441,28 @@ static void show_stats(struct patch *patch)
free(qname); 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; int fd;
unsigned long got;
struct strbuf nbuf;
unsigned long size = *size_p;
char *buf = *buf_p;
switch (st->st_mode & S_IFMT) { switch (st->st_mode & S_IFMT) {
case S_IFLNK: 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: case S_IFREG:
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) if (fd < 0)
return error("unable to open %s", path); return error("unable to open %s", path);
got = 0; if (strbuf_read(buf, fd, st->st_size) < 0) {
for (;;) { close(fd);
ssize_t ret = xread(fd, buf + got, size - got); return -1;
if (ret <= 0)
break;
got += ret;
} }
close(fd); close(fd);
strbuf_init(&nbuf, 0); convert_to_git(path, buf->buf, buf->len, buf);
if (convert_to_git(path, buf, size, &nbuf)) { return 0;
free(buf);
*buf_p = nbuf.buf;
*alloc_p = nbuf.alloc;
*size_p = nbuf.len;
}
return got != size;
default: default:
return -1; return -1;
} }
@ -1576,12 +1567,6 @@ static void remove_last_line(const char **rbuf, int *rsize)
*rsize = offset + 1; *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) static int apply_line(char *output, const char *patch, int plen)
{ {
/* plen is number of bytes to be copied from patch, /* 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; 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; int match_beginning, match_end;
char *buf = desc->buffer;
const char *patch = frag->patch; const char *patch = frag->patch;
int offset, size = frag->size; int offset, size = frag->size;
char *old = xmalloc(size); char *old = xmalloc(size);
@ -1765,24 +1749,17 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
lines = 0; lines = 0;
pos = frag->newpos; pos = frag->newpos;
for (;;) { for (;;) {
offset = find_offset(buf, desc->size, offset = find_offset(buf->buf, buf->len,
oldlines, oldsize, pos, &lines); oldlines, oldsize, pos, &lines);
if (match_end && offset + oldsize != desc->size) if (match_end && offset + oldsize != buf->len)
offset = -1; offset = -1;
if (match_beginning && offset) if (match_beginning && offset)
offset = -1; offset = -1;
if (offset >= 0) { if (offset >= 0) {
int diff;
unsigned long size, alloc;
if (new_whitespace == strip_whitespace && 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; 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 /* Warn if it was necessary to reduce the number
* of context lines. * 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", " to apply fragment at %d\n",
leading, trailing, pos + lines); leading, trailing, pos + lines);
if (size > alloc) { strbuf_splice(buf, offset, oldsize, newlines, newsize);
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);
offset = 0; offset = 0;
break; break;
} }
@ -1840,12 +1806,11 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
return offset; 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; struct fragment *fragment = patch->fragments;
void *data; unsigned long len;
void *result; void *dst;
/* Binary patch is irreversible without the optional second hunk */ /* Binary patch is irreversible without the optional second hunk */
if (apply_in_reverse) { 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); ? patch->new_name : patch->old_name);
fragment = fragment->next; fragment = fragment->next;
} }
data = (void*) fragment->patch;
switch (fragment->binary_patch_method) { switch (fragment->binary_patch_method) {
case BINARY_DELTA_DEFLATED: case BINARY_DELTA_DEFLATED:
result = patch_delta(desc->buffer, desc->size, dst = patch_delta(buf->buf, buf->len, fragment->patch,
data, fragment->size, &len);
fragment->size, if (!dst)
&dst_size);
free(desc->buffer);
desc->buffer = result;
break;
case BINARY_LITERAL_DEFLATED:
free(desc->buffer);
desc->buffer = data;
dst_size = fragment->size;
break;
}
if (!desc->buffer)
return -1; return -1;
desc->size = desc->alloc = dst_size; /* XXX patch_delta NUL-terminates */
strbuf_attach(buf, dst, len, len + 1);
return 0; return 0;
case BINARY_LITERAL_DEFLATED:
strbuf_reset(buf);
strbuf_add(buf, fragment->patch, fragment->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; const char *name = patch->old_name ? patch->old_name : patch->new_name;
unsigned char sha1[20]; 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 /* See if the old one matches what the patch
* applies to. * 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)) if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
return error("the patch applies to '%s' (%s), " return error("the patch applies to '%s' (%s), "
"which does not match the " "which does not match the "
@ -1906,16 +1866,14 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
} }
else { else {
/* Otherwise, the old one must be empty. */ /* Otherwise, the old one must be empty. */
if (desc->size) if (buf->len)
return error("the patch applies to an empty " return error("the patch applies to an empty "
"'%s' but it is not empty", name); "'%s' but it is not empty", name);
} }
get_sha1_hex(patch->new_sha1_prefix, sha1); get_sha1_hex(patch->new_sha1_prefix, sha1);
if (is_null_sha1(sha1)) { if (is_null_sha1(sha1)) {
free(desc->buffer); strbuf_release(buf);
desc->alloc = desc->size = 0;
desc->buffer = NULL;
return 0; /* deletion patch */ return 0; /* deletion patch */
} }
@ -1923,43 +1881,44 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
/* We already have the postimage */ /* We already have the postimage */
enum object_type type; enum object_type type;
unsigned long size; unsigned long size;
char *result;
free(desc->buffer); result = read_sha1_file(sha1, &type, &size);
desc->buffer = read_sha1_file(sha1, &type, &size); if (!result)
if (!desc->buffer)
return error("the necessary postimage %s for " return error("the necessary postimage %s for "
"'%s' cannot be read", "'%s' cannot be read",
patch->new_sha1_prefix, name); patch->new_sha1_prefix, name);
desc->alloc = desc->size = size; /* XXX read_sha1_file NUL-terminates */
} strbuf_attach(buf, result, size, size + 1);
else { } else {
/* We have verified desc matches the preimage; /* We have verified buf matches the preimage;
* apply the patch data to it, which is stored * apply the patch data to it, which is stored
* in the patch->fragments->{patch,size}. * 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'", return error("binary patch does not apply to '%s'",
name); name);
/* verify that the result matches */ /* 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)) 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; 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; struct fragment *frag = patch->fragments;
const char *name = patch->old_name ? patch->old_name : patch->new_name; const char *name = patch->old_name ? patch->old_name : patch->new_name;
if (patch->is_binary) if (patch->is_binary)
return apply_binary(desc, patch); return apply_binary(buf, patch);
while (frag) { 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); error("patch failed: %s:%ld", name, frag->oldpos);
if (!apply_with_reject) if (!apply_with_reject)
return -1; return -1;
@ -1970,76 +1929,57 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
return 0; return 0;
} }
static int read_file_or_gitlink(struct cache_entry *ce, char **buf_p, static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
unsigned long *size_p)
{ {
if (!ce) if (!ce)
return 0; return 0;
if (S_ISGITLINK(ntohl(ce->ce_mode))) { if (S_ISGITLINK(ntohl(ce->ce_mode))) {
*buf_p = xmalloc(100); strbuf_grow(buf, 100);
*size_p = snprintf(*buf_p, 100, strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
"Subproject commit %s\n", sha1_to_hex(ce->sha1));
} else { } else {
enum object_type type; enum object_type type;
*buf_p = read_sha1_file(ce->sha1, &type, size_p); unsigned long sz;
if (!*buf_p) char *result;
result = read_sha1_file(ce->sha1, &type, &sz);
if (!result)
return -1; return -1;
/* XXX read_sha1_file NUL-terminates */
strbuf_attach(buf, result, sz, sz + 1);
} }
return 0; return 0;
} }
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce) static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{ {
char *buf; struct strbuf buf;
unsigned long size, alloc;
struct buffer_desc desc;
size = 0; strbuf_init(&buf, 0);
alloc = 0;
buf = NULL;
if (cached) { 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); return error("read of %s failed", patch->old_name);
alloc = size;
} else if (patch->old_name) { } else if (patch->old_name) {
if (S_ISGITLINK(patch->old_mode)) { if (S_ISGITLINK(patch->old_mode)) {
if (ce) if (ce) {
read_file_or_gitlink(ce, &buf, &size); read_file_or_gitlink(ce, &buf);
else { } else {
/* /*
* There is no way to apply subproject * There is no way to apply subproject
* patch without looking at the index. * patch without looking at the index.
*/ */
patch->fragments = NULL; patch->fragments = NULL;
size = 0;
} }
} } else {
else { if (read_old_data(st, patch->old_name, &buf))
size = xsize_t(st->st_size); return error("read of %s failed", patch->old_name);
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);
} }
} }
desc.size = size; if (apply_fragments(&buf, patch) < 0)
desc.alloc = alloc;
desc.buffer = buf;
if (apply_fragments(&desc, patch) < 0)
return -1; /* note with --reject this succeeds. */ return -1; /* note with --reject this succeeds. */
patch->result = buf.buf;
/* NUL terminate the result */ patch->resultsize = buf.len;
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;
if (0 < patch->is_delete && patch->resultsize) if (0 < patch->is_delete && patch->resultsize)
return error("removal patch leaves file contents"); 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; size = nbuf.len;
buf = nbuf.buf; 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) if (close(fd) < 0)
die("closing file %s: %s", path, strerror(errno)); die("closing file %s: %s", path, strerror(errno));
strbuf_release(&nbuf);
return 0; return 0;
} }