http-push: fix off-by-path_len
[gitweb.git] / builtin-apply.c
index 50b623e54c003fb5bbe183568d13f496c3c41c25..a8f75ed3ed411d8cf7a3ec9dfefef7407c50f447 100644 (file)
@@ -321,13 +321,12 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
        const char *start = line;
 
        if (*line == '"') {
-               struct strbuf name;
+               struct strbuf name = STRBUF_INIT;
 
                /*
                 * Proposed "new-style" GNU patch/diff format; see
                 * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
                 */
-               strbuf_init(&name, 0);
                if (!unquote_c_style(&name, line, NULL)) {
                        char *cp;
 
@@ -631,7 +630,7 @@ static int gitdiff_index(const char *line, struct patch *patch)
        memcpy(patch->new_sha1_prefix, line, len);
        patch->new_sha1_prefix[len] = 0;
        if (*ptr == ' ')
-               patch->new_mode = patch->old_mode = strtoul(ptr+1, NULL, 8);
+               patch->old_mode = strtoul(ptr+1, NULL, 8);
        return 0;
 }
 
@@ -675,11 +674,8 @@ static char *git_header_name(char *line, int llen)
 
        if (*line == '"') {
                const char *cp;
-               struct strbuf first;
-               struct strbuf sp;
-
-               strbuf_init(&first, 0);
-               strbuf_init(&sp, 0);
+               struct strbuf first = STRBUF_INIT;
+               struct strbuf sp = STRBUF_INIT;
 
                if (unquote_c_style(&first, line, &second))
                        goto free_and_fail1;
@@ -741,10 +737,9 @@ static char *git_header_name(char *line, int llen)
         */
        for (second = name; second < line + llen; second++) {
                if (*second == '"') {
-                       struct strbuf sp;
+                       struct strbuf sp = STRBUF_INIT;
                        const char *np;
 
-                       strbuf_init(&sp, 0);
                        if (unquote_c_style(&sp, second, NULL))
                                goto free_and_fail2;
 
@@ -1515,11 +1510,10 @@ static const char minuses[]=
 
 static void show_stats(struct patch *patch)
 {
-       struct strbuf qname;
+       struct strbuf qname = STRBUF_INIT;
        char *cp = patch->new_name ? patch->new_name : patch->old_name;
        int max, add, del;
 
-       strbuf_init(&qname, 0);
        quote_c_style(cp, &qname, NULL, 0);
 
        /*
@@ -1565,10 +1559,8 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
 {
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
-               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);
+               if (strbuf_readlink(buf, path, st->st_size) < 0)
+                       return error("unable to read symlink %s", path);
                return 0;
        case S_IFREG:
                if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
@@ -2299,14 +2291,12 @@ static void add_to_fn_table(struct patch *patch)
 
 static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
 {
-       struct strbuf buf;
+       struct strbuf buf = STRBUF_INIT;
        struct image image;
        size_t len;
        char *img;
        struct patch *tpatch;
 
-       strbuf_init(&buf, 0);
-
        if (!(patch->is_copy || patch->is_rename) &&
            ((tpatch = in_fn_table(patch->old_name)) != NULL)) {
                if (tpatch == (struct patch *) -1) {
@@ -2457,6 +2447,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
        if (st_mode != patch->old_mode)
                fprintf(stderr, "warning: %s has type %o, expected %o\n",
                        old_name, st_mode, patch->old_mode);
+       if (!patch->new_mode)
+               patch->new_mode = st_mode;
        return 0;
 
  is_new:
@@ -2786,7 +2778,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
 static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
 {
        int fd;
-       struct strbuf nbuf;
+       struct strbuf nbuf = STRBUF_INIT;
 
        if (S_ISGITLINK(mode)) {
                struct stat st;
@@ -2805,7 +2797,6 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
        if (fd < 0)
                return -1;
 
-       strbuf_init(&nbuf, 0);
        if (convert_to_working_tree(path, buf, size, &nbuf)) {
                size = nbuf.len;
                buf  = nbuf.buf;
@@ -2996,29 +2987,45 @@ static int write_out_results(struct patch *list, int skipped_patch)
 
 static struct lock_file lock_file;
 
-static struct excludes {
-       struct excludes *next;
-       const char *path;
-} *excludes;
+static struct string_list limit_by_name;
+static int has_include;
+static void add_name_limit(const char *name, int exclude)
+{
+       struct string_list_item *it;
+
+       it = string_list_append(name, &limit_by_name);
+       it->util = exclude ? NULL : (void *) 1;
+}
 
 static int use_patch(struct patch *p)
 {
        const char *pathname = p->new_name ? p->new_name : p->old_name;
-       struct excludes *x = excludes;
-       while (x) {
-               if (fnmatch(x->path, pathname, 0) == 0)
-                       return 0;
-               x = x->next;
-       }
+       int i;
+
+       /* Paths outside are not touched regardless of "--include" */
        if (0 < prefix_length) {
                int pathlen = strlen(pathname);
                if (pathlen <= prefix_length ||
                    memcmp(prefix, pathname, prefix_length))
                        return 0;
        }
-       return 1;
+
+       /* See if it matches any of exclude/include rule */
+       for (i = 0; i < limit_by_name.nr; i++) {
+               struct string_list_item *it = &limit_by_name.items[i];
+               if (!fnmatch(it->string, pathname, 0))
+                       return (it->util != NULL);
+       }
+
+       /*
+        * If we had any include, a path that does not match any rule is
+        * not used.  Otherwise, we saw bunch of exclude rules (or none)
+        * and such a path is used.
+        */
+       return !has_include;
 }
 
+
 static void prefix_one(char **name)
 {
        char *old_name = *name;
@@ -3051,13 +3058,12 @@ static void prefix_patches(struct patch *p)
 static int apply_patch(int fd, const char *filename, int options)
 {
        size_t offset;
-       struct strbuf buf;
+       struct strbuf buf = STRBUF_INIT;
        struct patch *list = NULL, **listp = &list;
        int skipped_patch = 0;
 
        /* FIXME - memory leak when using multiple patch files as inputs */
        memset(&fn_table, 0, sizeof(struct string_list));
-       strbuf_init(&buf, 0);
        patch_input_file = filename;
        read_patch_file(&buf, fd);
        offset = 0;
@@ -3159,10 +3165,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        continue;
                }
                if (!prefixcmp(arg, "--exclude=")) {
-                       struct excludes *x = xmalloc(sizeof(*x));
-                       x->path = arg + 10;
-                       x->next = excludes;
-                       excludes = x;
+                       add_name_limit(arg + 10, 1);
+                       continue;
+               }
+               if (!prefixcmp(arg, "--include=")) {
+                       add_name_limit(arg + 10, 0);
+                       has_include = 1;
                        continue;
                }
                if (!prefixcmp(arg, "-p")) {