Sync with Git 2.13.7
authorJunio C Hamano <gitster@pobox.com>
Tue, 22 May 2018 05:10:49 +0000 (14:10 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 22 May 2018 05:10:49 +0000 (14:10 +0900)
* maint-2.13:
Git 2.13.7
verify_path: disallow symlinks in .gitmodules
update-index: stat updated files earlier
verify_dotfile: mention case-insensitivity in comment
verify_path: drop clever fallthrough
skip_prefix: add case-insensitive variant
is_{hfs,ntfs}_dotgitmodules: add tests
is_ntfs_dotgit: match other .git files
is_hfs_dotgit: match other .git files
is_ntfs_dotgit: use a size_t for traversing string
submodule-config: verify submodule names as paths

1  2 
apply.c
builtin/submodule--helper.c
builtin/update-index.c
cache.h
git-compat-util.h
git-submodule.sh
path.c
read-cache.c
submodule-config.c
submodule-config.h
t/helper/test-path-utils.c
diff --combined apply.c
index 0c7b25989cdf58b411190744c97d93450be9b53e,b96d3755950f09e3c1661b59a3247060388868aa..d92e58f45362e518bf47e86f587bf7e14468e126
+++ b/apply.c
@@@ -8,7 -8,6 +8,7 @@@
   */
  
  #include "cache.h"
 +#include "config.h"
  #include "blob.h"
  #include "delta.h"
  #include "diff.h"
@@@ -80,6 -79,7 +80,6 @@@ int init_apply_state(struct apply_stat
  {
        memset(state, 0, sizeof(*state));
        state->prefix = prefix;
 -      state->prefix_length = state->prefix ? strlen(state->prefix) : 0;
        state->lock_file = lock_file;
        state->newfd = -1;
        state->apply = 1;
@@@ -219,7 -219,6 +219,7 @@@ struct patch 
        unsigned int recount:1;
        unsigned int conflicted_threeway:1;
        unsigned int direct_to_threeway:1;
 +      unsigned int crlf_in_old:1;
        struct fragment *fragments;
        char *result;
        size_t resultsize;
@@@ -764,6 -763,17 +764,6 @@@ static char *find_name_traditional(stru
        return find_name_common(state, line, def, p_value, line + len, 0);
  }
  
 -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.
@@@ -786,11 -796,11 +786,11 @@@ static int guess_p_value(struct apply_s
                 * Does it begin with "a/$our-prefix" and such?  Then this is
                 * very likely to apply to our directory.
                 */
 -              if (!strncmp(name, state->prefix, state->prefix_length))
 +              if (starts_with(name, state->prefix))
                        val = count_slashes(state->prefix);
                else {
                        cp++;
 -                      if (!strncmp(cp, state->prefix, state->prefix_length))
 +                      if (starts_with(cp, state->prefix))
                                val = count_slashes(state->prefix) + 1;
                }
        }
@@@ -1662,19 -1672,6 +1662,19 @@@ static void check_whitespace(struct app
        record_ws_error(state, result, line + 1, len - 2, state->linenr);
  }
  
 +/*
 + * Check if the patch has context lines with CRLF or
 + * the patch wants to remove lines with CRLF.
 + */
 +static void check_old_for_crlf(struct patch *patch, const char *line, int len)
 +{
 +      if (len >= 2 && line[len-1] == '\n' && line[len-2] == '\r') {
 +              patch->ws_rule |= WS_CR_AT_EOL;
 +              patch->crlf_in_old = 1;
 +      }
 +}
 +
 +
  /*
   * Parse a unified diff. Note that this really needs to parse each
   * fragment separately, since the only way to know the difference
@@@ -1725,14 -1722,11 +1725,14 @@@ static int parse_fragment(struct apply_
                        if (!deleted && !added)
                                leading++;
                        trailing++;
 +                      check_old_for_crlf(patch, line, len);
                        if (!state->apply_in_reverse &&
                            state->ws_error_action == correct_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
                        break;
                case '-':
 +                      if (!state->apply_in_reverse)
 +                              check_old_for_crlf(patch, line, len);
                        if (state->apply_in_reverse &&
                            state->ws_error_action != nowarn_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
                        trailing = 0;
                        break;
                case '+':
 +                      if (state->apply_in_reverse)
 +                              check_old_for_crlf(patch, line, len);
                        if (!state->apply_in_reverse &&
                            state->ws_error_action != nowarn_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
@@@ -2107,16 -2099,17 +2107,16 @@@ static int use_patch(struct apply_stat
        int i;
  
        /* Paths outside are not touched regardless of "--include" */
 -      if (0 < state->prefix_length) {
 -              int pathlen = strlen(pathname);
 -              if (pathlen <= state->prefix_length ||
 -                  memcmp(state->prefix, pathname, state->prefix_length))
 +      if (state->prefix && *state->prefix) {
 +              const char *rest;
 +              if (!skip_prefix(pathname, state->prefix, &rest) || !*rest)
                        return 0;
        }
  
        /* See if it matches any of exclude/include rule */
        for (i = 0; i < state->limit_by_name.nr; i++) {
                struct string_list_item *it = &state->limit_by_name.items[i];
 -              if (!wildmatch(it->string, pathname, 0, NULL))
 +              if (!wildmatch(it->string, pathname, 0))
                        return (it->util != NULL);
        }
  
@@@ -2285,11 -2278,8 +2285,11 @@@ static void show_stats(struct apply_sta
                add, pluses, del, minuses);
  }
  
 -static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
 +static int read_old_data(struct stat *st, struct patch *patch,
 +                       const char *path, struct strbuf *buf)
  {
 +      enum safe_crlf safe_crlf = patch->crlf_in_old ?
 +              SAFE_CRLF_KEEP_CRLF : SAFE_CRLF_RENORMALIZE;
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
                if (strbuf_readlink(buf, path, st->st_size) < 0)
        case S_IFREG:
                if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
                        return error(_("unable to open or read %s"), path);
 -              convert_to_git(path, buf->buf, buf->len, buf, 0);
 +              /*
 +               * "git apply" without "--index/--cached" should never look
 +               * at the index; the target file may not have been added to
 +               * the index yet, and we may not even be in any Git repository.
 +               * Pass NULL to convert_to_git() to stress this; the function
 +               * should never look at the index when explicit crlf option
 +               * is given.
 +               */
 +              convert_to_git(NULL, path, buf->buf, buf->len, buf, safe_crlf);
                return 0;
        default:
                return -1;
@@@ -2837,10 -2819,13 +2837,10 @@@ static void update_image(struct apply_s
                img->line_allocated = img->line;
        }
        if (preimage_limit != postimage->nr)
 -              memmove(img->line + applied_pos + postimage->nr,
 -                      img->line + applied_pos + preimage_limit,
 -                      (img->nr - (applied_pos + preimage_limit)) *
 -                      sizeof(*img->line));
 -      memcpy(img->line + applied_pos,
 -             postimage->line,
 -             postimage->nr * sizeof(*img->line));
 +              MOVE_ARRAY(img->line + applied_pos + postimage->nr,
 +                         img->line + applied_pos + preimage_limit,
 +                         img->nr - (applied_pos + preimage_limit));
 +      COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->nr);
        if (!state->allow_overlap)
                for (i = 0; i < postimage->nr; i++)
                        img->line[applied_pos + i].flag |= LINE_PATCHED;
@@@ -3409,7 -3394,6 +3409,7 @@@ static int load_patch_target(struct app
                             struct strbuf *buf,
                             const struct cache_entry *ce,
                             struct stat *st,
 +                           struct patch *patch,
                             const char *name,
                             unsigned expected_mode)
  {
                } else if (has_symlink_leading_path(name, strlen(name))) {
                        return error(_("reading from '%s' beyond a symbolic link"), name);
                } else {
 -                      if (read_old_data(st, name, buf))
 +                      if (read_old_data(st, patch, name, buf))
                                return error(_("failed to read %s"), name);
                }
        }
@@@ -3458,7 -3442,7 +3458,7 @@@ static int load_preimage(struct apply_s
                /* We have a patched copy in memory; use that. */
                strbuf_add(&buf, previous->result, previous->resultsize);
        } else {
 -              status = load_patch_target(state, &buf, ce, st,
 +              status = load_patch_target(state, &buf, ce, st, patch,
                                           patch->old_name, patch->old_mode);
                if (status < 0)
                        return status;
@@@ -3546,7 -3530,7 +3546,7 @@@ static int load_current(struct apply_st
        if (verify_index_match(ce, &st))
                return error(_("%s: does not match index"), name);
  
 -      status = load_patch_target(state, &buf, ce, &st, name, mode);
 +      status = load_patch_target(state, &buf, ce, &st, patch, name, mode);
        if (status < 0)
                return status;
        else if (status)
@@@ -3742,7 -3726,8 +3742,7 @@@ static int check_preimage(struct apply_
   is_new:
        patch->is_new = 1;
        patch->is_delete = 0;
 -      free(patch->old_name);
 -      patch->old_name = NULL;
 +      FREE_AND_NULL(patch->old_name);
        return 0;
  }
  
@@@ -3777,7 -3762,7 +3777,7 @@@ static int check_to_create(struct apply
                        return 0;
  
                return EXISTS_IN_WORKTREE;
 -      } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
 +      } else if (!is_missing_file_error(errno)) {
                return error_errno("%s", new_name);
        }
        return 0;
@@@ -3882,9 -3867,9 +3882,9 @@@ static int check_unsafe_path(struct pat
        if (!patch->is_delete)
                new_name = patch->new_name;
  
-       if (old_name && !verify_path(old_name))
+       if (old_name && !verify_path(old_name, patch->old_mode))
                return error(_("invalid path '%s'"), old_name);
-       if (new_name && !verify_path(new_name))
+       if (new_name && !verify_path(new_name, patch->new_mode))
                return error(_("invalid path '%s'"), new_name);
        return 0;
  }
index 895555c93a3bb86ad5511a2ded2350614732d618,b4b4d29d82896e706be44f8509cb39a6e34037fa..e8ccddd3b1b4473a23a5b50434a140f526f5ca7a
@@@ -1,7 -1,5 +1,7 @@@
  #include "builtin.h"
 +#include "repository.h"
  #include "cache.h"
 +#include "config.h"
  #include "parse-options.h"
  #include "quote.h"
  #include "pathspec.h"
@@@ -234,7 -232,8 +234,7 @@@ static int module_list_compute(int argc
        int i, result = 0;
        char *ps_matched = NULL;
        parse_pathspec(pathspec, 0,
 -                     PATHSPEC_PREFER_FULL |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 +                     PATHSPEC_PREFER_FULL,
                       prefix, argv);
  
        if (pathspec->nr)
@@@ -280,7 -279,7 +280,7 @@@ static void module_list_active(struct m
        for (i = 0; i < list->nr; i++) {
                const struct cache_entry *ce = list->entries[i];
  
 -              if (!is_submodule_initialized(ce->name))
 +              if (!is_submodule_active(the_repository, ce->name))
                        continue;
  
                ALLOC_GROW(active_modules.entries,
@@@ -362,7 -361,7 +362,7 @@@ static void init_submodule(const char *
         *
         * Set active flag for the submodule being initialized
         */
 -      if (!is_submodule_initialized(path)) {
 +      if (!is_submodule_active(the_repository, path)) {
                strbuf_reset(&sb);
                strbuf_addf(&sb, "submodule.%s.active", sub->name);
                git_config_set_gently(sb.buf, "true");
@@@ -817,7 -816,7 +817,7 @@@ static int prepare_to_clone_next_submod
        }
  
        /* Check if the submodule has been initialized. */
 -      if (!is_submodule_initialized(ce->name)) {
 +      if (!is_submodule_active(the_repository, ce->name)) {
                next_submodule_warn_missing(suc, out, displaypath);
                goto cleanup;
        }
@@@ -930,7 -929,7 +930,7 @@@ static int update_clone_task_finished(i
        const struct cache_entry *ce;
        struct submodule_update_clone *suc = suc_cb;
  
 -      int *idxP = *(int**)idx_task_cb;
 +      int *idxP = idx_task_cb;
        int idx = *idxP;
        free(idxP);
  
@@@ -1108,28 -1107,9 +1108,28 @@@ static int resolve_remote_submodule_bra
  static int push_check(int argc, const char **argv, const char *prefix)
  {
        struct remote *remote;
 +      const char *superproject_head;
 +      char *head;
 +      int detached_head = 0;
 +      struct object_id head_oid;
  
 -      if (argc < 2)
 -              die("submodule--helper push-check requires at least 1 argument");
 +      if (argc < 3)
 +              die("submodule--helper push-check requires at least 2 arguments");
 +
 +      /*
 +       * superproject's resolved head ref.
 +       * if HEAD then the superproject is in a detached head state, otherwise
 +       * it will be the resolved head ref.
 +       */
 +      superproject_head = argv[1];
 +      argv++;
 +      argc--;
 +      /* Get the submodule's head ref and determine if it is detached */
 +      head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
 +      if (!head)
 +              die(_("Failed to resolve HEAD as a valid ref."));
 +      if (!strcmp(head, "HEAD"))
 +              detached_head = 1;
  
        /*
         * The remote must be configured.
                        if (rs->pattern || rs->matching)
                                continue;
  
 -                      /*
 -                       * LHS must match a single ref
 -                       * NEEDSWORK: add logic to special case 'HEAD' once
 -                       * working with submodules in a detached head state
 -                       * ceases to be the norm.
 -                       */
 -                      if (count_refspec_match(rs->src, local_refs, NULL) != 1)
 +                      /* LHS must match a single ref */
 +                      switch (count_refspec_match(rs->src, local_refs, NULL)) {
 +                      case 1:
 +                              break;
 +                      case 0:
 +                              /*
 +                               * If LHS matches 'HEAD' then we need to ensure
 +                               * that it matches the same named branch
 +                               * checked out in the superproject.
 +                               */
 +                              if (!strcmp(rs->src, "HEAD")) {
 +                                      if (!detached_head &&
 +                                          !strcmp(head, superproject_head))
 +                                              break;
 +                                      die("HEAD does not match the named branch in the superproject");
 +                              }
 +                      default:
                                die("src refspec '%s' must name a ref",
                                    rs->src);
 +                      }
                }
                free_refspec(refspec_nr, refspec);
        }
 +      free(head);
  
        return 0;
  }
@@@ -1224,9 -1192,32 +1224,32 @@@ static int is_active(int argc, const ch
  
        gitmodules_config();
  
 -      return !is_submodule_initialized(argv[1]);
 +      return !is_submodule_active(the_repository, argv[1]);
  }
  
+ /*
+  * Exit non-zero if any of the submodule names given on the command line is
+  * invalid. If no names are given, filter stdin to print only valid names
+  * (which is primarily intended for testing).
+  */
+ static int check_name(int argc, const char **argv, const char *prefix)
+ {
+       if (argc > 1) {
+               while (*++argv) {
+                       if (check_submodule_name(*argv) < 0)
+                               return 1;
+               }
+       } else {
+               struct strbuf buf = STRBUF_INIT;
+               while (strbuf_getline(&buf, stdin) != EOF) {
+                       if (!check_submodule_name(buf.buf))
+                               printf("%s\n", buf.buf);
+               }
+               strbuf_release(&buf);
+       }
+       return 0;
+ }
  #define SUPPORT_SUPER_PREFIX (1<<0)
  
  struct cmd_struct {
@@@ -1248,13 -1239,15 +1271,14 @@@ static struct cmd_struct commands[] = 
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
        {"is-active", is_active, 0},
+       {"check-name", check_name, 0},
  };
  
  int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
  {
        int i;
 -      if (argc < 2)
 -              die(_("submodule--helper subcommand must be "
 -                    "called with a subcommand"));
 +      if (argc < 2 || !strcmp(argv[1], "-h"))
 +              usage("git submodule--helper <command>");
  
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                if (!strcmp(argv[1], commands[i].cmd)) {
diff --combined builtin/update-index.c
index 56721cf03db23a2f5a1b8e9419422df916d7b00f,19216595fbb917d06d51a42a85d0975d903948a9..dc11661119bffd7fb40cd45741533af31f62268a
@@@ -4,7 -4,6 +4,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
 +#include "config.h"
  #include "lockfile.h"
  #include "quote.h"
  #include "cache-tree.h"
@@@ -258,7 -257,7 +258,7 @@@ static int remove_one_path(const char *
   */
  static int process_lstat_error(const char *path, int err)
  {
 -      if (err == ENOENT || err == ENOTDIR)
 +      if (is_missing_file_error(err))
                return remove_one_path(path);
        return error("lstat(\"%s\"): %s", path, strerror(err));
  }
@@@ -359,10 -358,9 +359,9 @@@ static int process_directory(const cha
        return error("%s: is a directory - add files inside instead", path);
  }
  
- static int process_path(const char *path)
+ static int process_path(const char *path, struct stat *st, int stat_errno)
  {
        int pos, len;
-       struct stat st;
        const struct cache_entry *ce;
  
        len = strlen(path);
         * First things first: get the stat information, to decide
         * what to do about the pathname!
         */
-       if (lstat(path, &st) < 0)
-               return process_lstat_error(path, errno);
+       if (stat_errno)
+               return process_lstat_error(path, stat_errno);
  
-       if (S_ISDIR(st.st_mode))
-               return process_directory(path, len, &st);
+       if (S_ISDIR(st->st_mode))
+               return process_directory(path, len, st);
  
-       return add_one_path(ce, path, len, &st);
+       return add_one_path(ce, path, len, st);
  }
  
  static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
        int size, len, option;
        struct cache_entry *ce;
  
-       if (!verify_path(path))
+       if (!verify_path(path, mode))
                return error("Invalid path '%s'", path);
  
        len = strlen(path);
@@@ -444,7 -442,17 +443,17 @@@ static void chmod_path(char flip, cons
  
  static void update_one(const char *path)
  {
-       if (!verify_path(path)) {
+       int stat_errno = 0;
+       struct stat st;
+       if (mark_valid_only || mark_skip_worktree_only || force_remove)
+               st.st_mode = 0;
+       else if (lstat(path, &st) < 0) {
+               st.st_mode = 0;
+               stat_errno = errno;
+       } /* else stat is valid */
+       if (!verify_path(path, st.st_mode)) {
                fprintf(stderr, "Ignoring path %s\n", path);
                return;
        }
                report("remove '%s'", path);
                return;
        }
-       if (process_path(path))
+       if (process_path(path, &st, stat_errno))
                die("Unable to process path %s", path);
        report("add '%s'", path);
  }
@@@ -535,7 -543,7 +544,7 @@@ static void read_index_info(int nul_ter
                        path_name = uq.buf;
                }
  
-               if (!verify_path(path_name)) {
+               if (!verify_path(path_name, mode)) {
                        fprintf(stderr, "Ignoring path %s\n", path_name);
                        continue;
                }
diff --combined cache.h
index 5cc116ba4221f6655271d867a9bcc445b1bd26ad,5a44f79e263b650472b650b72de3b5430243f273..ffadd5bc7082fa2197d0ce63bb224a635c566de7
+++ b/cache.h
@@@ -11,8 -11,6 +11,8 @@@
  #include "string-list.h"
  #include "pack-revindex.h"
  #include "hash.h"
 +#include "path.h"
 +#include "sha1-array.h"
  
  #ifndef platform_SHA_CTX
  /*
@@@ -464,8 -462,6 +464,8 @@@ static inline enum object_type object_t
   */
  extern const char * const local_repo_env[];
  
 +extern void setup_git_env(void);
 +
  /*
   * Returns true iff we have a configured git repository (either via
   * setup_git_directory, or in the environment via $GIT_DIR).
@@@ -529,15 -525,12 +529,15 @@@ extern void set_git_work_tree(const cha
  
  extern void setup_work_tree(void);
  /*
 - * Find GIT_DIR of the repository that contains the current working directory,
 - * without changing the working directory or other global state. The result is
 - * appended to gitdir. The return value is either NULL if no repository was
 - * found, or pointing to the path inside gitdir's buffer.
 + * Find the commondir and gitdir of the repository that contains the current
 + * working directory, without changing the working directory or other global
 + * state. The result is appended to commondir and gitdir.  If the discovered
 + * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
 + * both have the same result appended to the buffer.  The return value is
 + * either 0 upon success and non-zero if no repository was found.
   */
 -extern const char *discover_git_directory(struct strbuf *gitdir);
 +extern int discover_git_directory(struct strbuf *commondir,
 +                                struct strbuf *gitdir);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
  extern char *prefix_path(const char *prefix, int len, const char *path);
@@@ -604,9 -597,8 +604,9 @@@ extern int read_index_unmerged(struct i
  #define CLOSE_LOCK            (1 << 1)
  extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
  extern int discard_index(struct index_state *);
 +extern void move_index_extensions(struct index_state *dst, struct index_state *src);
  extern int unmerged_index(const struct index_state *);
- extern int verify_path(const char *path);
+ extern int verify_path(const char *path, unsigned mode);
  extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
  extern int index_dir_exists(struct index_state *istate, const char *name, int namelen);
  extern void adjust_dirname_case(struct index_state *istate, char *name);
@@@ -773,6 -765,7 +773,6 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 -extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
  
  /*
   * Include broken refs in all ref iterations, which will
@@@ -894,6 -887,64 +894,6 @@@ extern void check_repository_format(voi
  #define DATA_CHANGED    0x0020
  #define TYPE_CHANGED    0x0040
  
 -/*
 - * Return a statically allocated filename, either generically (mkpath), in
 - * the repository directory (git_path), or in a submodule's repository
 - * directory (git_path_submodule). In all cases, note that the result
 - * may be overwritten by another call to _any_ of the functions. Consider
 - * using the safer "dup" or "strbuf" formats below (in some cases, the
 - * unsafe versions have already been removed).
 - */
 -extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -
 -extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
 -      __attribute__((format (printf, 3, 4)));
 -extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 -                                   const char *fmt, ...)
 -      __attribute__((format (printf, 3, 4)));
 -extern char *git_pathdup(const char *fmt, ...)
 -      __attribute__((format (printf, 1, 2)));
 -extern char *mkpathdup(const char *fmt, ...)
 -      __attribute__((format (printf, 1, 2)));
 -extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -
 -extern void report_linked_checkout_garbage(void);
 -
 -/*
 - * You can define a static memoized git path like:
 - *
 - *    static GIT_PATH_FUNC(git_path_foo, "FOO");
 - *
 - * or use one of the global ones below.
 - */
 -#define GIT_PATH_FUNC(func, filename) \
 -      const char *func(void) \
 -      { \
 -              static char *ret; \
 -              if (!ret) \
 -                      ret = git_pathdup(filename); \
 -              return ret; \
 -      }
 -
 -const char *git_path_cherry_pick_head(void);
 -const char *git_path_revert_head(void);
 -const char *git_path_squash_msg(void);
 -const char *git_path_merge_msg(void);
 -const char *git_path_merge_rr(void);
 -const char *git_path_merge_mode(void);
 -const char *git_path_merge_head(void);
 -const char *git_path_fetch_head(void);
 -const char *git_path_shallow(void);
 -
  /*
   * Return the name of the file in the local object database that would
   * be used to store a loose object with the specified sha1.  The
@@@ -939,7 -990,14 +939,7 @@@ extern const struct object_id null_oid
  
  static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
  {
 -      int i;
 -
 -      for (i = 0; i < GIT_SHA1_RAWSZ; i++, sha1++, sha2++) {
 -              if (*sha1 != *sha2)
 -                      return *sha1 - *sha2;
 -      }
 -
 -      return 0;
 +      return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
  }
  
  static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
@@@ -967,13 -1025,6 +967,13 @@@ static inline void oidcpy(struct object
        hashcpy(dst->hash, src->hash);
  }
  
 +static inline struct object_id *oiddup(const struct object_id *src)
 +{
 +      struct object_id *dst = xmalloc(sizeof(struct object_id));
 +      oidcpy(dst, src);
 +      return dst;
 +}
 +
  static inline void hashclr(unsigned char *hash)
  {
        memset(hash, 0, GIT_SHA1_RAWSZ);
@@@ -1137,7 -1188,15 +1137,15 @@@ int normalize_path_copy(char *dst, cons
  int longest_ancestor_length(const char *path, struct string_list *prefixes);
  char *strip_path_suffix(const char *path, const char *suffix);
  int daemon_avoid_alias(const char *path);
- extern int is_ntfs_dotgit(const char *name);
+ /*
+  * These functions match their is_hfs_dotgit() counterparts; see utf8.h for
+  * details.
+  */
+ int is_ntfs_dotgit(const char *name);
+ int is_ntfs_dotgitmodules(const char *name);
+ int is_ntfs_dotgitignore(const char *name);
+ int is_ntfs_dotgitattributes(const char *name);
  
  /*
   * Returns true iff "str" could be confused as a command-line option when
@@@ -1161,12 -1220,13 +1169,12 @@@ extern char *xdg_config_home(const cha
   */
  extern char *xdg_cache_home(const char *filename);
  
 -/* object replacement */
 -#define LOOKUP_REPLACE_OBJECT 1
 -#define LOOKUP_UNKNOWN_OBJECT 2
 -extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
 +extern void *read_sha1_file_extended(const unsigned char *sha1,
 +                                   enum object_type *type,
 +                                   unsigned long *size, int lookup_replace);
  static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
 -      return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
 +      return read_sha1_file_extended(sha1, type, size, 1);
  }
  
  /*
@@@ -1188,6 -1248,13 +1196,6 @@@ static inline const unsigned char *look
        return do_lookup_replace_object(sha1);
  }
  
 -static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
 -{
 -      if (!(flag & LOOKUP_REPLACE_OBJECT))
 -              return sha1;
 -      return lookup_replace_object(sha1);
 -}
 -
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
@@@ -1224,10 -1291,15 +1232,10 @@@ int read_loose_object(const char *path
                      void **contents);
  
  /*
 - * Return true iff we have an object named sha1, whether local or in
 - * an alternate object database, and whether packed or loose.  This
 - * function does not respect replace references.
 - *
 - * If the QUICK flag is set, do not re-check the pack directory
 - * when we cannot find the object (this means we may give a false
 - * negative answer if another process is simultaneously repacking).
 + * Convenience for sha1_object_info_extended() with a NULL struct
 + * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass
 + * nonzero flags to also set other flags.
   */
 -#define HAS_SHA1_QUICK 0x1
  extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
  static inline int has_sha1_file(const unsigned char *sha1)
  {
@@@ -1264,8 -1336,8 +1272,8 @@@ static inline unsigned int hexval(unsig
   */
  static inline int hex2chr(const char *s)
  {
 -      int val = hexval(s[0]);
 -      return (val < 0) ? val : (val << 4) | hexval(s[1]);
 +      unsigned int val = hexval(s[0]);
 +      return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
  }
  
  /* Convert to/from hex/sha1 representation */
@@@ -1429,18 -1501,18 +1437,18 @@@ struct date_mode 
  #define DATE_MODE(t) date_mode_from_type(DATE_##t)
  struct date_mode *date_mode_from_type(enum date_mode_type type);
  
 -const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
 -void show_date_relative(unsigned long time, int tz, const struct timeval *now,
 +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
 +void show_date_relative(timestamp_t time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
  int parse_date(const char *date, struct strbuf *out);
 -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
 -int parse_expiry_date(const char *date, unsigned long *timestamp);
 +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);
 +int parse_expiry_date(const char *date, timestamp_t *timestamp);
  void datestamp(struct strbuf *out);
  #define approxidate(s) approxidate_careful((s), NULL)
 -unsigned long approxidate_careful(const char *, int *);
 -unsigned long approxidate_relative(const char *date, const struct timeval *now);
 +timestamp_t approxidate_careful(const char *, int *);
 +timestamp_t approxidate_relative(const char *date, const struct timeval *now);
  void parse_date_format(const char *format, struct date_mode *mode);
 -int date_overflows(unsigned long date);
 +int date_overflows(timestamp_t date);
  
  #define IDENT_STRICT         1
  #define IDENT_NO_DATE        2
@@@ -1493,7 -1565,6 +1501,7 @@@ struct checkout 
        struct index_state *istate;
        const char *base_dir;
        int base_dir_len;
 +      struct delayed_checkout *delayed_checkout;
        unsigned force:1,
                 quiet:1,
                 not_new:1,
  
  #define TEMPORARY_FILENAME_LENGTH 25
  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
 +extern void enable_delayed_checkout(struct checkout *state);
 +extern int finish_delayed_checkout(struct checkout *state);
  
  struct cache_def {
        struct strbuf path;
@@@ -1532,19 -1601,10 +1540,19 @@@ extern struct alternate_object_databas
        struct strbuf scratch;
        size_t base_len;
  
 +      /*
 +       * Used to store the results of readdir(3) calls when searching
 +       * for unique abbreviated hashes.  This cache is never
 +       * invalidated, thus it's racy and not necessarily accurate.
 +       * That's fine for its purpose; don't use it for tasks requiring
 +       * greater accuracy!
 +       */
 +      char loose_objects_subdir_seen[256];
 +      struct oid_array loose_objects_cache;
 +
        char path[FLEX_ARRAY];
  } *alt_odb_list;
  extern void prepare_alt_odb(void);
 -extern void read_info_alternates(const char * relative_base, int depth);
  extern char *compute_alternate_path(const char *path, struct strbuf *err);
  typedef int alt_odb_fn(struct alternate_object_database *, void *);
  extern int foreach_alt_odb(alt_odb_fn, void*);
@@@ -1756,15 -1816,9 +1764,15 @@@ typedef int each_loose_object_fn(const 
  typedef int each_loose_cruft_fn(const char *basename,
                                const char *path,
                                void *data);
 -typedef int each_loose_subdir_fn(int nr,
 +typedef int each_loose_subdir_fn(unsigned int nr,
                                 const char *path,
                                 void *data);
 +int for_each_file_in_obj_subdir(unsigned int subdir_nr,
 +                              struct strbuf *path,
 +                              each_loose_object_fn obj_cb,
 +                              each_loose_cruft_fn cruft_cb,
 +                              each_loose_subdir_fn subdir_cb,
 +                              void *data);
  int for_each_loose_file_in_objdir(const char *path,
                                  each_loose_object_fn obj_cb,
                                  each_loose_cruft_fn cruft_cb,
@@@ -1796,7 -1850,6 +1804,7 @@@ struct object_info 
        off_t *disk_sizep;
        unsigned char *delta_base_sha1;
        struct strbuf *typename;
 +      void **contentp;
  
        /* Response */
        enum {
   */
  #define OBJECT_INFO_INIT {NULL}
  
 +/* Invoke lookup_replace_object() on the given hash */
 +#define OBJECT_INFO_LOOKUP_REPLACE 1
 +/* Allow reading from a loose object file of unknown/bogus type */
 +#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
 +/* Do not check cached storage */
 +#define OBJECT_INFO_SKIP_CACHED 4
 +/* Do not retry packed storage after checking packed and loose storage */
 +#define OBJECT_INFO_QUICK 8
  extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
  extern int packed_object_info(struct packed_git *pack, off_t offset, struct object_info *);
  
  /* Dumb servers support */
  extern int update_server_info(int);
  
 -/* git_config_parse_key() returns these negated: */
 -#define CONFIG_INVALID_KEY 1
 -#define CONFIG_NO_SECTION_OR_NAME 2
 -/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
 -#define CONFIG_NO_LOCK -1
 -#define CONFIG_INVALID_FILE 3
 -#define CONFIG_NO_WRITE 4
 -#define CONFIG_NOTHING_SET 5
 -#define CONFIG_INVALID_PATTERN 6
 -#define CONFIG_GENERIC_ERROR 7
 -
 -#define CONFIG_REGEX_NONE ((void *)1)
 -
 -struct git_config_source {
 -      unsigned int use_stdin:1;
 -      const char *file;
 -      const char *blob;
 -};
 -
 -enum config_origin_type {
 -      CONFIG_ORIGIN_BLOB,
 -      CONFIG_ORIGIN_FILE,
 -      CONFIG_ORIGIN_STDIN,
 -      CONFIG_ORIGIN_SUBMODULE_BLOB,
 -      CONFIG_ORIGIN_CMDLINE
 -};
 -
 -struct config_options {
 -      unsigned int respect_includes : 1;
 -      const char *git_dir;
 -};
 -
 -typedef int (*config_fn_t)(const char *, const char *, void *);
 -extern int git_default_config(const char *, const char *, void *);
 -extern int git_config_from_file(config_fn_t fn, const char *, void *);
 -extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
 -                                      const char *name, const char *buf, size_t len, void *data);
 -extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
 -                                   const unsigned char *sha1, void *data);
 -extern void git_config_push_parameter(const char *text);
 -extern int git_config_from_parameters(config_fn_t fn, void *data);
 -extern void read_early_config(config_fn_t cb, void *data);
 -extern void git_config(config_fn_t fn, void *);
 -extern int git_config_with_options(config_fn_t fn, void *,
 -                                 struct git_config_source *config_source,
 -                                 const struct config_options *opts);
 -extern int git_parse_ulong(const char *, unsigned long *);
 -extern int git_parse_maybe_bool(const char *);
 -extern int git_config_int(const char *, const char *);
 -extern int64_t git_config_int64(const char *, const char *);
 -extern unsigned long git_config_ulong(const char *, const char *);
 -extern ssize_t git_config_ssize_t(const char *, const char *);
 -extern int git_config_bool_or_int(const char *, const char *, int *);
 -extern int git_config_bool(const char *, const char *);
 -extern int git_config_maybe_bool(const char *, const char *);
 -extern int git_config_string(const char **, const char *, const char *);
 -extern int git_config_pathname(const char **, const char *, const char *);
 -extern int git_config_set_in_file_gently(const char *, const char *, const char *);
 -extern void git_config_set_in_file(const char *, const char *, const char *);
 -extern int git_config_set_gently(const char *, const char *);
 -extern void git_config_set(const char *, const char *);
 -extern int git_config_parse_key(const char *, char **, int *);
 -extern int git_config_key_is_valid(const char *key);
 -extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);
 -extern void git_config_set_multivar(const char *, const char *, const char *, int);
 -extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
 -extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
 -extern int git_config_rename_section(const char *, const char *);
 -extern int git_config_rename_section_in_file(const char *, const char *, const char *);
 -extern const char *git_etc_gitconfig(void);
 -extern int git_env_bool(const char *, int);
 -extern unsigned long git_env_ulong(const char *, unsigned long);
 -extern int git_config_system(void);
 -extern int config_error_nonbool(const char *);
 -#if defined(__GNUC__)
 -#define config_error_nonbool(s) (config_error_nonbool(s), const_error())
 -#endif
  extern const char *get_log_output_encoding(void);
  extern const char *get_commit_output_encoding(void);
  
 -extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 -
 -enum config_scope {
 -      CONFIG_SCOPE_UNKNOWN = 0,
 -      CONFIG_SCOPE_SYSTEM,
 -      CONFIG_SCOPE_GLOBAL,
 -      CONFIG_SCOPE_REPO,
 -      CONFIG_SCOPE_CMDLINE,
 -};
 -
 -extern enum config_scope current_config_scope(void);
 -extern const char *current_config_origin_type(void);
 -extern const char *current_config_name(void);
 -
 -struct config_include_data {
 -      int depth;
 -      config_fn_t fn;
 -      void *data;
 -      const struct config_options *opts;
 -};
 -#define CONFIG_INCLUDE_INIT { 0 }
 -extern int git_config_include(const char *name, const char *value, void *data);
 -
 -/*
 - * Match and parse a config key of the form:
 - *
 - *   section.(subsection.)?key
 - *
 - * (i.e., what gets handed to a config_fn_t). The caller provides the section;
 - * we return -1 if it does not match, 0 otherwise. The subsection and key
 - * out-parameters are filled by the function (and *subsection is NULL if it is
 - * missing).
 - *
 - * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if
 - * there is no subsection at all.
 - */
 -extern int parse_config_key(const char *var,
 -                          const char *section,
 -                          const char **subsection, int *subsection_len,
 -                          const char **key);
 -
 -struct config_set_element {
 -      struct hashmap_entry ent;
 -      char *key;
 -      struct string_list value_list;
 -};
 -
 -struct configset_list_item {
 -      struct config_set_element *e;
 -      int value_index;
 -};
 -
 -/*
 - * the contents of the list are ordered according to their
 - * position in the config files and order of parsing the files.
 - * (i.e. key-value pair at the last position of .git/config will
 - * be at the last item of the list)
 - */
 -struct configset_list {
 -      struct configset_list_item *items;
 -      unsigned int nr, alloc;
 -};
 -
 -struct config_set {
 -      struct hashmap config_hash;
 -      int hash_initialized;
 -      struct configset_list list;
 -};
 -
 -extern void git_configset_init(struct config_set *cs);
 -extern int git_configset_add_file(struct config_set *cs, const char *filename);
 -extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);
 -extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
 -extern void git_configset_clear(struct config_set *cs);
 -extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
 -extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
 -extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
 -extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
 -extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
 -
 -extern int git_config_get_value(const char *key, const char **value);
 -extern const struct string_list *git_config_get_value_multi(const char *key);
 -extern void git_config_clear(void);
 -extern void git_config_iter(config_fn_t fn, void *data);
 -extern int git_config_get_string_const(const char *key, const char **dest);
 -extern int git_config_get_string(const char *key, char **dest);
 -extern int git_config_get_int(const char *key, int *dest);
 -extern int git_config_get_ulong(const char *key, unsigned long *dest);
 -extern int git_config_get_bool(const char *key, int *dest);
 -extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
 -extern int git_config_get_maybe_bool(const char *key, int *dest);
 -extern int git_config_get_pathname(const char *key, const char **dest);
 -extern int git_config_get_untracked_cache(void);
 -extern int git_config_get_split_index(void);
 -extern int git_config_get_max_percent_split_change(void);
 -
 -/* This dies if the configured or default date is in the future */
 -extern int git_config_get_expiry(const char *key, const char **output);
 -
  /*
   * This is a hack for test programs like test-dump-untracked-cache to
   * ensure that they do not modify the untracked cache when reading it.
   */
  extern int ignore_untracked_cache_config;
  
 -struct key_value_info {
 -      const char *filename;
 -      int linenr;
 -      enum config_origin_type origin_type;
 -      enum config_scope scope;
 -};
 -
 -extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
 -extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
 -
  extern int committer_ident_sufficiently_given(void);
  extern int author_ident_sufficiently_given(void);
  
@@@ -1967,8 -2201,7 +1975,8 @@@ extern int ws_blank_line(const char *li
  #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
  
  /* ls-files */
 -void overlay_tree_on_cache(const char *tree_name, const char *prefix);
 +void overlay_tree_on_index(struct index_state *istate,
 +                         const char *tree_name, const char *prefix);
  
  char *alias_lookup(const char *alias);
  int split_cmdline(char *cmdline, const char ***argv);
@@@ -1987,8 -2220,8 +1995,8 @@@ struct commit_list
  int try_merge_command(const char *strategy, size_t xopts_nr,
                const char **xopts, struct commit_list *common,
                const char *head_arg, struct commit_list *remotes);
 -int checkout_fast_forward(const unsigned char *from,
 -                        const unsigned char *to,
 +int checkout_fast_forward(const struct object_id *from,
 +                        const struct object_id *to,
                          int overwrite_ignore);
  
  
diff --combined git-compat-util.h
index bf4869dcef39b12dcb650d5fc4a87ace8ea91848,4be15e5eb233ffdfbce17826c20e841e56f14630..6cb3c2f19eb5a0822ae17a1b1e1abc08d3de25e4
@@@ -322,11 -322,6 +322,11 @@@ extern char *gitdirname(char *)
  #define PRIo32 "o"
  #endif
  
 +typedef uintmax_t timestamp_t;
 +#define PRItime PRIuMAX
 +#define parse_timestamp strtoumax
 +#define TIME_MAX UINTMAX_MAX
 +
  #ifndef PATH_SEP
  #define PATH_SEP ':'
  #endif
@@@ -623,7 -618,7 +623,7 @@@ extern int git_lstat(const char *, stru
  #endif
  
  #define DEFAULT_PACKED_GIT_LIMIT \
 -      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? 8192 : 256))
 +      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? (32 * 1024L * 1024L) : 256))
  
  #ifdef NO_PREAD
  #define pread git_pread
@@@ -696,12 -691,10 +696,12 @@@ char *gitstrdup(const char *s)
  #endif
  
  #ifdef FREAD_READS_DIRECTORIES
 -#ifdef fopen
 -#undef fopen
 -#endif
 -#define fopen(a,b) git_fopen(a,b)
 +# if !defined(SUPPRESS_FOPEN_REDEFINITION)
 +#  ifdef fopen
 +#   undef fopen
 +#  endif
 +#  define fopen(a,b) git_fopen(a,b)
 +# endif
  extern FILE *git_fopen(const char*, const char*);
  #endif
  
@@@ -809,13 -802,6 +809,13 @@@ extern int xmkstemp(char *template)
  extern int xmkstemp_mode(char *template, int mode);
  extern char *xgetcwd(void);
  extern FILE *fopen_for_writing(const char *path);
 +extern FILE *fopen_or_warn(const char *path, const char *mode);
 +
 +/*
 + * FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note
 + * that ptr is used twice, so don't pass e.g. ptr++.
 + */
 +#define FREE_AND_NULL(p) do { free(p); (p) = NULL; } while (0)
  
  #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))
  #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
@@@ -828,14 -814,6 +828,14 @@@ static inline void copy_array(void *dst
                memcpy(dst, src, st_mult(size, n));
  }
  
 +#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
 +      BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
 +static inline void move_array(void *dst, const void *src, size_t n, size_t size)
 +{
 +      if (n)
 +              memmove(dst, src, st_mult(size, n));
 +}
 +
  /*
   * These functions help you allocate structs with flex arrays, and copy
   * the data directly into the array. For example, if you had:
@@@ -900,11 -878,9 +900,11 @@@ static inline char *xstrdup_or_null(con
  
  static inline size_t xsize_t(off_t len)
  {
 -      if (len > (size_t) len)
 +      size_t size = (size_t) len;
 +
 +      if (len != (off_t) size)
                die("Cannot handle files this big");
 -      return (size_t)len;
 +      return size;
  }
  
  __attribute__((format (printf, 3, 4)))
@@@ -980,6 -956,23 +980,23 @@@ static inline int sane_iscase(int x, in
                return (x & 0x20) == 0;
  }
  
+ /*
+  * Like skip_prefix, but compare case-insensitively. Note that the comparison
+  * is done via tolower(), so it is strictly ASCII (no multi-byte characters or
+  * locale-specific conversions).
+  */
+ static inline int skip_iprefix(const char *str, const char *prefix,
+                              const char **out)
+ {
+       do {
+               if (!*prefix) {
+                       *out = str;
+                       return 1;
+               }
+       } while (tolower(*str++) == tolower(*prefix++));
+       return 0;
+ }
  static inline int strtoul_ui(char const *s, int base, unsigned int *result)
  {
        unsigned long ul;
@@@ -1132,8 -1125,8 +1149,8 @@@ int remove_or_warn(unsigned int mode, c
  int access_or_warn(const char *path, int mode, unsigned flag);
  int access_or_die(const char *path, int mode, unsigned flag);
  
 -/* Warn on an inaccessible file that ought to be accessible */
 -void warn_on_inaccessible(const char *path);
 +/* Warn on an inaccessible file if errno indicates this is an error */
 +int warn_on_fopen_errors(const char *path);
  
  #ifdef GMTIME_UNRELIABLE_ERRORS
  struct tm *git_gmtime(const time_t *);
@@@ -1156,21 -1149,6 +1173,21 @@@ struct tm *git_gmtime_r(const time_t *
  #define getc_unlocked(fh) getc(fh)
  #endif
  
 +/*
 + * Our code often opens a path to an optional file, to work on its
 + * contents when we can successfully open it.  We can ignore a failure
 + * to open if such an optional file does not exist, but we do want to
 + * report a failure in opening for other reasons (e.g. we got an I/O
 + * error, or the file is there, but we lack the permission to open).
 + *
 + * Call this function after seeing an error from open() or fopen() to
 + * see if the errno indicates a missing file that we can safely ignore.
 + */
 +static inline int is_missing_file_error(int errno_)
 +{
 +      return (errno_ == ENOENT || errno_ == ENOTDIR);
 +}
 +
  extern int cmd_main(int, const char **);
  
  #endif
diff --combined git-submodule.sh
index 66d1ae8ef6c5f12c856a2f88eabce515dcafd489,92750b9e2fc54a451f7fe9dad42737861e47dbb7..8f260fbd9ca4a38ce78d8a29957cabbe3e26fb4b
@@@ -213,8 -213,7 +213,8 @@@ cmd_add(
                die "$(eval_gettext "'\$sm_path' already exists in the index and is not a submodule")"
        fi
  
 -      if test -z "$force" && ! git add --dry-run --ignore-missing "$sm_path" > /dev/null 2>&1
 +      if test -z "$force" &&
 +              ! git add --dry-run --ignore-missing --no-warn-embedded-repo "$sm_path" > /dev/null 2>&1
        then
                eval_gettextln "The following path is ignored by one of your .gitignore files:
  \$sm_path
@@@ -229,6 -228,11 +229,11 @@@ Use -f if you really want to add it." >
                sm_name="$sm_path"
        fi
  
+       if ! git submodule--helper check-name "$sm_name"
+       then
+               die "$(eval_gettext "'$sm_name' is not a valid submodule name")"
+       fi
        # perhaps the path exists and is already a git repo, else clone it
        if test -e "$sm_path"
        then
@@@ -268,7 -272,7 +273,7 @@@ or you are unsure what this means choos
        fi
        git config submodule."$sm_name".url "$realrepo"
  
 -      git add $force "$sm_path" ||
 +      git add --no-warn-embedded-repo $force "$sm_path" ||
        die "$(eval_gettext "Failed to add submodule '\$sm_path'")"
  
        git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
@@@ -611,6 -615,7 +616,6 @@@ cmd_update(
                die_if_unmatched "$mode" "$sha1"
  
                name=$(git submodule--helper name "$sm_path") || exit
 -              url=$(git config submodule."$name".url)
                if ! test -z "$update"
                then
                        update_module=$update
@@@ -863,7 -868,7 +868,7 @@@ cmd_summary() 
                                test $status != A && test $ignore_config = all && continue
                        fi
                        # Also show added or modified modules which are checked out
 -                      GIT_DIR="$sm_path/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
 +                      GIT_DIR="$sm_path/.git" git rev-parse --git-dir >/dev/null 2>&1 &&
                        printf '%s\n' "$sm_path"
                done
        )
                missing_dst=
  
                test $mod_src = 160000 &&
 -              ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
 +              ! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_src^0 >/dev/null &&
                missing_src=t
  
                test $mod_dst = 160000 &&
 -              ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
 +              ! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_dst^0 >/dev/null &&
                missing_dst=t
  
                display_name=$(git submodule--helper relative-path "$name" "$wt_prefix")
diff --combined path.c
index 335d4dd8777bccfe84415f8d8b738a9a844e248d,c72062574599f7bc312b404a817f9603384fd49c..9ac0531a29b94e7d83c52c172d566a0e243e0025
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -2,13 -2,11 +2,13 @@@
   * Utilities for paths and pathnames
   */
  #include "cache.h"
 +#include "repository.h"
  #include "strbuf.h"
  #include "string-list.h"
  #include "dir.h"
  #include "worktree.h"
  #include "submodule-config.h"
 +#include "path.h"
  
  static int get_st_mode_bits(const char *path, int *mode)
  {
@@@ -33,10 -31,11 +33,10 @@@ static struct strbuf *get_pathname(void
        return sb;
  }
  
 -static char *cleanup_path(char *path)
 +static const char *cleanup_path(const char *path)
  {
        /* Clean it up */
 -      if (!memcmp(path, "./", 2)) {
 -              path += 2;
 +      if (skip_prefix(path, "./", &path)) {
                while (*path == '/')
                        path++;
        }
@@@ -45,7 -44,7 +45,7 @@@
  
  static void strbuf_cleanup_path(struct strbuf *sb)
  {
 -      char *path = cleanup_path(sb->buf);
 +      const char *path = cleanup_path(sb->buf);
        if (path > sb->buf)
                strbuf_remove(sb, 0, path - sb->buf);
  }
@@@ -62,7 -61,7 +62,7 @@@ char *mksnpath(char *buf, size_t n, con
                strlcpy(buf, bad_path, n);
                return buf;
        }
 -      return cleanup_path(buf);
 +      return (char *)cleanup_path(buf);
  }
  
  static int dir_prefix(const char *buf, const char *dir)
@@@ -344,6 -343,8 +344,6 @@@ static void update_common_dir(struct st
  {
        char *base = buf->buf + git_dir_len;
        init_common_trie();
 -      if (!common_dir)
 -              common_dir = get_git_common_dir();
        if (trie_find(&common_trie, base, check_common, NULL) > 0)
                replace_dir(buf, git_dir_len, common_dir);
  }
@@@ -354,7 -355,7 +354,7 @@@ void report_linked_checkout_garbage(voi
        const struct common_dir *p;
        int len;
  
 -      if (!git_common_dir_env)
 +      if (!the_repository->different_commondir)
                return;
        strbuf_addf(&sb, "%s/", get_git_dir());
        len = sb.len;
        strbuf_release(&sb);
  }
  
 -static void adjust_git_path(struct strbuf *buf, int git_dir_len)
 +static void adjust_git_path(const struct repository *repo,
 +                          struct strbuf *buf, int git_dir_len)
  {
        const char *base = buf->buf + git_dir_len;
 -      if (git_graft_env && is_dir_file(base, "info", "grafts"))
 +      if (is_dir_file(base, "info", "grafts"))
                strbuf_splice(buf, 0, buf->len,
 -                            get_graft_file(), strlen(get_graft_file()));
 -      else if (git_index_env && !strcmp(base, "index"))
 +                            repo->graft_file, strlen(repo->graft_file));
 +      else if (!strcmp(base, "index"))
                strbuf_splice(buf, 0, buf->len,
 -                            get_index_file(), strlen(get_index_file()));
 -      else if (git_db_env && dir_prefix(base, "objects"))
 -              replace_dir(buf, git_dir_len + 7, get_object_directory());
 +                            repo->index_file, strlen(repo->index_file));
 +      else if (dir_prefix(base, "objects"))
 +              replace_dir(buf, git_dir_len + 7, repo->objectdir);
        else if (git_hooks_path && dir_prefix(base, "hooks"))
                replace_dir(buf, git_dir_len + 5, git_hooks_path);
 -      else if (git_common_dir_env)
 -              update_common_dir(buf, git_dir_len, NULL);
 +      else if (repo->different_commondir)
 +              update_common_dir(buf, git_dir_len, repo->commondir);
  }
  
 -static void do_git_path(const struct worktree *wt, struct strbuf *buf,
 +static void strbuf_worktree_gitdir(struct strbuf *buf,
 +                                 const struct repository *repo,
 +                                 const struct worktree *wt)
 +{
 +      if (!wt)
 +              strbuf_addstr(buf, repo->gitdir);
 +      else if (!wt->id)
 +              strbuf_addstr(buf, repo->commondir);
 +      else
 +              strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
 +}
 +
 +static void do_git_path(const struct repository *repo,
 +                      const struct worktree *wt, struct strbuf *buf,
                        const char *fmt, va_list args)
  {
        int gitdir_len;
 -      strbuf_addstr(buf, get_worktree_git_dir(wt));
 +      strbuf_worktree_gitdir(buf, repo, wt);
        if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
                strbuf_addch(buf, '/');
        gitdir_len = buf->len;
        strbuf_vaddf(buf, fmt, args);
 -      adjust_git_path(buf, gitdir_len);
 +      if (!wt)
 +              adjust_git_path(repo, buf, gitdir_len);
        strbuf_cleanup_path(buf);
  }
  
 +char *repo_git_path(const struct repository *repo,
 +                  const char *fmt, ...)
 +{
 +      struct strbuf path = STRBUF_INIT;
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_path(repo, NULL, &path, fmt, args);
 +      va_end(args);
 +      return strbuf_detach(&path, NULL);
 +}
 +
 +void strbuf_repo_git_path(struct strbuf *sb,
 +                        const struct repository *repo,
 +                        const char *fmt, ...)
 +{
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_path(repo, NULL, sb, fmt, args);
 +      va_end(args);
 +}
 +
  char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
  {
        va_list args;
        strbuf_reset(buf);
        va_start(args, fmt);
 -      do_git_path(NULL, buf, fmt, args);
 +      do_git_path(the_repository, NULL, buf, fmt, args);
        va_end(args);
        return buf->buf;
  }
@@@ -450,7 -415,7 +450,7 @@@ void strbuf_git_path(struct strbuf *sb
  {
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, sb, fmt, args);
 +      do_git_path(the_repository, NULL, sb, fmt, args);
        va_end(args);
  }
  
@@@ -459,7 -424,7 +459,7 @@@ const char *git_path(const char *fmt, .
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, pathname, fmt, args);
 +      do_git_path(the_repository, NULL, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
@@@ -469,7 -434,7 +469,7 @@@ char *git_pathdup(const char *fmt, ...
        struct strbuf path = STRBUF_INIT;
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, &path, fmt, args);
 +      do_git_path(the_repository, NULL, &path, fmt, args);
        va_end(args);
        return strbuf_detach(&path, NULL);
  }
@@@ -500,52 -465,11 +500,52 @@@ const char *worktree_git_path(const str
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_path(wt, pathname, fmt, args);
 +      do_git_path(the_repository, wt, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
  
 +static void do_worktree_path(const struct repository *repo,
 +                           struct strbuf *buf,
 +                           const char *fmt, va_list args)
 +{
 +      strbuf_addstr(buf, repo->worktree);
 +      if(buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
 +              strbuf_addch(buf, '/');
 +
 +      strbuf_vaddf(buf, fmt, args);
 +      strbuf_cleanup_path(buf);
 +}
 +
 +char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
 +{
 +      struct strbuf path = STRBUF_INIT;
 +      va_list args;
 +
 +      if (!repo->worktree)
 +              return NULL;
 +
 +      va_start(args, fmt);
 +      do_worktree_path(repo, &path, fmt, args);
 +      va_end(args);
 +
 +      return strbuf_detach(&path, NULL);
 +}
 +
 +void strbuf_repo_worktree_path(struct strbuf *sb,
 +                             const struct repository *repo,
 +                             const char *fmt, ...)
 +{
 +      va_list args;
 +
 +      if (!repo->worktree)
 +              return;
 +
 +      va_start(args, fmt);
 +      do_worktree_path(repo, sb, fmt, args);
 +      va_end(args);
 +}
 +
  /* Returns 0 on success, negative on failure. */
  static int do_submodule_path(struct strbuf *buf, const char *path,
                             const char *fmt, va_list args)
@@@ -600,12 -524,11 +600,12 @@@ int strbuf_git_path_submodule(struct st
        return err;
  }
  
 -static void do_git_common_path(struct strbuf *buf,
 +static void do_git_common_path(const struct repository *repo,
 +                             struct strbuf *buf,
                               const char *fmt,
                               va_list args)
  {
 -      strbuf_addstr(buf, get_git_common_dir());
 +      strbuf_addstr(buf, repo->commondir);
        if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
                strbuf_addch(buf, '/');
        strbuf_vaddf(buf, fmt, args);
@@@ -617,27 -540,24 +617,27 @@@ const char *git_common_path(const char 
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_common_path(pathname, fmt, args);
 +      do_git_common_path(the_repository, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
  
 -void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 +void strbuf_git_common_path(struct strbuf *sb,
 +                          const struct repository *repo,
 +                          const char *fmt, ...)
  {
        va_list args;
        va_start(args, fmt);
 -      do_git_common_path(sb, fmt, args);
 +      do_git_common_path(repo, sb, fmt, args);
        va_end(args);
  }
  
  int validate_headref(const char *path)
  {
        struct stat st;
 -      char *buf, buffer[256];
 -      unsigned char sha1[20];
 +      char buffer[256];
 +      const char *refname;
 +      struct object_id oid;
        int fd;
        ssize_t len;
  
        len = read_in_full(fd, buffer, sizeof(buffer)-1);
        close(fd);
  
 +      if (len < 0)
 +              return -1;
 +      buffer[len] = '\0';
 +
        /*
         * Is it a symbolic ref?
         */
 -      if (len < 4)
 -              return -1;
 -      if (!memcmp("ref:", buffer, 4)) {
 -              buf = buffer + 4;
 -              len -= 4;
 -              while (len && isspace(*buf))
 -                      buf++, len--;
 -              if (len >= 5 && !memcmp("refs/", buf, 5))
 +      if (skip_prefix(buffer, "ref:", &refname)) {
 +              while (isspace(*refname))
 +                      refname++;
 +              if (starts_with(refname, "refs/"))
                        return 0;
        }
  
        /*
         * Is this a detached HEAD?
         */
 -      if (!get_sha1_hex(buffer, sha1))
 +      if (!get_oid_hex(buffer, &oid))
                return 0;
  
        return -1;
@@@ -1304,7 -1224,7 +1304,7 @@@ static int only_spaces_and_periods(cons
  
  int is_ntfs_dotgit(const char *name)
  {
-       int len;
+       size_t len;
  
        for (len = 0; ; len++)
                if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
                }
  }
  
+ static int is_ntfs_dot_generic(const char *name,
+                              const char *dotgit_name,
+                              size_t len,
+                              const char *dotgit_ntfs_shortname_prefix)
+ {
+       int saw_tilde;
+       size_t i;
+       if ((name[0] == '.' && !strncasecmp(name + 1, dotgit_name, len))) {
+               i = len + 1;
+ only_spaces_and_periods:
+               for (;;) {
+                       char c = name[i++];
+                       if (!c)
+                               return 1;
+                       if (c != ' ' && c != '.')
+                               return 0;
+               }
+       }
+       /*
+        * Is it a regular NTFS short name, i.e. shortened to 6 characters,
+        * followed by ~1, ... ~4?
+        */
+       if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' &&
+           name[7] >= '1' && name[7] <= '4') {
+               i = 8;
+               goto only_spaces_and_periods;
+       }
+       /*
+        * Is it a fall-back NTFS short name (for details, see
+        * https://en.wikipedia.org/wiki/8.3_filename?
+        */
+       for (i = 0, saw_tilde = 0; i < 8; i++)
+               if (name[i] == '\0')
+                       return 0;
+               else if (saw_tilde) {
+                       if (name[i] < '0' || name[i] > '9')
+                               return 0;
+               } else if (name[i] == '~') {
+                       if (name[++i] < '1' || name[i] > '9')
+                               return 0;
+                       saw_tilde = 1;
+               } else if (i >= 6)
+                       return 0;
+               else if (name[i] < 0) {
+                       /*
+                        * We know our needles contain only ASCII, so we clamp
+                        * here to make the results of tolower() sane.
+                        */
+                       return 0;
+               } else if (tolower(name[i]) != dotgit_ntfs_shortname_prefix[i])
+                       return 0;
+       goto only_spaces_and_periods;
+ }
+ /*
+  * Inline helper to make sure compiler resolves strlen() on literals at
+  * compile time.
+  */
+ static inline int is_ntfs_dot_str(const char *name, const char *dotgit_name,
+                                 const char *dotgit_ntfs_shortname_prefix)
+ {
+       return is_ntfs_dot_generic(name, dotgit_name, strlen(dotgit_name),
+                                  dotgit_ntfs_shortname_prefix);
+ }
+ int is_ntfs_dotgitmodules(const char *name)
+ {
+       return is_ntfs_dot_str(name, "gitmodules", "gi7eba");
+ }
+ int is_ntfs_dotgitignore(const char *name)
+ {
+       return is_ntfs_dot_str(name, "gitignore", "gi250a");
+ }
+ int is_ntfs_dotgitattributes(const char *name)
+ {
+       return is_ntfs_dot_str(name, "gitattributes", "gi7d29");
+ }
  int looks_like_command_line_option(const char *str)
  {
        return str && str[0] == '-';
diff --combined read-cache.c
index 5e6d24d44450d9408b461f05cf55b51035ae11dc,aa99f1f797985d4128af3716b8e4257e4ba2d37c..5b57b369e86b88c992d3158eca43c50a0b01d4c9
@@@ -5,7 -5,6 +5,7 @@@
   */
  #define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
 +#include "config.h"
  #include "tempfile.h"
  #include "lockfile.h"
  #include "cache-tree.h"
@@@ -515,8 -514,9 +515,8 @@@ int remove_index_entry_at(struct index_
        istate->cache_nr--;
        if (pos >= istate->cache_nr)
                return 0;
 -      memmove(istate->cache + pos,
 -              istate->cache + pos + 1,
 -              (istate->cache_nr - pos) * sizeof(struct cache_entry *));
 +      MOVE_ARRAY(istate->cache + pos, istate->cache + pos + 1,
 +                 istate->cache_nr - pos);
        return 1;
  }
  
@@@ -732,7 -732,7 +732,7 @@@ struct cache_entry *make_cache_entry(un
        int size, len;
        struct cache_entry *ce, *ret;
  
-       if (!verify_path(path)) {
+       if (!verify_path(path, mode)) {
                error("Invalid path '%s'", path);
                return NULL;
        }
@@@ -796,7 -796,7 +796,7 @@@ int ce_same_name(const struct cache_ent
   * Also, we don't want double slashes or slashes at the
   * end that can make pathnames ambiguous.
   */
- static int verify_dotfile(const char *rest)
+ static int verify_dotfile(const char *rest, unsigned mode)
  {
        /*
         * The first character was '.', but that
  
        switch (*rest) {
        /*
-        * ".git" followed by  NUL or slash is bad. This
-        * shares the path end test with the ".." case.
+        * ".git" followed by NUL or slash is bad. Note that we match
+        * case-insensitively here, even if ignore_case is not set.
+        * This outlaws ".GIT" everywhere out of an abundance of caution,
+        * since there's really no good reason to allow it.
+        *
+        * Once we've seen ".git", we can also find ".gitmodules", etc (also
+        * case-insensitively).
         */
        case 'g':
        case 'G':
                        break;
                if (rest[2] != 't' && rest[2] != 'T')
                        break;
-               rest += 2;
-       /* fallthrough */
+               if (rest[3] == '\0' || is_dir_sep(rest[3]))
+                       return 0;
+               if (S_ISLNK(mode)) {
+                       rest += 3;
+                       if (skip_iprefix(rest, "modules", &rest) &&
+                           (*rest == '\0' || is_dir_sep(*rest)))
+                               return 0;
+               }
+               break;
        case '.':
                if (rest[1] == '\0' || is_dir_sep(rest[1]))
                        return 0;
        return 1;
  }
  
- int verify_path(const char *path)
+ int verify_path(const char *path, unsigned mode)
  {
        char c;
  
                        return 1;
                if (is_dir_sep(c)) {
  inside:
-                       if (protect_hfs && is_hfs_dotgit(path))
-                               return 0;
-                       if (protect_ntfs && is_ntfs_dotgit(path))
-                               return 0;
+                       if (protect_hfs) {
+                               if (is_hfs_dotgit(path))
+                                       return 0;
+                               if (S_ISLNK(mode)) {
+                                       if (is_hfs_dotgitmodules(path))
+                                               return 0;
+                               }
+                       }
+                       if (protect_ntfs) {
+                               if (is_ntfs_dotgit(path))
+                                       return 0;
+                               if (S_ISLNK(mode)) {
+                                       if (is_ntfs_dotgitmodules(path))
+                                               return 0;
+                               }
+                       }
                        c = *path++;
-                       if ((c == '.' && !verify_dotfile(path)) ||
+                       if ((c == '.' && !verify_dotfile(path, mode)) ||
                            is_dir_sep(c) || c == '\0')
                                return 0;
                }
@@@ -1163,7 -1188,7 +1188,7 @@@ static int add_index_entry_with_check(s
  
        if (!ok_to_add)
                return -1;
-       if (!verify_path(ce->name))
+       if (!verify_path(ce->name, ce->ce_mode))
                return error("Invalid path '%s'", ce->name);
  
        if (!skip_df_check &&
@@@ -1894,7 -1919,8 +1919,7 @@@ int discard_index(struct index_state *i
        free_name_hash(istate);
        cache_tree_free(&(istate->cache_tree));
        istate->initialized = 0;
 -      free(istate->cache);
 -      istate->cache = NULL;
 +      FREE_AND_NULL(istate->cache);
        istate->cache_alloc = 0;
        discard_split_index(istate);
        free_untracked_cache(istate->untracked);
@@@ -1921,7 -1947,7 +1946,7 @@@ static int ce_write_flush(git_SHA_CTX *
        unsigned int buffered = write_buffer_len;
        if (buffered) {
                git_SHA1_Update(context, write_buffer, buffered);
 -              if (write_in_full(fd, write_buffer, buffered) != buffered)
 +              if (write_in_full(fd, write_buffer, buffered) < 0)
                        return -1;
                write_buffer_len = 0;
        }
@@@ -1970,7 -1996,7 +1995,7 @@@ static int ce_flush(git_SHA_CTX *contex
  
        /* Flush first if not enough space for SHA1 signature */
        if (left + 20 > WRITE_BUFFER_SIZE) {
 -              if (write_in_full(fd, write_buffer, left) != left)
 +              if (write_in_full(fd, write_buffer, left) < 0)
                        return -1;
                left = 0;
        }
        git_SHA1_Final(write_buffer + left, context);
        hashcpy(sha1, write_buffer + left);
        left += 20;
 -      return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
 +      return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
  }
  
  static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
@@@ -2197,7 -2223,6 +2222,7 @@@ static int do_write_index(struct index_
        int entries = istate->cache_nr;
        struct stat st;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 +      int drop_cache_tree = 0;
  
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
                                warning(msg, ce->name);
                        else
                                return error(msg, ce->name);
 +
 +                      drop_cache_tree = 1;
                }
                if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
                        return -1;
                if (err)
                        return -1;
        }
 -      if (!strip_extensions && istate->cache_tree) {
 +      if (!strip_extensions && !drop_cache_tree && istate->cache_tree) {
                struct strbuf sb = STRBUF_INIT;
  
                cache_tree_write(&sb, istate->cache_tree);
@@@ -2616,7 -2639,8 +2641,7 @@@ void *read_blob_data_from_index(const s
  
  void stat_validity_clear(struct stat_validity *sv)
  {
 -      free(sv->sd);
 -      sv->sd = NULL;
 +      FREE_AND_NULL(sv->sd);
  }
  
  int stat_validity_check(struct stat_validity *sv, const char *path)
@@@ -2642,9 -2666,3 +2667,9 @@@ void stat_validity_update(struct stat_v
                fill_stat_data(sv->sd, &st);
        }
  }
 +
 +void move_index_extensions(struct index_state *dst, struct index_state *src)
 +{
 +      dst->untracked = src->untracked;
 +      src->untracked = NULL;
 +}
diff --combined submodule-config.c
index 5fe2d0787745de4d97218c738b808667dc8348d3,de54351c6f26bc7db4a3f4c6fa8304da6bc9d0c7..acb7767d3704bafd5ec555daf17f2cb37d33e2a7
@@@ -1,10 -1,7 +1,10 @@@
  #include "cache.h"
 +#include "repository.h"
 +#include "config.h"
  #include "submodule-config.h"
  #include "submodule.h"
  #include "strbuf.h"
 +#include "parse-options.h"
  
  /*
   * submodule cache lookup structure
@@@ -17,7 -14,6 +17,7 @@@
  struct submodule_cache {
        struct hashmap for_path;
        struct hashmap for_name;
 +      unsigned initialized:1;
  };
  
  /*
@@@ -34,34 -30,29 +34,34 @@@ enum lookup_type 
        lookup_path
  };
  
 -static struct submodule_cache the_submodule_cache;
 -static int is_cache_init;
 -
 -static int config_path_cmp(const struct submodule_entry *a,
 +static int config_path_cmp(const void *unused_cmp_data,
 +                         const struct submodule_entry *a,
                           const struct submodule_entry *b,
 -                         const void *unused)
 +                         const void *unused_keydata)
  {
        return strcmp(a->config->path, b->config->path) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
  }
  
 -static int config_name_cmp(const struct submodule_entry *a,
 +static int config_name_cmp(const void *unused_cmp_data,
 +                         const struct submodule_entry *a,
                           const struct submodule_entry *b,
 -                         const void *unused)
 +                         const void *unused_keydata)
  {
        return strcmp(a->config->name, b->config->name) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
  }
  
 -static void cache_init(struct submodule_cache *cache)
 +static struct submodule_cache *submodule_cache_alloc(void)
 +{
 +      return xcalloc(1, sizeof(struct submodule_cache));
 +}
 +
 +static void submodule_cache_init(struct submodule_cache *cache)
  {
 -      hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);
 -      hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);
 +      hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, NULL, 0);
 +      hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, NULL, 0);
 +      cache->initialized = 1;
  }
  
  static void free_one_config(struct submodule_entry *entry)
        free(entry->config);
  }
  
 -static void cache_free(struct submodule_cache *cache)
 +static void submodule_cache_clear(struct submodule_cache *cache)
  {
        struct hashmap_iter iter;
        struct submodule_entry *entry;
  
 +      if (!cache->initialized)
 +              return;
 +
        /*
         * We iterate over the name hash here to be symmetric with the
         * allocation of struct submodule entries. Each is allocated by
  
        hashmap_free(&cache->for_path, 1);
        hashmap_free(&cache->for_name, 1);
 +      cache->initialized = 0;
 +}
 +
 +void submodule_cache_free(struct submodule_cache *cache)
 +{
 +      submodule_cache_clear(cache);
 +      free(cache);
  }
  
  static unsigned int hash_sha1_string(const unsigned char *sha1,
@@@ -182,6 -163,31 +182,31 @@@ static struct submodule *cache_lookup_n
        return NULL;
  }
  
+ int check_submodule_name(const char *name)
+ {
+       /* Disallow empty names */
+       if (!*name)
+               return -1;
+       /*
+        * Look for '..' as a path component. Check both '/' and '\\' as
+        * separators rather than is_dir_sep(), because we want the name rules
+        * to be consistent across platforms.
+        */
+       goto in_component; /* always start inside component */
+       while (*name) {
+               char c = *name++;
+               if (c == '/' || c == '\\') {
+ in_component:
+                       if (name[0] == '.' && name[1] == '.' &&
+                           (!name[2] || name[2] == '/' || name[2] == '\\'))
+                               return -1;
+               }
+       }
+       return 0;
+ }
  static int name_and_item_from_var(const char *var, struct strbuf *name,
                                  struct strbuf *item)
  {
                return 0;
  
        strbuf_add(name, subsection, subsection_len);
+       if (check_submodule_name(name->buf) < 0) {
+               warning(_("ignoring suspicious submodule name: %s"), name->buf);
+               strbuf_release(name);
+               return 0;
+       }
        strbuf_addstr(item, key);
  
        return 1;
@@@ -253,27 -265,6 +284,27 @@@ int parse_fetch_recurse_submodules_arg(
        return parse_fetch_recurse(opt, arg, 1);
  }
  
 +int option_fetch_parse_recurse_submodules(const struct option *opt,
 +                                        const char *arg, int unset)
 +{
 +      int *v;
 +
 +      if (!opt->value)
 +              return -1;
 +
 +      v = opt->value;
 +
 +      if (unset) {
 +              *v = RECURSE_SUBMODULES_OFF;
 +      } else {
 +              if (arg)
 +                      *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
 +              else
 +                      *v = RECURSE_SUBMODULES_ON;
 +      }
 +      return 0;
 +}
 +
  static int parse_update_recurse(const char *opt, const char *arg,
                                int die_on_error)
  {
@@@ -533,62 -524,43 +564,62 @@@ out
        return submodule;
  }
  
 -static void ensure_cache_init(void)
 +static void submodule_cache_check_init(struct repository *repo)
  {
 -      if (is_cache_init)
 +      if (repo->submodule_cache && repo->submodule_cache->initialized)
                return;
  
 -      cache_init(&the_submodule_cache);
 -      is_cache_init = 1;
 +      if (!repo->submodule_cache)
 +              repo->submodule_cache = submodule_cache_alloc();
 +
 +      submodule_cache_init(repo->submodule_cache);
  }
  
 -int parse_submodule_config_option(const char *var, const char *value)
 +int submodule_config_option(struct repository *repo,
 +                          const char *var, const char *value)
  {
        struct parse_config_parameter parameter;
 -      parameter.cache = &the_submodule_cache;
 +
 +      submodule_cache_check_init(repo);
 +
 +      parameter.cache = repo->submodule_cache;
        parameter.treeish_name = NULL;
        parameter.gitmodules_sha1 = null_sha1;
        parameter.overwrite = 1;
  
 -      ensure_cache_init();
        return parse_config(var, value, &parameter);
  }
  
 +int parse_submodule_config_option(const char *var, const char *value)
 +{
 +      return submodule_config_option(the_repository, var, value);
 +}
 +
  const struct submodule *submodule_from_name(const unsigned char *treeish_name,
                const char *name)
  {
 -      ensure_cache_init();
 -      return config_from(&the_submodule_cache, treeish_name, name, lookup_name);
 +      submodule_cache_check_init(the_repository);
 +      return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);
  }
  
  const struct submodule *submodule_from_path(const unsigned char *treeish_name,
                const char *path)
  {
 -      ensure_cache_init();
 -      return config_from(&the_submodule_cache, treeish_name, path, lookup_path);
 +      submodule_cache_check_init(the_repository);
 +      return config_from(the_repository->submodule_cache, treeish_name, path, lookup_path);
 +}
 +
 +const struct submodule *submodule_from_cache(struct repository *repo,
 +                                           const unsigned char *treeish_name,
 +                                           const char *key)
 +{
 +      submodule_cache_check_init(repo);
 +      return config_from(repo->submodule_cache, treeish_name,
 +                         key, lookup_path);
  }
  
  void submodule_free(void)
  {
 -      cache_free(&the_submodule_cache);
 -      is_cache_init = 0;
 +      if (the_repository->submodule_cache)
 +              submodule_cache_clear(the_repository->submodule_cache);
  }
diff --combined submodule-config.h
index 233bfcb7fff0b2dedc64fbb11d167734bf0fad7e,103cc79dd8aa4e0052b1efe9a9a83db48143d4dc..634fe39565cedfb4f242322d74a7096ead339556
@@@ -22,30 -22,24 +22,37 @@@ struct submodule 
        int recommend_shallow;
  };
  
 +struct submodule_cache;
 +struct repository;
 +
 +extern void submodule_cache_free(struct submodule_cache *cache);
 +
  extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
 +struct option;
 +extern int option_fetch_parse_recurse_submodules(const struct option *opt,
 +                                               const char *arg, int unset);
  extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg);
  extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);
  extern int parse_submodule_config_option(const char *var, const char *value);
 +extern int submodule_config_option(struct repository *repo,
 +                                 const char *var, const char *value);
  extern const struct submodule *submodule_from_name(
                const unsigned char *commit_or_tree, const char *name);
  extern const struct submodule *submodule_from_path(
                const unsigned char *commit_or_tree, const char *path);
 +extern const struct submodule *submodule_from_cache(struct repository *repo,
 +                                                  const unsigned char *treeish_name,
 +                                                  const char *key);
  extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,
                                      unsigned char *gitmodules_sha1,
                                      struct strbuf *rev);
  extern void submodule_free(void);
  
+ /*
+  * Returns 0 if the name is syntactically acceptable as a submodule "name"
+  * (e.g., that may be found in the subsection of a .gitmodules file) and -1
+  * otherwise.
+  */
+ int check_submodule_name(const char *name);
  #endif /* SUBMODULE_CONFIG_H */
index 2b3c5092a199835ea2e84339b473a9e29778178d,77517a43edf6cd1549a0267352a27b226e1ea6a5..94846550f74a843f979de14116ab2df5dd15f6e3
@@@ -1,5 -1,6 +1,6 @@@
  #include "cache.h"
  #include "string-list.h"
+ #include "utf8.h"
  
  /*
   * A "string_list_each_func_t" function that normalizes an entry from
@@@ -38,20 -39,6 +39,20 @@@ struct test_data 
        const char *alternative; /* output: ... or this.      */
  };
  
 +/*
 + * Compatibility wrappers for OpenBSD, whose basename(3) and dirname(3)
 + * have const parameters.
 + */
 +static char *posix_basename(char *path)
 +{
 +      return basename(path);
 +}
 +
 +static char *posix_dirname(char *path)
 +{
 +      return dirname(path);
 +}
 +
  static int test_function(struct test_data *data, char *(*func)(char *input),
        const char *funcname)
  {
@@@ -170,6 -157,11 +171,11 @@@ static struct test_data dirname_data[] 
        { NULL,              NULL     }
  };
  
+ static int is_dotgitmodules(const char *path)
+ {
+       return is_hfs_dotgitmodules(path) || is_ntfs_dotgitmodules(path);
+ }
  int cmd_main(int argc, const char **argv)
  {
        if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
        }
  
        if (argc == 2 && !strcmp(argv[1], "basename"))
 -              return test_function(basename_data, basename, argv[1]);
 +              return test_function(basename_data, posix_basename, argv[1]);
  
        if (argc == 2 && !strcmp(argv[1], "dirname"))
 -              return test_function(dirname_data, dirname, argv[1]);
 +              return test_function(dirname_data, posix_dirname, argv[1]);
  
+       if (argc > 2 && !strcmp(argv[1], "is_dotgitmodules")) {
+               int res = 0, expect = 1, i;
+               for (i = 2; i < argc; i++)
+                       if (!strcmp("--not", argv[i]))
+                               expect = !expect;
+                       else if (expect != is_dotgitmodules(argv[i]))
+                               res = error("'%s' is %s.gitmodules", argv[i],
+                                           expect ? "not " : "");
+                       else
+                               fprintf(stderr, "ok: '%s' is %s.gitmodules\n",
+                                       argv[i], expect ? "" : "not ");
+               return !!res;
+       }
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
        return 1;