Merge branch 'maint'
authorJunio C Hamano <junkio@cox.net>
Tue, 27 Feb 2007 09:33:52 +0000 (01:33 -0800)
committerJunio C Hamano <junkio@cox.net>
Tue, 27 Feb 2007 09:33:52 +0000 (01:33 -0800)
* maint:
git-apply: do not fix whitespaces on context lines.
diff --cc: integer overflow given a 2GB-or-larger file
mailinfo: do not get confused with logical lines that are too long.

1  2 
builtin-apply.c
builtin-mailinfo.c
diff --combined builtin-apply.c
index 2dde34186a53cba3066a363525bff7998d268266,bec95d6c8aa60ac40718f52da5a8f9603330dadb..b84d747e3f3117570db5a2089c2abe67a611cb02
@@@ -28,7 -28,6 +28,7 @@@ static int newfd = -1
  
  static int unidiff_zero;
  static int p_value = 1;
 +static int p_value_known;
  static int check_index;
  static int write_index;
  static int cached;
@@@ -145,7 -144,6 +145,7 @@@ struct patch 
        unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
 +      unsigned int is_toplevel_relative:1;
        unsigned int inaccurate_eof:1;
        unsigned int is_binary:1;
        unsigned int is_copy:1;
@@@ -240,7 -238,7 +240,7 @@@ static int name_terminate(const char *n
        return 1;
  }
  
 -static char * find_name(const char *line, char *def, int p_value, int terminate)
 +static char *find_name(const char *line, char *def, int p_value, int terminate)
  {
        int len;
        const char *start = line;
        return name;
  }
  
 +static int count_slashes(const char *cp)
 +{
 +      int cnt = 0;
 +      char ch;
 +
 +      while ((ch = *cp++))
 +              if (ch == '/')
 +                      cnt++;
 +      return cnt;
 +}
 +
 +/*
 + * Given the string after "--- " or "+++ ", guess the appropriate
 + * p_value for the given patch.
 + */
 +static int guess_p_value(const char *nameline)
 +{
 +      char *name, *cp;
 +      int val = -1;
 +
 +      if (is_dev_null(nameline))
 +              return -1;
 +      name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
 +      if (!name)
 +              return -1;
 +      cp = strchr(name, '/');
 +      if (!cp)
 +              val = 0;
 +      else if (prefix) {
 +              /*
 +               * Does it begin with "a/$our-prefix" and such?  Then this is
 +               * very likely to apply to our directory.
 +               */
 +              if (!strncmp(name, prefix, prefix_length))
 +                      val = count_slashes(prefix);
 +              else {
 +                      cp++;
 +                      if (!strncmp(cp, prefix, prefix_length))
 +                              val = count_slashes(prefix) + 1;
 +              }
 +      }
 +      free(name);
 +      return val;
 +}
 +
  /*
   * Get the name etc info from the --/+++ lines of a traditional patch header
   *
 - * NOTE! This hardcodes "-p1" behaviour in filename detection.
 - *
   * FIXME! The end-of-filename heuristics are kind of screwy. For existing
   * files, we can happily check the index for a match, but for creating a
   * new file we should try to match whatever "patch" does. I have no idea.
@@@ -371,16 -326,6 +371,16 @@@ static void parse_traditional_patch(con
  
        first += 4;     /* skip "--- " */
        second += 4;    /* skip "+++ " */
 +      if (!p_value_known) {
 +              int p, q;
 +              p = guess_p_value(first);
 +              q = guess_p_value(second);
 +              if (p < 0) p = q;
 +              if (0 <= p && p == q) {
 +                      p_value = p;
 +                      p_value_known = 1;
 +              }
 +      }
        if (is_dev_null(first)) {
                patch->is_new = 1;
                patch->is_delete = 0;
@@@ -842,7 -787,6 +842,7 @@@ static int find_header(char *line, unsi
  {
        unsigned long offset, len;
  
 +      patch->is_toplevel_relative = 0;
        patch->is_rename = patch->is_copy = 0;
        patch->is_new = patch->is_delete = -1;
        patch->old_mode = patch->new_mode = 0;
                                        die("git diff header lacks filename information (line %d)", linenr);
                                patch->old_name = patch->new_name = patch->def_name;
                        }
 +                      patch->is_toplevel_relative = 1;
                        *hdrsize = git_hdr_len;
                        return offset;
                }
@@@ -1186,11 -1129,11 +1186,11 @@@ static struct fragment *parse_binary_hu
  
        *status_p = 0;
  
 -      if (!strncmp(buffer, "delta ", 6)) {
 +      if (!prefixcmp(buffer, "delta ")) {
                patch_method = BINARY_DELTA_DEFLATED;
                origlen = strtoul(buffer + 6, NULL, 10);
        }
 -      else if (!strncmp(buffer, "literal ", 8)) {
 +      else if (!prefixcmp(buffer, "literal ")) {
                patch_method = BINARY_LITERAL_DEFLATED;
                origlen = strtoul(buffer + 8, NULL, 10);
        }
@@@ -1450,39 -1393,28 +1450,39 @@@ static void show_stats(struct patch *pa
        free(qname);
  }
  
 -static int read_old_data(struct stat *st, const char *path, void *buf, unsigned long size)
 +static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p)
  {
        int fd;
        unsigned long got;
 +      unsigned long nsize;
 +      char *nbuf;
 +      unsigned long size = *size_p;
 +      char *buf = *buf_p;
  
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
 -              return readlink(path, buf, size);
 +              return readlink(path, buf, size) != size;
        case S_IFREG:
                fd = open(path, O_RDONLY);
                if (fd < 0)
                        return error("unable to open %s", path);
                got = 0;
                for (;;) {
 -                      int ret = xread(fd, (char *) buf + got, size - got);
 +                      int ret = xread(fd, buf + got, size - got);
                        if (ret <= 0)
                                break;
                        got += ret;
                }
                close(fd);
 -              return got;
 -
 +              nsize = got;
 +              nbuf = buf;
 +              if (convert_to_git(path, &nbuf, &nsize)) {
 +                      free(buf);
 +                      *buf_p = nbuf;
 +                      *alloc_p = nsize;
 +                      *size_p = nsize;
 +              }
 +              return got != size;
        default:
                return -1;
        }
@@@ -1607,7 -1539,8 +1607,8 @@@ static int apply_line(char *output, con
        int need_fix_leading_space = 0;
        char *buf;
  
-       if ((new_whitespace != strip_whitespace) || !whitespace_error) {
+       if ((new_whitespace != strip_whitespace) || !whitespace_error ||
+           *patch != '+') {
                memcpy(output, patch + 1, plen);
                return plen;
        }
@@@ -1723,8 -1656,6 +1724,8 @@@ static int apply_one_fragment(struct bu
                        /* Ignore it, we already handled it */
                        break;
                default:
 +                      if (apply_verbosely)
 +                              error("invalid start of line: '%c'", first);
                        return -1;
                }
                patch += len;
                }
        }
  
 +      if (offset && apply_verbosely)
 +              error("while searching for:\n%.*s", oldsize, oldlines);
 +
        free(old);
        free(new);
        return offset;
@@@ -1983,7 -1911,7 +1984,7 @@@ static int apply_data(struct patch *pat
                size = st->st_size;
                alloc = size + 8192;
                buf = xmalloc(alloc);
 -              if (read_old_data(st, patch->old_name, buf, alloc) != size)
 +              if (read_old_data(st, patch->old_name, &buf, &alloc, &size))
                        return error("read of %s failed", patch->old_name);
        }
  
@@@ -2305,7 -2233,7 +2306,7 @@@ static void patch_stats(struct patch *p
        }
  }
  
 -static void remove_file(struct patch *patch)
 +static void remove_file(struct patch *patch, int rmdir_empty)
  {
        if (write_index) {
                if (remove_file_from_cache(patch->old_name) < 0)
                cache_tree_invalidate_path(active_cache_tree, patch->old_name);
        }
        if (!cached) {
 -              if (!unlink(patch->old_name)) {
 +              if (!unlink(patch->old_name) && rmdir_empty) {
                        char *name = xstrdup(patch->old_name);
                        char *end = strrchr(name, '/');
                        while (end) {
@@@ -2355,22 -2283,12 +2356,22 @@@ static void add_index_file(const char *
  static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
  {
        int fd;
 +      char *nbuf;
 +      unsigned long nsize;
  
        if (S_ISLNK(mode))
                /* Although buf:size is counted string, it also is NUL
                 * terminated.
                 */
                return symlink(buf, path);
 +      nsize = size;
 +      nbuf = (char *) buf;
 +      if (convert_to_working_tree(path, &nbuf, &nsize)) {
 +              free((char *) buf);
 +              buf = nbuf;
 +              size = nsize;
 +      }
 +
        fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
        if (fd < 0)
                return -1;
@@@ -2456,7 -2374,7 +2457,7 @@@ static void write_out_one_result(struc
  {
        if (patch->is_delete > 0) {
                if (phase == 0)
 -                      remove_file(patch);
 +                      remove_file(patch, 1);
                return;
        }
        if (patch->is_new > 0 || patch->is_copy) {
         * thing: remove the old, write the new
         */
        if (phase == 0)
 -              remove_file(patch);
 +              remove_file(patch, 0);
        if (phase == 1)
                create_file(patch);
  }
@@@ -2591,32 -2509,6 +2592,32 @@@ static int use_patch(struct patch *p
        return 1;
  }
  
 +static void prefix_one(char **name)
 +{
 +      char *old_name = *name;
 +      if (!old_name)
 +              return;
 +      *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
 +      free(old_name);
 +}
 +
 +static void prefix_patches(struct patch *p)
 +{
 +      if (!prefix || p->is_toplevel_relative)
 +              return;
 +      for ( ; p; p = p->next) {
 +              if (p->new_name == p->old_name) {
 +                      char *prefixed = p->new_name;
 +                      prefix_one(&prefixed);
 +                      p->new_name = p->old_name = prefixed;
 +              }
 +              else {
 +                      prefix_one(&p->new_name);
 +                      prefix_one(&p->old_name);
 +              }
 +      }
 +}
 +
  static int apply_patch(int fd, const char *filename, int inaccurate_eof)
  {
        unsigned long offset, size;
                        break;
                if (apply_in_reverse)
                        reverse_patches(patch);
 +              if (prefix)
 +                      prefix_patches(patch);
                if (use_patch(patch)) {
                        patch_stats(patch);
                        *listp = patch;
                        listp = &patch->next;
 -              } else {
 +              }
 +              else {
                        /* perhaps free it a bit better? */
                        free(patch);
                        skipped_patch++;
@@@ -2707,16 -2596,9 +2708,16 @@@ int cmd_apply(int argc, const char **ar
        int read_stdin = 1;
        int inaccurate_eof = 0;
        int errs = 0;
 +      int is_not_gitdir = 0;
  
        const char *whitespace_option = NULL;
  
 +      prefix = setup_git_directory_gently(&is_not_gitdir);
 +      prefix_length = prefix ? strlen(prefix) : 0;
 +      git_config(git_apply_config);
 +      if (apply_default_whitespace)
 +              parse_whitespace_option(apply_default_whitespace);
 +
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                char *end;
                        read_stdin = 0;
                        continue;
                }
 -              if (!strncmp(arg, "--exclude=", 10)) {
 +              if (!prefixcmp(arg, "--exclude=")) {
                        struct excludes *x = xmalloc(sizeof(*x));
                        x->path = arg + 10;
                        x->next = excludes;
                        excludes = x;
                        continue;
                }
 -              if (!strncmp(arg, "-p", 2)) {
 +              if (!prefixcmp(arg, "-p")) {
                        p_value = atoi(arg + 2);
 +                      p_value_known = 1;
                        continue;
                }
                if (!strcmp(arg, "--no-add")) {
                        continue;
                }
                if (!strcmp(arg, "--index")) {
 +                      if (is_not_gitdir)
 +                              die("--index outside a repository");
                        check_index = 1;
                        continue;
                }
                if (!strcmp(arg, "--cached")) {
 +                      if (is_not_gitdir)
 +                              die("--cached outside a repository");
                        check_index = 1;
                        cached = 1;
                        continue;
                        line_termination = 0;
                        continue;
                }
 -              if (!strncmp(arg, "-C", 2)) {
 +              if (!prefixcmp(arg, "-C")) {
                        p_context = strtoul(arg + 2, &end, 0);
                        if (*end != '\0')
                                die("unrecognized context count '%s'", arg + 2);
                        continue;
                }
 -              if (!strncmp(arg, "--whitespace=", 13)) {
 +              if (!prefixcmp(arg, "--whitespace=")) {
                        whitespace_option = arg + 13;
                        parse_whitespace_option(arg + 13);
                        continue;
                        apply = apply_with_reject = apply_verbosely = 1;
                        continue;
                }
 -              if (!strcmp(arg, "--verbose")) {
 +              if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) {
                        apply_verbosely = 1;
                        continue;
                }
                        inaccurate_eof = 1;
                        continue;
                }
 -
 -              if (check_index && prefix_length < 0) {
 -                      prefix = setup_git_directory();
 -                      prefix_length = prefix ? strlen(prefix) : 0;
 -                      git_config(git_apply_config);
 -                      if (!whitespace_option && apply_default_whitespace)
 -                              parse_whitespace_option(apply_default_whitespace);
 -              }
                if (0 < prefix_length)
                        arg = prefix_filename(prefix, prefix_length, arg);
  
diff --combined builtin-mailinfo.c
index 6ee6b0b26c93b2155a02d2bf7d40c5c2d78519de,cf5ef29c0fa524799675734a3b4355ab326c76aa..766a37ebe2da56f92be3927d6ddfe46dba9386df
@@@ -406,6 -406,11 +406,11 @@@ static int is_rfc2822_header(char *line
         */
        int ch;
        char *cp = line;
+       /* Count mbox From headers as headers */
+       if (!memcmp(line, "From ", 5) || !memcmp(line, ">From ", 6))
+               return 1;
        while ((ch = *cp++)) {
                if (ch == ':')
                        return cp != line;
        return 0;
  }
  
+ /*
+  * sz is size of 'line' buffer in bytes.  Must be reasonably
+  * long enough to hold one physical real-world e-mail line.
+  */
  static int read_one_header_line(char *line, int sz, FILE *in)
  {
-       int ofs = 0;
-       while (ofs < sz) {
-               int peek, len;
-               if (fgets(line + ofs, sz - ofs, in) == NULL)
-                       break;
-               len = eatspace(line + ofs);
-               if ((len == 0) || !is_rfc2822_header(line)) {
-                       /* Re-add the newline */
-                       line[ofs + len] = '\n';
-                       line[ofs + len + 1] = '\0';
-                       break;
-               }
-               ofs += len;
-               /* Yuck, 2822 header "folding" */
+       int len;
+       /*
+        * We will read at most (sz-1) bytes and then potentially
+        * re-add NUL after it.  Accessing line[sz] after this is safe
+        * and we can allow len to grow up to and including sz.
+        */
+       sz--;
+       /* Get the first part of the line. */
+       if (!fgets(line, sz, in))
+               return 0;
+       /*
+        * Is it an empty line or not a valid rfc2822 header?
+        * If so, stop here, and return false ("not a header")
+        */
+       len = eatspace(line);
+       if (!len || !is_rfc2822_header(line)) {
+               /* Re-add the newline */
+               line[len] = '\n';
+               line[len + 1] = '\0';
+               return 0;
+       }
+       /*
+        * Now we need to eat all the continuation lines..
+        * Yuck, 2822 header "folding"
+        */
+       for (;;) {
+               int peek, addlen;
+               static char continuation[1000];
                peek = fgetc(in); ungetc(peek, in);
                if (peek != ' ' && peek != '\t')
                        break;
+               if (!fgets(continuation, sizeof(continuation), in))
+                       break;
+               addlen = eatspace(continuation);
+               if (len < sz - 1) {
+                       if (addlen >= sz - len)
+                               addlen = sz - len - 1;
+                       memcpy(line + len, continuation, addlen);
+                       len += addlen;
+               }
        }
-       /* Count mbox From headers as headers */
-       if (!ofs && (!memcmp(line, "From ", 5) || !memcmp(line, ">From ", 6)))
-               ofs = 1;
-       return ofs;
+       line[len] = 0;
+       return 1;
  }
  
  static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047)
@@@ -811,7 -847,7 +847,7 @@@ int cmd_mailinfo(int argc, const char *
                        metainfo_charset = def_charset;
                else if (!strcmp(argv[1], "-n"))
                        metainfo_charset = NULL;
 -              else if (!strncmp(argv[1], "--encoding=", 11))
 +              else if (!prefixcmp(argv[1], "--encoding="))
                        metainfo_charset = argv[1] + 11;
                else
                        usage(mailinfo_usage);