Merge branch 'lf/setup-prefix-pathspec' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 3 Apr 2013 16:24:18 +0000 (09:24 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 3 Apr 2013 16:24:19 +0000 (09:24 -0700)
"git cmd -- ':(top'" was not diagnosed as an invalid syntax, and
instead the parser kept reading beyond the end of the string.

* lf/setup-prefix-pathspec:
setup.c: check that the pathspec magic ends with ")"
setup.c: stop prefix_pathspec() from looping past the end of string

1  2 
setup.c
diff --combined setup.c
index 1dee47e0850369c87408c540ce2b2251db17be3d,da0d8c80ba47ba9b9085c9fbb8e961712354f332..a2be9690ad3bd8895affe485e67bb7edac4afa9d
+++ b/setup.c
@@@ -1,6 -1,5 +1,6 @@@
  #include "cache.h"
  #include "dir.h"
 +#include "string-list.h"
  
  static int inside_git_dir = -1;
  static int inside_work_tree = -1;
@@@ -66,14 -65,7 +66,14 @@@ int check_filename(const char *prefix, 
        const char *name;
        struct stat st;
  
 -      name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
 +      if (!prefixcmp(arg, ":/")) {
 +              if (arg[2] == '\0') /* ":/" is root dir, always exists */
 +                      return 1;
 +              name = arg + 2;
 +      } else if (prefix)
 +              name = prefix_filename(prefix, strlen(prefix), arg);
 +      else
 +              name = arg;
        if (!lstat(name, &st))
                return 1; /* file exists */
        if (errno == ENOENT || errno == ENOTDIR)
@@@ -207,10 -199,11 +207,11 @@@ static const char *prefix_pathspec(cons
                     *copyfrom && *copyfrom != ')';
                     copyfrom = nextat) {
                        size_t len = strcspn(copyfrom, ",)");
-                       if (copyfrom[len] == ')')
-                               nextat = copyfrom + len;
-                       else
+                       if (copyfrom[len] == ',')
                                nextat = copyfrom + len + 1;
+                       else
+                               /* handle ')' and '\0' */
+                               nextat = copyfrom + len;
                        if (!len)
                                continue;
                        for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
                                die("Invalid pathspec magic '%.*s' in '%s'",
                                    (int) len, copyfrom, elt);
                }
-               if (*copyfrom == ')')
-                       copyfrom++;
+               if (*copyfrom != ')')
+                       die("Missing ')' at the end of pathspec magic in '%s'", elt);
+               copyfrom++;
        } else {
                /* shorthand */
                for (copyfrom = elt + 1;
                return prefix_path(prefix, prefixlen, copyfrom);
  }
  
 +/*
 + * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
 + * based interface - see pathspec_magic above.
 + *
 + * Arguments:
 + *  - prefix - a path relative to the root of the working tree
 + *  - pathspec - a list of paths underneath the prefix path
 + *
 + * Iterates over pathspec, prepending each path with prefix,
 + * and return the resulting list.
 + *
 + * If pathspec is empty, return a singleton list containing prefix.
 + *
 + * If pathspec and prefix are both empty, return an empty list.
 + *
 + * This is typically used by built-in commands such as add.c, in order
 + * to normalize argv arguments provided to the built-in into a list of
 + * paths to process, all relative to the root of the working tree.
 + */
  const char **get_pathspec(const char *prefix, const char **pathspec)
  {
        const char *entry = *pathspec;
@@@ -647,37 -622,6 +649,37 @@@ static dev_t get_device_or_die(const ch
        return buf.st_dev;
  }
  
 +/*
 + * A "string_list_each_func_t" function that canonicalizes an entry
 + * from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
 + * discards it if unusable.  The presence of an empty entry in
 + * GIT_CEILING_DIRECTORIES turns off canonicalization for all
 + * subsequent entries.
 + */
 +static int canonicalize_ceiling_entry(struct string_list_item *item,
 +                                    void *cb_data)
 +{
 +      int *empty_entry_found = cb_data;
 +      char *ceil = item->string;
 +
 +      if (!*ceil) {
 +              *empty_entry_found = 1;
 +              return 0;
 +      } else if (!is_absolute_path(ceil)) {
 +              return 0;
 +      } else if (*empty_entry_found) {
 +              /* Keep entry but do not canonicalize it */
 +              return 1;
 +      } else {
 +              const char *real_path = real_path_if_valid(ceil);
 +              if (!real_path)
 +                      return 0;
 +              free(item->string);
 +              item->string = xstrdup(real_path);
 +              return 1;
 +      }
 +}
 +
  /*
   * We cannot decide in this function whether we are in the work tree or
   * not, since the config can only be read _after_ this function was called.
  static const char *setup_git_directory_gently_1(int *nongit_ok)
  {
        const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
 +      struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
        static char cwd[PATH_MAX+1];
        const char *gitdirenv, *ret;
        char *gitfile;
 -      int len, offset, offset_parent, ceil_offset;
 +      int len, offset, offset_parent, ceil_offset = -1;
        dev_t current_device = 0;
        int one_filesystem = 1;
  
        if (gitdirenv)
                return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
  
 -      ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
 +      if (env_ceiling_dirs) {
 +              int empty_entry_found = 0;
 +
 +              string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
 +              filter_string_list(&ceiling_dirs, 0,
 +                                 canonicalize_ceiling_entry, &empty_entry_found);
 +              ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
 +              string_list_clear(&ceiling_dirs, 0);
 +      }
 +
        if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
                ceil_offset = 1;