{"thread":{"id":"65763","subject":"[PATCH v1 1/1] environment.c: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'","startedAt":"2026-06-06T14:34:22Z","lastAt":"2026-06-13T15:33:13Z","messageCount":11,"participants":["Tian Yuchen","Christian Couder","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":1},"messages":[{"id":"544830","messageId":"20260606143412.15443-1-cat@malon.dev","threadId":"65763","inReplyTo":null,"subject":"[PATCH v1 1/1] environment.c: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-06T14:34:11Z","receivedAt":"2026-06-06T14:34:22Z","isPatch":true,"body":"Move the global 'protect_hfs' and 'protect_ntfs' configurations\ninto the repository-specific 'repo_config_values' struct.\nThis will help with the elimination of 'the_repository'\n\nFor now, associated functions access this configuration by\nexplicitly falling back to 'the_repository', which needs to\nbe addressed in the future.\n\nNote: In 't/helper/test-path-utils.c', there is a function\n'protect_ntfs_hfs_benchmark()' where these two global\nvariables are used as loop iterators. New local variables\nhave been created to replace them.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\nMentored-by: Olamide Caleb Bello <belkid98@gmail.com>\nSigned-off-by: Tian Yuchen <cat@malon.dev>\n---\n compat/mingw.c             |  2 +-\n environment.c              |  8 ++++----\n environment.h              |  4 ++--\n read-cache.c               |  7 ++++---\n t/helper/test-path-utils.c | 26 ++++++++++++++++----------\n 5 files changed, 27 insertions(+), 20 deletions(-)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex aa7525f419..c77696ba8a 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -3392,7 +3392,7 @@ int is_valid_win32_path(const char *path, int allow_literal_nul)\n \tconst char *p = path;\n \tint preceding_space_or_period = 0, i = 0, periods = 0;\n \n-\tif (!protect_ntfs)\n+\tif (!(the_repository->gitdir ? repo_config_values(the_repository)->protect_ntfs : 1))\n \t\treturn 1;\n \n \tskip_dos_drive_prefix((char **)&path);\ndiff --git a/environment.c b/environment.c\nindex fc3ed8bb1c..0730bfcbba 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -82,12 +82,10 @@ unsigned long pack_size_limit_cfg;\n #ifndef PROTECT_HFS_DEFAULT\n #define PROTECT_HFS_DEFAULT 0\n #endif\n-int protect_hfs = PROTECT_HFS_DEFAULT;\n \n #ifndef PROTECT_NTFS_DEFAULT\n #define PROTECT_NTFS_DEFAULT 1\n #endif\n-int protect_ntfs = PROTECT_NTFS_DEFAULT;\n \n /*\n  * The character that begins a commented line in user-editable file\n@@ -541,12 +539,12 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.protecthfs\")) {\n-\t\tprotect_hfs = git_config_bool(var, value);\n+\t\tcfg->protect_hfs = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"core.protectntfs\")) {\n-\t\tprotect_ntfs = git_config_bool(var, value);\n+\t\tcfg->protect_ntfs = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -720,5 +718,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n {\n \tcfg->attributes_file = NULL;\n \tcfg->apply_sparse_checkout = 0;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\ndiff --git a/environment.h b/environment.h\nindex 9eb97b3869..d48fd2719c 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -91,6 +91,8 @@ struct repo_config_values {\n \t/* section \"core\" config values */\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n+\tint protect_hfs;\n+\tint protect_ntfs;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -173,8 +175,6 @@ extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \n extern int precomposed_unicode;\n-extern int protect_hfs;\n-extern int protect_ntfs;\n \n extern int core_sparse_checkout_cone;\n extern int sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 21829102ae..b64a5629ef 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1002,7 +1002,7 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\treturn PATH_OK;\n \t\tif (is_dir_sep(c)) {\n inside:\n-\t\t\tif (protect_hfs) {\n+\t\t\tif ((the_repository->gitdir ? repo_config_values(the_repository)->protect_hfs : 0)) {\n \n \t\t\t\tif (is_hfs_dotgit(path))\n \t\t\t\t\treturn PATH_INVALID;\n@@ -1011,7 +1011,7 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\t\t\t\treturn PATH_INVALID;\n \t\t\t\t}\n \t\t\t}\n-\t\t\tif (protect_ntfs) {\n+\t\t\tif ((the_repository->gitdir ? repo_config_values(the_repository)->protect_ntfs : 1)) {\n #if defined GIT_WINDOWS_NATIVE || defined __CYGWIN__\n \t\t\t\tif (c == '\\\\')\n \t\t\t\t\treturn PATH_INVALID;\n@@ -1035,7 +1035,8 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\tif (c == '\\0')\n \t\t\t\treturn S_ISDIR(mode) ? PATH_DIR_WITH_SEP :\n \t\t\t\t\t\t       PATH_INVALID;\n-\t\t} else if (c == '\\\\' && protect_ntfs) {\n+\t\t} else if (c == '\\\\' &&\n+\t\t\t   (the_repository->gitdir ? repo_config_values(the_repository)->protect_ntfs : 1)) {\n \t\t\tif (is_ntfs_dotgit(path))\n \t\t\t\treturn PATH_INVALID;\n \t\t\tif (S_ISLNK(mode)) {\ndiff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c\nindex 15eb44485c..4455a68903 100644\n--- a/t/helper/test-path-utils.c\n+++ b/t/helper/test-path-utils.c\n@@ -250,6 +250,7 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \tdouble m[3][2], v[3][2];\n \tuint64_t cumul;\n \tdouble cumul2;\n+\tint ntfs, hfs;\n \n \tif (argc > 1 && !strcmp(argv[1], \"--with-symlink-mode\")) {\n \t\tfile_mode = 0120000;\n@@ -275,9 +276,14 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \t\twhile (len > 0)\n \t\t\tnames[i][--len] = (char)(' ' + (my_random() % ('\\x7f' - ' ')));\n \t}\n-\n-\tfor (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++)\n-\t\tfor (protect_hfs = 0; protect_hfs < 2; protect_hfs++) {\n+\t\n+\tif (!the_repository->gitdir)\n+\t\tthe_repository->gitdir = xstrdup(\".git\");\n+\n+\tfor (ntfs = 0; ntfs < 2; ntfs++)\n+\t\tfor (hfs = 0; hfs < 2; hfs++) {\n+\t\t\trepo_config_values(the_repository)->protect_ntfs = ntfs;\n+\t\t\trepo_config_values(the_repository)->protect_hfs = hfs;\n \t\t\tcumul = 0;\n \t\t\tcumul2 = 0;\n \t\t\tfor (i = 0; i < repetitions; i++) {\n@@ -285,18 +291,18 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \t\t\t\tfor (j = 0; j < nr; j++)\n \t\t\t\t\tverify_path(names[j], file_mode);\n \t\t\t\tend = getnanotime();\n-\t\t\t\tprintf(\"protect_ntfs = %d, protect_hfs = %d: %lfms\\n\", protect_ntfs, protect_hfs, (end-begin) / (double)1e6);\n+\t\t\t\tprintf(\"protect_ntfs = %d, protect_hfs = %d: %lfms\\n\", ntfs, hfs, (end-begin) / (double)1e6);\n \t\t\t\tcumul += end - begin;\n \t\t\t\tcumul2 += (end - begin) * (end - begin);\n \t\t\t}\n-\t\t\tm[protect_ntfs][protect_hfs] = cumul / (double)repetitions;\n-\t\t\tv[protect_ntfs][protect_hfs] = my_sqrt(cumul2 / (double)repetitions - m[protect_ntfs][protect_hfs] * m[protect_ntfs][protect_hfs]);\n-\t\t\tprintf(\"mean: %lfms, stddev: %lfms\\n\", m[protect_ntfs][protect_hfs] / (double)1e6, v[protect_ntfs][protect_hfs] / (double)1e6);\n+\t\t\tm[ntfs][hfs] = cumul / (double)repetitions;\n+\t\t\tv[ntfs][hfs] = my_sqrt(cumul2 / (double)repetitions - m[ntfs][hfs] * m[ntfs][hfs]);\n+\t\t\tprintf(\"mean: %lfms, stddev: %lfms\\n\", m[ntfs][hfs] / (double)1e6, v[ntfs][hfs] / (double)1e6);\n \t\t}\n \n-\tfor (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++)\n-\t\tfor (protect_hfs = 0; protect_hfs < 2; protect_hfs++)\n-\t\t\tprintf(\"ntfs=%d/hfs=%d: %lf%% slower\\n\", protect_ntfs, protect_hfs, (m[protect_ntfs][protect_hfs] - m[0][0]) * 100 / m[0][0]);\n+\tfor (ntfs = 0; ntfs < 2; ntfs++)\n+\t\tfor (hfs = 0; hfs < 2; hfs++)\n+\t\t\tprintf(\"ntfs=%d/hfs=%d: %lf%% slower\\n\", ntfs, hfs, (m[ntfs][hfs] - m[0][0]) * 100 / m[0][0]);\n \n \treturn 0;\n }\n-- \n2.43.0\n\n"},{"id":"544831","messageId":"20260606143412.15443-2-cat@malon.dev","threadId":"65763","inReplyTo":"20260606143412.15443-1-cat@malon.dev","subject":"[PATCH v1 0/1] environment: move protect_hfs and protect_ntfs","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-06T14:34:12Z","receivedAt":"2026-06-06T14:35:05Z","isPatch":true,"body":"Hi everyone,\n\nThis series continues the ongoing libification effort by moving the\nglobal **filesystem** variables, protect_hfs and protect_ntfs, into\nstruct repo_config_values.\n\nPlace them within the **per-repository** configuration structure\naligns with our goal of removing global states.\n\nRFC Questions:\n\n1. Should we keep PROTECT_HFS_DEFAULT and PROTECT_NTFS_DEFAULT\nin repo_config_values_init()?\n\n\tvoid repo_config_values_init(struct repo_config_values *cfg)\n\t\t{\n\t\t\tcfg->attributes_file = NULL;\n\t\t\tcfg->apply_sparse_checkout = 0;\n\t\t\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n\t\t\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n\t\t\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n\t\t}\n\nOr is it better if they are used anywhere other than in environment.c?\n\nIf so... \n2. Is it worth introducing a Macro or Getter for safe access?\n\n\t((the_repository->gitdir ? repo_config_values(the_repository)->protect_hfs : 0))\n\nThe current approach looks verbose and lacks readability, and\nhard-coded 0 and 1 are used as fallback values. I wonder if a macro or a\ngetter could be introduced, for example... \n\n\t#define SAFE_PROTECT_HFS(repo) \\\n\t\t(((repo) && (repo)->gitdir && (repo) == the_repository) ? \\ \n\t\trepo_config_values(repo)->protect_hfs : PROTECT_HFS_DEFAULT)\n\n...to improve the coding style a bit. Although I am aware that introducing\nnew macros is generally frowned upon, I would still like to know which\nparts this might make difficult to maintain.\n\n3. Note that Derrick attempted to use get_int_config_global to wrap\nthis kind of Filesystem Level global variables. This approach bypassed\nstruct repository, did not actually eliminate global state, and the\nreviewer politely rejected it. Nevertheless, I am still curious as\nto whether this approach might still be inspiring today.\n\nhttps://lore.kernel.org/git/a42dd9397d07b2dc4a0d7e75bfe1af2e46cad262.1685716420.git.gitgitgadget@gmail.com/\n\nThanks!\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\nMentored-by: Olamide Caleb Bello <belkid98@gmail.com>\nSigned-off-by: Tian Yuchen <cat@malon.dev>\n\nTian Yuchen (1):\n  environment.c: move 'protect_hfs' and 'protect_ntfs' into\n    'repo_config_values'\n\n compat/mingw.c             |  2 +-\n environment.c              |  8 ++++----\n environment.h              |  4 ++--\n read-cache.c               |  7 ++++---\n t/helper/test-path-utils.c | 26 ++++++++++++++++----------\n 5 files changed, 27 insertions(+), 20 deletions(-)\n\n-- \n2.43.0\n\n"},{"id":"545054","messageId":"CAP8UFD2vhb3fMp0sfJKewYm8H7HQQ5+dZnQFijDL4Z5Mcf3SCQ@mail.gmail.com","threadId":"65763","inReplyTo":"20260606143412.15443-1-cat@malon.dev","subject":"Re: [PATCH v1 1/1] environment.c: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2026-06-09T10:20:10Z","receivedAt":"2026-06-09T10:20:23Z","isPatch":true,"body":"\"environment.c:\" in the subject could be replaced by just\n\"environment:\". It's a bit shorter and it better describes the area of\nthe code where the main changes are made, as changes are not just made\nin \"environment.c\" but also in \"environment.h\".\n\nOn Sat, Jun 6, 2026 at 4:34 PM Tian Yuchen <cat@malon.dev> wrote:\n>\n> Move the global 'protect_hfs' and 'protect_ntfs' configurations\n> into the repository-specific 'repo_config_values' struct.\n> This will help with the elimination of 'the_repository'\n>\n> For now, associated functions access this configuration by\n> explicitly falling back to 'the_repository', which needs to\n> be addressed in the future.\n>\n> Note: In 't/helper/test-path-utils.c', there is a function\n> 'protect_ntfs_hfs_benchmark()' where these two global\n> variables are used as loop iterators. New local variables\n> have been created to replace them.\n\n\n> diff --git a/compat/mingw.c b/compat/mingw.c\n> index aa7525f419..c77696ba8a 100644\n> --- a/compat/mingw.c\n> +++ b/compat/mingw.c\n> @@ -3392,7 +3392,7 @@ int is_valid_win32_path(const char *path, int allow_literal_nul)\n>         const char *p = path;\n>         int preceding_space_or_period = 0, i = 0, periods = 0;\n>\n> -       if (!protect_ntfs)\n> +       if (!(the_repository->gitdir ? repo_config_values(the_repository)->protect_ntfs : 1))\n>                 return 1;\n\nI think the code would benefit from functions like:\n\nint repo_protect_ntfs(struct repository *repo)\n{\n    return repo->gitdir ?\n        repo_config_values(repo)->protect_ntfs :\n        PROTECT_NTFS_DEFAULT;\n}\n\nint repo_protect_hfs(struct repository *repo)\n{\n    return repo->gitdir ?\n        repo_config_values(repo)->protect_hfs :\n        PROTECT_HFS_DEFAULT;\n}\n\nThey could be called by passing `the_repository` for now, but perhaps\nlater in future commits `istate->repo` or something like that could be\npassed instead. Also a code comment could explain that the `gitdir`\ncheck prevents calling `repo_config_values()` before config is loaded.\n\nThanks.\n"},{"id":"545061","messageId":"CAP8UFD35Tiy1_fqpjq8P-z=ZhzR3MTiThqfCs977652umRoSEQ@mail.gmail.com","threadId":"65763","inReplyTo":"20260606143412.15443-2-cat@malon.dev","subject":"Re: [PATCH v1 0/1] environment: move protect_hfs and protect_ntfs","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2026-06-09T10:54:26Z","receivedAt":"2026-06-09T10:54:39Z","isPatch":true,"body":"On Sat, Jun 6, 2026 at 4:35 PM Tian Yuchen <cat@malon.dev> wrote:\n>\n> Hi everyone,\n>\n> This series continues the ongoing libification effort by moving the\n> global **filesystem** variables, protect_hfs and protect_ntfs, into\n> struct repo_config_values.\n>\n> Place them within the **per-repository** configuration structure\n> aligns with our goal of removing global states.\n>\n> RFC Questions:\n>\n> 1. Should we keep PROTECT_HFS_DEFAULT and PROTECT_NTFS_DEFAULT\n> in repo_config_values_init()?\n>\n>         void repo_config_values_init(struct repo_config_values *cfg)\n>                 {\n>                         cfg->attributes_file = NULL;\n>                         cfg->apply_sparse_checkout = 0;\n>                         cfg->protect_hfs = PROTECT_HFS_DEFAULT;\n>                         cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n>                         cfg->branch_track = BRANCH_TRACK_REMOTE;\n>                 }\n>\n> Or is it better if they are used anywhere other than in environment.c?\n\nI think it's better to keep them in \"environment.c\". The\nrepo_protect_ntfs() and repo_protect_hfs() function I suggest adding\nto \"environment.c\" in my reply to the patch should help with keeping\nthe macros in \"environment.c\".\n\n> If so...\n> 2. Is it worth introducing a Macro or Getter for safe access?\n>\n>         ((the_repository->gitdir ? repo_config_values(the_repository)->protect_hfs : 0))\n\nYes, it seems to me that a getter is enough.\n\n> The current approach looks verbose and lacks readability, and\n> hard-coded 0 and 1 are used as fallback values. I wonder if a macro or a\n> getter could be introduced, for example...\n>\n>         #define SAFE_PROTECT_HFS(repo) \\\n>                 (((repo) && (repo)->gitdir && (repo) == the_repository) ? \\\n>                 repo_config_values(repo)->protect_hfs : PROTECT_HFS_DEFAULT)\n>\n> ...to improve the coding style a bit. Although I am aware that introducing\n> new macros is generally frowned upon, I would still like to know which\n> parts this might make difficult to maintain.\n\nUnless there are features that we really want which a function can't\nprovide, a function is better as it provides type safety and is\nusually easier to maintain.\n\n> 3. Note that Derrick attempted to use get_int_config_global to wrap\n> this kind of Filesystem Level global variables. This approach bypassed\n> struct repository, did not actually eliminate global state, and the\n> reviewer politely rejected it. Nevertheless, I am still curious as\n> to whether this approach might still be inspiring today.\n>\n> https://lore.kernel.org/git/a42dd9397d07b2dc4a0d7e75bfe1af2e46cad262.1685716420.git.gitgitgadget@gmail.com/\n\nTo help your reviewers, it might be interesting if you could already\ntell why this was rejected by Glen Choo (who reviewed Derrick Stolee's\nwork then). It seems to me that Glen said that using plain fields in a\nstruct should be better as long as the fields are always initialized\nduring the setup process.\n\nAnd it seems to me that our patch follows the direction that Glen suggested.\n\nThanks.\n"},{"id":"545137","messageId":"20260610124353.149874-1-cat@malon.dev","threadId":"65763","inReplyTo":"20260606143412.15443-1-cat@malon.dev","subject":"[PATCH v2 0/1] environment: move protect_hfs and protect_ntfs into repo_config_values","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-10T12:43:51Z","receivedAt":"2026-06-10T12:44:02Z","isPatch":true,"body":"Hi everyone,\n\nThis series continues the ongoing libification effort by moving the\nglobal filesystem variables, 'protect_hfs' and 'protect_ntfs', into\n'struct repo_config_values'.\n\nPlace them within the per-repository configuration structure\naligns with our goal of removing global states.\n\nFor reviewers familiar with previous libification efforts, Derrick Stolee\nattempted to wrap this kind of filesystem-level variable using a\nlazy-loaded global accessor get_int_config_global() [1].\n\nHowever, as Glen Choo pointed out in his review of that series [2],\nit is strongly preferred to use plain fields in a repository-scoped\nstruct over global lazy-loaders, provided those fields are properly\ninitialized during the setup process.\n\nBy moving these variables into repo_config_values and parsing\nthem eagerly, we successfully tie the filesystem security flags\nto the specific repository instance without altering the timing\nof configuration warnings or introducing new global states.\n\nThanks!\n\nRecent related patch (environment.c: migrate 'trust_executable_bit' into 'repo_config_values'): [3]\n\n[1] https://lore.kernel.org/git/a42dd9397d07b2dc4a0d7e75bfe1af2e46cad262.1685716420.git.gitgitgadget@gmail.com/\n[2] https://lore.kernel.org/git/kl6lbkhpzujf.fsf@chooglen-macbookpro.roam.corp.google.com/\n[3] https://lore.kernel.org/git/20260610093635.139719-1-cat@malon.dev/\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\nMentored-by: Olamide Caleb Bello <belkid98@gmail.com>\nSigned-off-by: Tian Yuchen <cat@malon.dev>\n\nTian Yuchen (1):\n  environment.c: move 'protect_hfs' and 'protect_ntfs' into\n    'repo_config_values'\n\n compat/mingw.c             |  2 +-\n environment.c              | 22 ++++++++++++++++++----\n environment.h              | 12 ++++++++++--\n read-cache.c               |  7 ++++---\n t/helper/test-path-utils.c | 24 +++++++++++++++---------\n 5 files changed, 48 insertions(+), 19 deletions(-)\n\n-- \n2.43.0\n\n"},{"id":"545138","messageId":"20260610124353.149874-2-cat@malon.dev","threadId":"65763","inReplyTo":"20260610124353.149874-1-cat@malon.dev","subject":"[PATCH v2 1/1] environment.c: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-10T12:43:52Z","receivedAt":"2026-06-10T12:44:05Z","isPatch":true,"body":"Move the global 'protect_hfs' and 'protect_ntfs' configurations\ninto the repository-specific 'repo_config_values' struct.\nThis will help with the elimination of 'the_repository'\n\nTo ensure code readability, the getter functions\n'repo_protect_hfs()' and 'repo_protect_ntfs()'\nhave been introduced.\n\nFor now, associated functions access this configuration by\nexplicitly falling back to 'the_repository', which needs to\nbe addressed in the future.\n\nNote: In 't/helper/test-path-utils.c', there is a function\n'protect_ntfs_hfs_benchmark()' where these two global\nvariables are used as loop iterators. New local variables\nhave been created to replace them.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\nMentored-by: Olamide Caleb Bello <belkid98@gmail.com>\nSigned-off-by: Tian Yuchen <cat@malon.dev>\n---\n compat/mingw.c             |  2 +-\n environment.c              | 22 ++++++++++++++++++----\n environment.h              | 12 ++++++++++--\n read-cache.c               |  7 ++++---\n t/helper/test-path-utils.c | 24 +++++++++++++++---------\n 5 files changed, 48 insertions(+), 19 deletions(-)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex aa7525f419..af87df77fd 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -3392,7 +3392,7 @@ int is_valid_win32_path(const char *path, int allow_literal_nul)\n \tconst char *p = path;\n \tint preceding_space_or_period = 0, i = 0, periods = 0;\n \n-\tif (!protect_ntfs)\n+\tif (!repo_protect_ntfs(the_repository))\n \t\treturn 1;\n \n \tskip_dos_drive_prefix((char **)&path);\ndiff --git a/environment.c b/environment.c\nindex fc3ed8bb1c..683fe1b4d3 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -82,12 +82,10 @@ unsigned long pack_size_limit_cfg;\n #ifndef PROTECT_HFS_DEFAULT\n #define PROTECT_HFS_DEFAULT 0\n #endif\n-int protect_hfs = PROTECT_HFS_DEFAULT;\n \n #ifndef PROTECT_NTFS_DEFAULT\n #define PROTECT_NTFS_DEFAULT 1\n #endif\n-int protect_ntfs = PROTECT_NTFS_DEFAULT;\n \n /*\n  * The character that begins a commented line in user-editable file\n@@ -142,6 +140,20 @@ int is_bare_repository(void)\n \treturn is_bare_repository_cfg && !repo_get_work_tree(the_repository);\n }\n \n+int repo_protect_ntfs(struct repository *repo)\n+{\n+\treturn repo->gitdir ?\n+\t\trepo_config_values(repo)->protect_ntfs :\n+\t\tPROTECT_NTFS_DEFAULT;\n+}\n+\n+int repo_protect_hfs(struct repository *repo)\n+{\n+\treturn repo->gitdir ?\n+\t\trepo_config_values(repo)->protect_hfs :\n+\t\tPROTECT_HFS_DEFAULT;\n+}\n+\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n@@ -541,12 +553,12 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.protecthfs\")) {\n-\t\tprotect_hfs = git_config_bool(var, value);\n+\t\tcfg->protect_hfs = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"core.protectntfs\")) {\n-\t\tprotect_ntfs = git_config_bool(var, value);\n+\t\tcfg->protect_ntfs = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -720,5 +732,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n {\n \tcfg->attributes_file = NULL;\n \tcfg->apply_sparse_checkout = 0;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\ndiff --git a/environment.h b/environment.h\nindex 9eb97b3869..fdd9775900 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -91,6 +91,8 @@ struct repo_config_values {\n \t/* section \"core\" config values */\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n+\tint protect_hfs;\n+\tint protect_ntfs;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -123,6 +125,14 @@ int git_default_config(const char *, const char *,\n int git_default_core_config(const char *var, const char *value,\n \t\t\t    const struct config_context *ctx, void *cb);\n \n+/*\n+ * Getters for the `protect_hfs` and `protect_ntfs` fields of `struct repo_config_values`.\n+ * They check `repo->gitdir` to prevent calling repo_config_values()\n+ * before the configuration is loaded or in bare environments.\n+ */\n+int repo_protect_hfs(struct repository *repo);\n+int repo_protect_ntfs(struct repository *repo);\n+\n void repo_config_values_init(struct repo_config_values *cfg);\n \n /*\n@@ -173,8 +183,6 @@ extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \n extern int precomposed_unicode;\n-extern int protect_hfs;\n-extern int protect_ntfs;\n \n extern int core_sparse_checkout_cone;\n extern int sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 21829102ae..2c6a60c756 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1002,7 +1002,7 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\treturn PATH_OK;\n \t\tif (is_dir_sep(c)) {\n inside:\n-\t\t\tif (protect_hfs) {\n+\t\t\tif (repo_protect_hfs(the_repository)) {\n \n \t\t\t\tif (is_hfs_dotgit(path))\n \t\t\t\t\treturn PATH_INVALID;\n@@ -1011,7 +1011,7 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\t\t\t\treturn PATH_INVALID;\n \t\t\t\t}\n \t\t\t}\n-\t\t\tif (protect_ntfs) {\n+\t\t\tif (repo_protect_ntfs(the_repository)) {\n #if defined GIT_WINDOWS_NATIVE || defined __CYGWIN__\n \t\t\t\tif (c == '\\\\')\n \t\t\t\t\treturn PATH_INVALID;\n@@ -1035,7 +1035,8 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\tif (c == '\\0')\n \t\t\t\treturn S_ISDIR(mode) ? PATH_DIR_WITH_SEP :\n \t\t\t\t\t\t       PATH_INVALID;\n-\t\t} else if (c == '\\\\' && protect_ntfs) {\n+\t\t} else if (c == '\\\\' &&\n+\t\t\t   repo_protect_ntfs(the_repository)) {\n \t\t\tif (is_ntfs_dotgit(path))\n \t\t\t\treturn PATH_INVALID;\n \t\t\tif (S_ISLNK(mode)) {\ndiff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c\nindex 15eb44485c..f77b3f9d70 100644\n--- a/t/helper/test-path-utils.c\n+++ b/t/helper/test-path-utils.c\n@@ -250,6 +250,7 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \tdouble m[3][2], v[3][2];\n \tuint64_t cumul;\n \tdouble cumul2;\n+\tint ntfs, hfs;\n \n \tif (argc > 1 && !strcmp(argv[1], \"--with-symlink-mode\")) {\n \t\tfile_mode = 0120000;\n@@ -276,8 +277,13 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \t\t\tnames[i][--len] = (char)(' ' + (my_random() % ('\\x7f' - ' ')));\n \t}\n \n-\tfor (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++)\n-\t\tfor (protect_hfs = 0; protect_hfs < 2; protect_hfs++) {\n+\tif (!the_repository->gitdir)\n+\t\tthe_repository->gitdir = xstrdup(\".git\");\n+\n+\tfor (ntfs = 0; ntfs < 2; ntfs++)\n+\t\tfor (hfs = 0; hfs < 2; hfs++) {\n+\t\t\trepo_config_values(the_repository)->protect_ntfs = ntfs;\n+\t\t\trepo_config_values(the_repository)->protect_hfs = hfs;\n \t\t\tcumul = 0;\n \t\t\tcumul2 = 0;\n \t\t\tfor (i = 0; i < repetitions; i++) {\n@@ -285,18 +291,18 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \t\t\t\tfor (j = 0; j < nr; j++)\n \t\t\t\t\tverify_path(names[j], file_mode);\n \t\t\t\tend = getnanotime();\n-\t\t\t\tprintf(\"protect_ntfs = %d, protect_hfs = %d: %lfms\\n\", protect_ntfs, protect_hfs, (end-begin) / (double)1e6);\n+\t\t\t\tprintf(\"protect_ntfs = %d, protect_hfs = %d: %lfms\\n\", ntfs, hfs, (end-begin) / (double)1e6);\n \t\t\t\tcumul += end - begin;\n \t\t\t\tcumul2 += (end - begin) * (end - begin);\n \t\t\t}\n-\t\t\tm[protect_ntfs][protect_hfs] = cumul / (double)repetitions;\n-\t\t\tv[protect_ntfs][protect_hfs] = my_sqrt(cumul2 / (double)repetitions - m[protect_ntfs][protect_hfs] * m[protect_ntfs][protect_hfs]);\n-\t\t\tprintf(\"mean: %lfms, stddev: %lfms\\n\", m[protect_ntfs][protect_hfs] / (double)1e6, v[protect_ntfs][protect_hfs] / (double)1e6);\n+\t\t\tm[ntfs][hfs] = cumul / (double)repetitions;\n+\t\t\tv[ntfs][hfs] = my_sqrt(cumul2 / (double)repetitions - m[ntfs][hfs] * m[ntfs][hfs]);\n+\t\t\tprintf(\"mean: %lfms, stddev: %lfms\\n\", m[ntfs][hfs] / (double)1e6, v[ntfs][hfs] / (double)1e6);\n \t\t}\n \n-\tfor (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++)\n-\t\tfor (protect_hfs = 0; protect_hfs < 2; protect_hfs++)\n-\t\t\tprintf(\"ntfs=%d/hfs=%d: %lf%% slower\\n\", protect_ntfs, protect_hfs, (m[protect_ntfs][protect_hfs] - m[0][0]) * 100 / m[0][0]);\n+\tfor (ntfs = 0; ntfs < 2; ntfs++)\n+\t\tfor (hfs = 0; hfs < 2; hfs++)\n+\t\t\tprintf(\"ntfs=%d/hfs=%d: %lf%% slower\\n\", ntfs, hfs, (m[ntfs][hfs] - m[0][0]) * 100 / m[0][0]);\n \n \treturn 0;\n }\n-- \n2.43.0\n\n"},{"id":"545171","messageId":"xmqqse6uwdnz.fsf@gitster.g","threadId":"65763","inReplyTo":"20260610124353.149874-2-cat@malon.dev","subject":"Re: [PATCH v2 1/1] environment.c: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-10T16:41:52Z","receivedAt":"2026-06-10T16:41:54Z","isPatch":true,"body":"Tian Yuchen <cat@malon.dev> writes:\n\n> +int repo_protect_ntfs(struct repository *repo)\n> +{\n> +\treturn repo->gitdir ?\n> +\t\trepo_config_values(repo)->protect_ntfs :\n> +\t\tPROTECT_NTFS_DEFAULT;\n> +}\n> +\n> +int repo_protect_hfs(struct repository *repo)\n> +{\n> +\treturn repo->gitdir ?\n> +\t\trepo_config_values(repo)->protect_hfs :\n> +\t\tPROTECT_HFS_DEFAULT;\n> +}\n> ...\n> @@ -123,6 +125,14 @@ int git_default_config(const char *, const char *,\n>  int git_default_core_config(const char *var, const char *value,\n>  \t\t\t    const struct config_context *ctx, void *cb);\n>  \n> +/*\n> + * Getters for the `protect_hfs` and `protect_ntfs` fields of `struct repo_config_values`.\n> + * They check `repo->gitdir` to prevent calling repo_config_values()\n> + * before the configuration is loaded or in bare environments.\n> + */\n> +int repo_protect_hfs(struct repository *repo);\n> +int repo_protect_ntfs(struct repository *repo);\n\nI briefly wondered what *should* happen when repo->gitdir is not\nready, as it feels almost a bug for a caller to call these two\nfunctions before the repository is ready to be used.\n\nWhen repo is not ready, these return their respective default\nvalues.  That's like the original code using the initial value of\nthese global variables.\n\nIOW, this rewrite is bug-for-bug compatible, which is good.\n\nShall we declare victory and mark the topic for 'next' now?\n\nThanks.\n"},{"id":"545345","messageId":"CAP8UFD1UbsXu_7DK2keGLUO3Yh06-YHieZP+On-yjY3SmV2Xmg@mail.gmail.com","threadId":"65763","inReplyTo":"xmqqse6uwdnz.fsf@gitster.g","subject":"Re: [PATCH v2 1/1] environment.c: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2026-06-12T07:22:23Z","receivedAt":"2026-06-12T07:22:36Z","isPatch":true,"body":"On Wed, Jun 10, 2026 at 6:41 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Tian Yuchen <cat@malon.dev> writes:\n>\n> > +int repo_protect_ntfs(struct repository *repo)\n> > +{\n> > +     return repo->gitdir ?\n> > +             repo_config_values(repo)->protect_ntfs :\n> > +             PROTECT_NTFS_DEFAULT;\n> > +}\n> > +\n> > +int repo_protect_hfs(struct repository *repo)\n> > +{\n> > +     return repo->gitdir ?\n> > +             repo_config_values(repo)->protect_hfs :\n> > +             PROTECT_HFS_DEFAULT;\n> > +}\n> > ...\n> > @@ -123,6 +125,14 @@ int git_default_config(const char *, const char *,\n> >  int git_default_core_config(const char *var, const char *value,\n> >                           const struct config_context *ctx, void *cb);\n> >\n> > +/*\n> > + * Getters for the `protect_hfs` and `protect_ntfs` fields of `struct repo_config_values`.\n> > + * They check `repo->gitdir` to prevent calling repo_config_values()\n> > + * before the configuration is loaded or in bare environments.\n> > + */\n> > +int repo_protect_hfs(struct repository *repo);\n> > +int repo_protect_ntfs(struct repository *repo);\n>\n> I briefly wondered what *should* happen when repo->gitdir is not\n> ready, as it feels almost a bug for a caller to call these two\n> functions before the repository is ready to be used.\n>\n> When repo is not ready, these return their respective default\n> values.  That's like the original code using the initial value of\n> these global variables.\n>\n> IOW, this rewrite is bug-for-bug compatible, which is good.\n>\n> Shall we declare victory and mark the topic for 'next' now?\n\nI would have preferred the commit subject to start with \"environment:\"\nrather than \"environment.c:\" but it's a small nit and maybe you can\nfix it while merging.\n\nOtherwise the patch looks indeed good to me.\n\nThanks.\n"},{"id":"545404","messageId":"xmqqik7nhfbv.fsf@gitster.g","threadId":"65763","inReplyTo":"CAP8UFD1UbsXu_7DK2keGLUO3Yh06-YHieZP+On-yjY3SmV2Xmg@mail.gmail.com","subject":"Re: [PATCH v2 1/1] environment.c: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-12T16:51:48Z","receivedAt":"2026-06-12T16:51:51Z","isPatch":true,"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> On Wed, Jun 10, 2026 at 6:41 PM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> Tian Yuchen <cat@malon.dev> writes:\n>>\n>> > +int repo_protect_ntfs(struct repository *repo)\n>> > +{\n>> > +     return repo->gitdir ?\n>> ...\n>> Shall we declare victory and mark the topic for 'next' now?\n>\n> I would have preferred the commit subject to start with \"environment:\"\n> rather than \"environment.c:\" but it's a small nit and maybe you can\n> fix it while merging.\n\nIf I remember, perhaps I'll try.  But you know what happens when you\nadd more stuff that are not something only the maintainer can do on\nmy plate ;-)\n"},{"id":"545456","messageId":"20260613153302.168801-1-cat@malon.dev","threadId":"65763","inReplyTo":"20260610124353.149874-1-cat@malon.dev","subject":"[PATCH v3 0/1] environment: move protect_hfs and protect_ntfs into repo_config_values","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-13T15:33:00Z","receivedAt":"2026-06-13T15:33:10Z","isPatch":true,"body":"Hi everyone,\n\nThis series continues the ongoing libification effort by moving the\nglobal filesystem variables, 'protect_hfs' and 'protect_ntfs', into\n'struct repo_config_values'.\n\nPlace them within the per-repository configuration structure\naligns with our goal of removing global states.\n\nFor reviewers familiar with previous libification efforts, Derrick Stolee\nattempted to wrap this kind of filesystem-level variable using a\nlazy-loaded global accessor get_int_config_global() [1].\n\nHowever, as Glen Choo pointed out in his review of that series [2],\nit is strongly preferred to use plain fields in a repository-scoped\nstruct over global lazy-loaders, provided those fields are properly\ninitialized during the setup process.\n\nBy moving these variables into repo_config_values and parsing\nthem eagerly, we successfully tie the filesystem security flags\nto the specific repository instance without altering the timing\nof configuration warnings or introducing new global states.\n\nThanks!\n\nRecent related patch (environment.c: migrate 'trust_executable_bit' into 'repo_config_values'): [3]\n\nChanges since V2:\n\n 1. s/environment.c/environment\n\n 2. Updated the link for \"Recent related patch\"\n\n\n[1] https://lore.kernel.org/git/a42dd9397d07b2dc4a0d7e75bfe1af2e46cad262.1685716420.git.gitgitgadget@gmail.com/\n[2] https://lore.kernel.org/git/kl6lbkhpzujf.fsf@chooglen-macbookpro.roam.corp.google.com/\n[3] https://lore.kernel.org/git/20260612160527.167203-1-cat@malon.dev/\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\nMentored-by: Olamide Caleb Bello <belkid98@gmail.com>\nSigned-off-by: Tian Yuchen <cat@malon.dev>\n\nTian Yuchen (1):\n  environment: move 'protect_hfs' and 'protect_ntfs' into\n    'repo_config_values'\n\n compat/mingw.c             |  2 +-\n environment.c              | 22 ++++++++++++++++++----\n environment.h              | 12 ++++++++++--\n read-cache.c               |  7 ++++---\n t/helper/test-path-utils.c | 24 +++++++++++++++---------\n 5 files changed, 48 insertions(+), 19 deletions(-)\n\n-- \n2.43.0\n\n"},{"id":"545457","messageId":"20260613153302.168801-2-cat@malon.dev","threadId":"65763","inReplyTo":"20260613153302.168801-1-cat@malon.dev","subject":"[PATCH v3 1/1] environment: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'","fromName":"Tian Yuchen","fromEmail":"cat@malon.dev","sentAt":"2026-06-13T15:33:01Z","receivedAt":"2026-06-13T15:33:13Z","isPatch":true,"body":"Move the global 'protect_hfs' and 'protect_ntfs' configurations\ninto the repository-specific 'repo_config_values' struct.\nThis will help with the elimination of 'the_repository'\n\nTo ensure code readability, the getter functions\n'repo_protect_hfs()' and 'repo_protect_ntfs()'\nhave been introduced.\n\nFor now, associated functions access this configuration by\nexplicitly falling back to 'the_repository', which needs to\nbe addressed in the future.\n\nNote: In 't/helper/test-path-utils.c', there is a function\n'protect_ntfs_hfs_benchmark()' where these two global\nvariables are used as loop iterators. New local variables\nhave been created to replace them.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>\nMentored-by: Olamide Caleb Bello <belkid98@gmail.com>\nSigned-off-by: Tian Yuchen <cat@malon.dev>\n---\n compat/mingw.c             |  2 +-\n environment.c              | 22 ++++++++++++++++++----\n environment.h              | 12 ++++++++++--\n read-cache.c               |  7 ++++---\n t/helper/test-path-utils.c | 24 +++++++++++++++---------\n 5 files changed, 48 insertions(+), 19 deletions(-)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex aa7525f419..af87df77fd 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -3392,7 +3392,7 @@ int is_valid_win32_path(const char *path, int allow_literal_nul)\n \tconst char *p = path;\n \tint preceding_space_or_period = 0, i = 0, periods = 0;\n \n-\tif (!protect_ntfs)\n+\tif (!repo_protect_ntfs(the_repository))\n \t\treturn 1;\n \n \tskip_dos_drive_prefix((char **)&path);\ndiff --git a/environment.c b/environment.c\nindex fc3ed8bb1c..683fe1b4d3 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -82,12 +82,10 @@ unsigned long pack_size_limit_cfg;\n #ifndef PROTECT_HFS_DEFAULT\n #define PROTECT_HFS_DEFAULT 0\n #endif\n-int protect_hfs = PROTECT_HFS_DEFAULT;\n \n #ifndef PROTECT_NTFS_DEFAULT\n #define PROTECT_NTFS_DEFAULT 1\n #endif\n-int protect_ntfs = PROTECT_NTFS_DEFAULT;\n \n /*\n  * The character that begins a commented line in user-editable file\n@@ -142,6 +140,20 @@ int is_bare_repository(void)\n \treturn is_bare_repository_cfg && !repo_get_work_tree(the_repository);\n }\n \n+int repo_protect_ntfs(struct repository *repo)\n+{\n+\treturn repo->gitdir ?\n+\t\trepo_config_values(repo)->protect_ntfs :\n+\t\tPROTECT_NTFS_DEFAULT;\n+}\n+\n+int repo_protect_hfs(struct repository *repo)\n+{\n+\treturn repo->gitdir ?\n+\t\trepo_config_values(repo)->protect_hfs :\n+\t\tPROTECT_HFS_DEFAULT;\n+}\n+\n int have_git_dir(void)\n {\n \treturn startup_info->have_repository\n@@ -541,12 +553,12 @@ int git_default_core_config(const char *var, const char *value,\n \t}\n \n \tif (!strcmp(var, \"core.protecthfs\")) {\n-\t\tprotect_hfs = git_config_bool(var, value);\n+\t\tcfg->protect_hfs = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"core.protectntfs\")) {\n-\t\tprotect_ntfs = git_config_bool(var, value);\n+\t\tcfg->protect_ntfs = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n@@ -720,5 +732,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n {\n \tcfg->attributes_file = NULL;\n \tcfg->apply_sparse_checkout = 0;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n \tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\ndiff --git a/environment.h b/environment.h\nindex 9eb97b3869..fdd9775900 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -91,6 +91,8 @@ struct repo_config_values {\n \t/* section \"core\" config values */\n \tchar *attributes_file;\n \tint apply_sparse_checkout;\n+\tint protect_hfs;\n+\tint protect_ntfs;\n \n \t/* section \"branch\" config values */\n \tenum branch_track branch_track;\n@@ -123,6 +125,14 @@ int git_default_config(const char *, const char *,\n int git_default_core_config(const char *var, const char *value,\n \t\t\t    const struct config_context *ctx, void *cb);\n \n+/*\n+ * Getters for the `protect_hfs` and `protect_ntfs` fields of `struct repo_config_values`.\n+ * They check `repo->gitdir` to prevent calling repo_config_values()\n+ * before the configuration is loaded or in bare environments.\n+ */\n+int repo_protect_hfs(struct repository *repo);\n+int repo_protect_ntfs(struct repository *repo);\n+\n void repo_config_values_init(struct repo_config_values *cfg);\n \n /*\n@@ -173,8 +183,6 @@ extern int pack_compression_level;\n extern unsigned long pack_size_limit_cfg;\n \n extern int precomposed_unicode;\n-extern int protect_hfs;\n-extern int protect_ntfs;\n \n extern int core_sparse_checkout_cone;\n extern int sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 21829102ae..2c6a60c756 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1002,7 +1002,7 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\treturn PATH_OK;\n \t\tif (is_dir_sep(c)) {\n inside:\n-\t\t\tif (protect_hfs) {\n+\t\t\tif (repo_protect_hfs(the_repository)) {\n \n \t\t\t\tif (is_hfs_dotgit(path))\n \t\t\t\t\treturn PATH_INVALID;\n@@ -1011,7 +1011,7 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\t\t\t\treturn PATH_INVALID;\n \t\t\t\t}\n \t\t\t}\n-\t\t\tif (protect_ntfs) {\n+\t\t\tif (repo_protect_ntfs(the_repository)) {\n #if defined GIT_WINDOWS_NATIVE || defined __CYGWIN__\n \t\t\t\tif (c == '\\\\')\n \t\t\t\t\treturn PATH_INVALID;\n@@ -1035,7 +1035,8 @@ static enum verify_path_result verify_path_internal(const char *path,\n \t\t\tif (c == '\\0')\n \t\t\t\treturn S_ISDIR(mode) ? PATH_DIR_WITH_SEP :\n \t\t\t\t\t\t       PATH_INVALID;\n-\t\t} else if (c == '\\\\' && protect_ntfs) {\n+\t\t} else if (c == '\\\\' &&\n+\t\t\t   repo_protect_ntfs(the_repository)) {\n \t\t\tif (is_ntfs_dotgit(path))\n \t\t\t\treturn PATH_INVALID;\n \t\t\tif (S_ISLNK(mode)) {\ndiff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c\nindex 15eb44485c..f77b3f9d70 100644\n--- a/t/helper/test-path-utils.c\n+++ b/t/helper/test-path-utils.c\n@@ -250,6 +250,7 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \tdouble m[3][2], v[3][2];\n \tuint64_t cumul;\n \tdouble cumul2;\n+\tint ntfs, hfs;\n \n \tif (argc > 1 && !strcmp(argv[1], \"--with-symlink-mode\")) {\n \t\tfile_mode = 0120000;\n@@ -276,8 +277,13 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \t\t\tnames[i][--len] = (char)(' ' + (my_random() % ('\\x7f' - ' ')));\n \t}\n \n-\tfor (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++)\n-\t\tfor (protect_hfs = 0; protect_hfs < 2; protect_hfs++) {\n+\tif (!the_repository->gitdir)\n+\t\tthe_repository->gitdir = xstrdup(\".git\");\n+\n+\tfor (ntfs = 0; ntfs < 2; ntfs++)\n+\t\tfor (hfs = 0; hfs < 2; hfs++) {\n+\t\t\trepo_config_values(the_repository)->protect_ntfs = ntfs;\n+\t\t\trepo_config_values(the_repository)->protect_hfs = hfs;\n \t\t\tcumul = 0;\n \t\t\tcumul2 = 0;\n \t\t\tfor (i = 0; i < repetitions; i++) {\n@@ -285,18 +291,18 @@ static int protect_ntfs_hfs_benchmark(int argc, const char **argv)\n \t\t\t\tfor (j = 0; j < nr; j++)\n \t\t\t\t\tverify_path(names[j], file_mode);\n \t\t\t\tend = getnanotime();\n-\t\t\t\tprintf(\"protect_ntfs = %d, protect_hfs = %d: %lfms\\n\", protect_ntfs, protect_hfs, (end-begin) / (double)1e6);\n+\t\t\t\tprintf(\"protect_ntfs = %d, protect_hfs = %d: %lfms\\n\", ntfs, hfs, (end-begin) / (double)1e6);\n \t\t\t\tcumul += end - begin;\n \t\t\t\tcumul2 += (end - begin) * (end - begin);\n \t\t\t}\n-\t\t\tm[protect_ntfs][protect_hfs] = cumul / (double)repetitions;\n-\t\t\tv[protect_ntfs][protect_hfs] = my_sqrt(cumul2 / (double)repetitions - m[protect_ntfs][protect_hfs] * m[protect_ntfs][protect_hfs]);\n-\t\t\tprintf(\"mean: %lfms, stddev: %lfms\\n\", m[protect_ntfs][protect_hfs] / (double)1e6, v[protect_ntfs][protect_hfs] / (double)1e6);\n+\t\t\tm[ntfs][hfs] = cumul / (double)repetitions;\n+\t\t\tv[ntfs][hfs] = my_sqrt(cumul2 / (double)repetitions - m[ntfs][hfs] * m[ntfs][hfs]);\n+\t\t\tprintf(\"mean: %lfms, stddev: %lfms\\n\", m[ntfs][hfs] / (double)1e6, v[ntfs][hfs] / (double)1e6);\n \t\t}\n \n-\tfor (protect_ntfs = 0; protect_ntfs < 2; protect_ntfs++)\n-\t\tfor (protect_hfs = 0; protect_hfs < 2; protect_hfs++)\n-\t\t\tprintf(\"ntfs=%d/hfs=%d: %lf%% slower\\n\", protect_ntfs, protect_hfs, (m[protect_ntfs][protect_hfs] - m[0][0]) * 100 / m[0][0]);\n+\tfor (ntfs = 0; ntfs < 2; ntfs++)\n+\t\tfor (hfs = 0; hfs < 2; hfs++)\n+\t\t\tprintf(\"ntfs=%d/hfs=%d: %lf%% slower\\n\", ntfs, hfs, (m[ntfs][hfs] - m[0][0]) * 100 / m[0][0]);\n \n \treturn 0;\n }\n-- \n2.43.0\n\n"}]}