Merge branch 'jk/submodule-name-verify-fix' into jk/submodule-name-verify-fsck
authorJeff King <peff@peff.net>
Tue, 15 May 2018 14:15:18 +0000 (10:15 -0400)
committerJeff King <peff@peff.net>
Tue, 22 May 2018 03:54:28 +0000 (23:54 -0400)
* jk/submodule-name-verify-fix:
verify_path: disallow symlinks in .gitmodules
update-index: stat updated files earlier
verify_path: drop clever fallthrough
skip_prefix: add icase-insensitive variant
is_{hfs,ntfs}_dotgitmodules: add tests
path: match NTFS short names for more .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

Note that this includes two bits of evil-merge:

- there's a new call to verify_path() that doesn't actually
have a mode available. It should be OK to pass "0" here,
since we're just manipulating the untracked cache, not an
actual index entry.

- the lstat() in builtin/update-index.c:update_one() needs
to be updated to handle the fsmonitor case (without this
it still behaves correctly, but does an unnecessary
lstat).

13 files changed:
1  2 
apply.c
builtin/submodule--helper.c
builtin/update-index.c
cache.h
dir.c
git-compat-util.h
git-submodule.sh
path.c
read-cache.c
submodule-config.c
submodule-config.h
t/helper/test-path-utils.c
utf8.c
diff --cc apply.c
Simple merge
index 6ba8587b6d3b7b8b1bc7a96451916c60210b093b,b4b4d29d82896e706be44f8509cb39a6e34037fa..4f35c98bb970328bca5135bd66fdaf3a9fce0d16
@@@ -1814,9 -1190,34 +1814,32 @@@ static int is_active(int argc, const ch
        if (argc != 2)
                die("submodule--helper is-active takes exactly 1 argument");
  
 -      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 {
index 58d1c2d2827d61899d73f1ea7632c5ee219f3ace,19216595fbb917d06d51a42a85d0975d903948a9..1af8a00b889c968634389bf61138200d97eb32f9
@@@ -449,7 -442,17 +448,18 @@@ 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)
++      if (mark_valid_only || mark_skip_worktree_only || force_remove ||
++          mark_fsmonitor_only)
+               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;
        }
diff --cc cache.h
index a61b2d3f0d79b0f56992e0343803811f5265d716,5a44f79e263b650472b650b72de3b5430243f273..0323853c99e75a1edc2e4415db9490ae36bd2c0f
+++ b/cache.h
@@@ -592,49 -590,15 +592,49 @@@ extern int read_index(struct index_stat
  extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
  extern int do_read_index(struct index_state *istate, const char *path,
                         int must_exist); /* for testting only! */
 -extern int read_index_from(struct index_state *, const char *path);
 +extern int read_index_from(struct index_state *, const char *path,
 +                         const char *gitdir);
  extern int is_index_unborn(struct index_state *);
  extern int read_index_unmerged(struct index_state *);
 +
 +/* For use with `write_locked_index()`. */
  #define COMMIT_LOCK           (1 << 0)
 -#define CLOSE_LOCK            (1 << 1)
 +#define SKIP_IF_UNCHANGED     (1 << 1)
 +
 +/*
 + * Write the index while holding an already-taken lock. Close the lock,
 + * and if `COMMIT_LOCK` is given, commit it.
 + *
 + * Unless a split index is in use, write the index into the lockfile.
 + *
 + * With a split index, write the shared index to a temporary file,
 + * adjust its permissions and rename it into place, then write the
 + * split index to the lockfile. If the temporary file for the shared
 + * index cannot be created, fall back to the behavior described in
 + * the previous paragraph.
 + *
 + * With `COMMIT_LOCK`, the lock is always committed or rolled back.
 + * Without it, the lock is closed, but neither committed nor rolled
 + * back.
 + *
 + * If `SKIP_IF_UNCHANGED` is given and the index is unchanged, nothing
 + * is written (and the lock is rolled back if `COMMIT_LOCK` is given).
 + */
  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);
 +
 +/**
 + * Returns 1 if the index differs from HEAD, 0 otherwise. When on an unborn
 + * branch, returns 1 if there are entries in the index, 0 otherwise. If an
 + * strbuf is provided, the space-separated list of files that differ will be
 + * appended to it.
 + */
 +extern int index_has_changes(struct strbuf *sb);
 +
+ 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);
diff --cc dir.c
index dedbf5d476f207e39c1b7853ec8c97553181e5fb,31f9343f9fcf57a89cab519f284cf2e0a767744d..41aac3b7b38e76bb790da4c21c362d7d0f1d1a07
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -2992,8 -2781,6 +2992,8 @@@ void untracked_cache_invalidate_path(st
  {
        if (!istate->untracked || !istate->untracked->root)
                return;
-       if (!safe_path && !verify_path(path))
++      if (!safe_path && !verify_path(path, 0))
 +              return;
        invalidate_one_component(istate->untracked, istate->untracked->root,
                                 path, strlen(path));
  }
Simple merge
Simple merge
diff --cc path.c
Simple merge
diff --cc read-cache.c
Simple merge
Simple merge
index a5503a5d177e90e009be9240bfddd68c9ead475b,103cc79dd8aa4e0052b1efe9a9a83db48143d4dc..17e297022396d2b2b837187d6deaf8a42d45a0d6
@@@ -22,30 -22,24 +22,37 @@@ struct submodule 
        int recommend_shallow;
  };
  
 +#define SUBMODULE_INIT { NULL, NULL, NULL, RECURSE_SUBMODULES_NONE, \
 +      NULL, NULL, SUBMODULE_UPDATE_STRATEGY_INIT, {0}, -1 };
 +
 +struct submodule_cache;
 +struct repository;
 +
 +extern void submodule_cache_free(struct submodule_cache *cache);
 +
 +extern int parse_submodule_fetchjobs(const char *var, const char *value);
  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 void repo_read_gitmodules(struct repository *repo);
 +extern void gitmodules_config_oid(const struct object_id *commit_oid);
  extern const struct submodule *submodule_from_name(
 -              const unsigned char *commit_or_tree, const char *name);
 +              const struct object_id *commit_or_tree, const char *name);
  extern const struct submodule *submodule_from_path(
 -              const unsigned char *commit_or_tree, const char *path);
 -extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,
 -                                    unsigned char *gitmodules_sha1,
 -                                    struct strbuf *rev);
 +              const struct object_id *commit_or_tree, const char *path);
 +extern const struct submodule *submodule_from_cache(struct repository *repo,
 +                                                  const struct object_id *treeish_name,
 +                                                  const char *key);
  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
@@@ -265,11 -257,25 +271,25 @@@ int cmd_main(int argc, const char **arg
        }
  
        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;
diff --cc utf8.c
Simple merge