log_ref_setup(): improve robustness against races
[gitweb.git] / dir.c
diff --git a/dir.c b/dir.c
index 0ea235f3d643d7a9072aca75d7317d1fd7552b4d..bfa8c8a9a51297c3a969c8706467504cb11ce51b 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -207,8 +207,9 @@ int within_depth(const char *name, int namelen,
        return 1;
 }
 
-#define DO_MATCH_EXCLUDE   1
-#define DO_MATCH_DIRECTORY 2
+#define DO_MATCH_EXCLUDE   (1<<0)
+#define DO_MATCH_DIRECTORY (1<<1)
+#define DO_MATCH_SUBMODULE (1<<2)
 
 /*
  * Does 'match' match the given name?
@@ -283,6 +284,32 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
                         item->nowildcard_len - prefix))
                return MATCHED_FNMATCH;
 
+       /* Perform checks to see if "name" is a super set of the pathspec */
+       if (flags & DO_MATCH_SUBMODULE) {
+               /* name is a literal prefix of the pathspec */
+               if ((namelen < matchlen) &&
+                   (match[namelen] == '/') &&
+                   !ps_strncmp(item, match, name, namelen))
+                       return MATCHED_RECURSIVELY;
+
+               /* name" doesn't match up to the first wild character */
+               if (item->nowildcard_len < item->len &&
+                   ps_strncmp(item, match, name,
+                              item->nowildcard_len - prefix))
+                       return 0;
+
+               /*
+                * Here is where we would perform a wildmatch to check if
+                * "name" can be matched as a directory (or a prefix) against
+                * the pathspec.  Since wildmatch doesn't have this capability
+                * at the present we have to punt and say that it is a match,
+                * potentially returning a false positive
+                * The submodules themselves will be able to perform more
+                * accurate matching to determine if the pathspec matches.
+                */
+               return MATCHED_RECURSIVELY;
+       }
+
        return 0;
 }
 
@@ -386,6 +413,21 @@ int match_pathspec(const struct pathspec *ps,
        return negative ? 0 : positive;
 }
 
+/**
+ * Check if a submodule is a superset of the pathspec
+ */
+int submodule_path_match(const struct pathspec *ps,
+                        const char *submodule_name,
+                        char *seen)
+{
+       int matched = do_match_pathspec(ps, submodule_name,
+                                       strlen(submodule_name),
+                                       0, seen,
+                                       DO_MATCH_DIRECTORY |
+                                       DO_MATCH_SUBMODULE);
+       return matched;
+}
+
 int report_path_error(const char *ps_matched,
                      const struct pathspec *pathspec,
                      const char *prefix)
@@ -525,7 +567,7 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
                return NULL;
        if (!ce_skip_worktree(active_cache[pos]))
                return NULL;
-       data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
+       data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz);
        if (!data || type != OBJ_BLOB) {
                free(data);
                return NULL;
@@ -533,7 +575,7 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
        *size = xsize_t(sz);
        if (sha1_stat) {
                memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
-               hashcpy(sha1_stat->sha1, active_cache[pos]->sha1);
+               hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash);
        }
        return data;
 }
@@ -713,7 +755,8 @@ static int add_excludes(const char *fname, const char *base, int baselen,
                                 !ce_stage(active_cache[pos]) &&
                                 ce_uptodate(active_cache[pos]) &&
                                 !would_convert_to_git(fname))
-                               hashcpy(sha1_stat->sha1, active_cache[pos]->sha1);
+                               hashcpy(sha1_stat->sha1,
+                                       active_cache[pos]->oid.hash);
                        else
                                hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
                        fill_stat_data(&sha1_stat->stat, &st);
@@ -2004,8 +2047,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
        if (!len || treat_leading_path(dir, path, len, simplify))
                read_directory_recursive(dir, path, len, untracked, 0, simplify);
        free_simplify(simplify);
-       qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
-       qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
+       QSORT(dir->entries, dir->nr, cmp_name);
+       QSORT(dir->ignored, dir->ignored_nr, cmp_name);
        if (dir->untracked) {
                static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
                trace_printf_key(&trace_untracked_stats,
@@ -2194,8 +2237,6 @@ static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude")
 
 void setup_standard_excludes(struct dir_struct *dir)
 {
-       const char *path;
-
        dir->exclude_per_dir = ".gitignore";
 
        /* core.excludefile defaulting to $XDG_HOME/git/ignore */
@@ -2206,10 +2247,12 @@ void setup_standard_excludes(struct dir_struct *dir)
                                         dir->untracked ? &dir->ss_excludes_file : NULL);
 
        /* per repository user preference */
-       path = git_path_info_exclude();
-       if (!access_or_warn(path, R_OK, 0))
-               add_excludes_from_file_1(dir, path,
-                                        dir->untracked ? &dir->ss_info_exclude : NULL);
+       if (startup_info->have_repository) {
+               const char *path = git_path_info_exclude();
+               if (!access_or_warn(path, R_OK, 0))
+                       add_excludes_from_file_1(dir, path,
+                                                dir->untracked ? &dir->ss_info_exclude : NULL);
+       }
 }
 
 int remove_path(const char *name)