diff --git a/apply.c b/apply.c index 249248d4f2..26286eb57b 100644 --- a/apply.c +++ b/apply.c @@ -3894,7 +3894,7 @@ static int check_preimage(struct apply_state *state, BUG("ce_mode == 0 for path '%s'", old_name); if (trust_executable_bit || !S_ISREG(st->st_mode)) - st_mode = ce_mode_from_stat(*ce, st->st_mode); + st_mode = ce_mode_from_stat(state->repo, *ce, st->st_mode); else if (*ce) st_mode = (*ce)->ce_mode; else diff --git a/builtin/update-index.c b/builtin/update-index.c index 3d6646c318..afd672a914 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -294,7 +294,7 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len ce->ce_flags = create_ce_flags(0); ce->ce_namelen = len; fill_stat_cache_info(the_repository->index, ce, st); - ce->ce_mode = ce_mode_from_stat(old, st->st_mode); + ce->ce_mode = ce_mode_from_stat(the_repository, old, st->st_mode); if (index_path(the_repository->index, &ce->oid, path, st, info_only ? 0 : INDEX_WRITE_OBJECT)) { diff --git a/diff-lib.c b/diff-lib.c index ae91027a02..46cae637ec 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -160,7 +160,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option) changed = check_removed(ce, &st); if (!changed) - wt_mode = ce_mode_from_stat(ce, st.st_mode); + wt_mode = ce_mode_from_stat(revs->repo, ce, st.st_mode); else { if (changed < 0) { perror(ce->name); @@ -193,7 +193,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option) num_compare_stages++; oidcpy(&dpath->parent[stage - 2].oid, &nce->oid); - dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode); + dpath->parent[stage-2].mode = ce_mode_from_stat(revs->repo, nce, mode); dpath->parent[stage-2].status = DIFF_STATUS_MODIFIED; } @@ -262,7 +262,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option) continue; } else if (revs->diffopt.ita_invisible_in_index && ce_intent_to_add(ce)) { - newmode = ce_mode_from_stat(ce, st.st_mode); + newmode = ce_mode_from_stat(revs->repo, ce, st.st_mode); diff_addremove(&revs->diffopt, '+', newmode, null_oid(the_hash_algo), 0, ce->name, 0); continue; @@ -270,7 +270,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option) changed = match_stat_with_submodule(&revs->diffopt, ce, &st, ce_option, &dirty_submodule); - newmode = ce_mode_from_stat(ce, st.st_mode); + newmode = ce_mode_from_stat(revs->repo, ce, st.st_mode); } if (!changed && !dirty_submodule) { @@ -338,7 +338,7 @@ static int get_stat_data(const struct cache_entry *ce, changed = match_stat_with_submodule(diffopt, ce, &st, 0, dirty_submodule); if (changed) { - mode = ce_mode_from_stat(ce, st.st_mode); + mode = ce_mode_from_stat(diffopt->repo, ce, st.st_mode); oid = null_oid(the_hash_algo); } } diff --git a/read-cache.c b/read-cache.c index 1ced8c630e..a9f0591743 100644 --- a/read-cache.c +++ b/read-cache.c @@ -750,7 +750,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, int pos = index_name_pos_also_unmerged(istate, path, namelen); ent = (0 <= pos) ? istate->cache[pos] : NULL; - ce->ce_mode = ce_mode_from_stat(ent, st_mode); + ce->ce_mode = ce_mode_from_stat(istate->repo, ent, st_mode); } /* When core.ignorecase=true, determine if a directory of the same name but differing diff --git a/read-cache.h b/read-cache.h index 043da1f1aa..af8c657ecb 100644 --- a/read-cache.h +++ b/read-cache.h @@ -4,15 +4,24 @@ #include "read-cache-ll.h" #include "object.h" #include "pathspec.h" +#include "environment.h" -static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce, +/* + * Determine the appropriate index mode for a file based on its stat() + * information and the existing cache entry (if any). + * + * This function handles degradation for filesystems that lack + * symlink support or reliable executable bits. + */ +static inline unsigned int ce_mode_from_stat(struct repository *repo UNUSED, + const struct cache_entry *ce, unsigned int mode) { extern int trust_executable_bit, has_symlinks; - if (!has_symlinks && S_ISREG(mode) && + if (S_ISREG(mode) && !has_symlinks && ce && S_ISLNK(ce->ce_mode)) return ce->ce_mode; - if (!trust_executable_bit && S_ISREG(mode)) { + if (S_ISREG(mode) && !trust_executable_bit) { if (ce && S_ISREG(ce->ce_mode)) return ce->ce_mode; return create_ce_mode(0666);