Code

builtin-apply: use strbuf's instead of buffer_desc's.
authorPierre Habouzit <madcoder@debian.org>
Sun, 16 Sep 2007 16:54:42 +0000 (18:54 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 17 Sep 2007 00:30:03 +0000 (17:30 -0700)
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>
builtin-apply.c

index 1256716aece3d3e97f615cc6d8957da68d3e14d6..61b51315edb040b19e7e17314c66780bab1be346 100644 (file)
@@ -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;
 }