setup: extract path_allowlist_apply()

In a following commit we are going to check whether a repository is
part of an allowlist specified in a config variable.

To prepare for that let's extract existing code from
safe_directory_cb() into a new path_allowlist_apply() helper that will
help with such checks.

While at it let's make the helper's code simpler and more generic.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Christian Couder
2026-08-07 15:55:08 +02:00
committed by Junio C Hamano
parent fa35fef800
commit bc0897872d

107
setup.c
View File

@@ -1329,6 +1329,64 @@ static int canonicalize_ceiling_entry(struct string_list_item *item,
}
}
static void path_allowlist_apply(const char *key, const char *value,
const char *target_path, int *is_match)
{
char *allowed = NULL;
char *normalized = NULL;
if (!value || !*value) {
*is_match = 0;
return;
}
if (!strcmp(value, "*")) {
*is_match = 1;
return;
}
if (git_config_pathname(&allowed, key, value) || !allowed)
return;
/*
* Setting the config variable to a non-absolute path makes
* little sense---it won't be relative to the configuration
* file the item is defined in. Except for ".", which means
* "if we are at the top level of a repository, then it is
* OK", which is slightly tighter than "*" that allows
* discovery.
*/
if (!is_absolute_path(allowed) && strcmp(allowed, ".")) {
warning(_("%s '%s' not absolute"), key, allowed);
goto end;
}
/*
* A .gitconfig in $HOME may be shared across different
* machines and the config variable entries may or may not
* exist as paths on all of these machines. In other words,
* it is not a warning worthy event when there is no such path
* on this machine---the entry may be useful elsewhere.
*/
normalized = real_pathdup(allowed, 0);
if (!normalized)
goto end;
if (ends_with(normalized, "/*")) {
size_t len = strlen(normalized);
if (!fspathncmp(normalized, target_path, len - 1))
*is_match = 1;
goto end;
}
if (!fspathcmp(target_path, normalized))
*is_match = 1;
end:
free(normalized);
free(allowed);
}
struct safe_directory_data {
char *path;
int is_safe;
@@ -1342,54 +1400,7 @@ static int safe_directory_cb(const char *key, const char *value,
if (strcmp(key, "safe.directory"))
return 0;
if (!value || !*value) {
data->is_safe = 0;
} else if (!strcmp(value, "*")) {
data->is_safe = 1;
} else {
char *allowed = NULL;
if (!git_config_pathname(&allowed, key, value) && allowed) {
char *normalized = NULL;
/*
* Setting safe.directory to a non-absolute path
* makes little sense---it won't be relative to
* the configuration file the item is defined in.
* Except for ".", which means "if we are at the top
* level of a repository, then it is OK", which is
* slightly tighter than "*" that allows discovery.
*/
if (!is_absolute_path(allowed) && strcmp(allowed, ".")) {
warning(_("safe.directory '%s' not absolute"),
allowed);
goto next;
}
/*
* A .gitconfig in $HOME may be shared across
* different machines and safe.directory entries
* may or may not exist as paths on all of these
* machines. In other words, it is not a warning
* worthy event when there is no such path on this
* machine---the entry may be useful elsewhere.
*/
normalized = real_pathdup(allowed, 0);
if (!normalized)
goto next;
if (ends_with(normalized, "/*")) {
size_t len = strlen(normalized);
if (!fspathncmp(normalized, data->path, len - 1))
data->is_safe = 1;
} else if (!fspathcmp(data->path, normalized)) {
data->is_safe = 1;
}
next:
free(normalized);
free(allowed);
}
}
path_allowlist_apply(key, value, data->path, &data->is_safe);
return 0;
}