setup: add discover_git_directory_reason()

There are many reasons why discovering a Git directory may fail. In
particular, 8959555cee (setup_git_directory(): add an owner check for
the top-level directory, 2022-03-02) added ownership checks as a
security precaution.

Callers attempting to set up a Git directory may want to inform the user
about the reason for the failure. For that, expose the enum
discovery_result from within setup.c and into cache.h where
discover_git_directory() is defined.

I initially wanted to change the return type of discover_git_directory()
to be this enum, but several callers rely upon the "zero means success".
The two problems with this are:

1. The zero value of the enum is actually GIT_DIR_NONE, so nonpositive
   results are errors.

2. There are multiple successful states, so some positive results are
   successful.

Instead of updating all callers immediately, add a new method,
discover_git_directory_reason(), and convert discover_git_directory() to
be a thin shim on top of it.

Because there are extra checks that discover_git_directory_reason() does
after setup_git_directory_gently_1(), there are other modes that can be
returned for failure states. Add these modes to the enum, but be sure to
explicitly add them as BUG() states in the switch of
setup_git_directory_gently().

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
This commit is contained in:
Derrick Stolee 2022-05-24 14:39:29 -04:00 коммит произвёл Johannes Schindelin
Родитель 071493708a
Коммит f37b612cf7
2 изменённых файлов: 40 добавлений и 22 удалений

31
cache.h
Просмотреть файл

@ -632,6 +632,29 @@ void set_git_work_tree(const char *tree);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
void setup_work_tree(void);
/*
* discover_git_directory_reason() is similar to discover_git_directory(),
* except it returns an enum value instead. It is important to note that
* a zero-valued return here is actually GIT_DIR_NONE, which is different
* from discover_git_directory.
*/
enum discovery_result {
GIT_DIR_NONE = 0,
GIT_DIR_EXPLICIT,
GIT_DIR_DISCOVERED,
GIT_DIR_BARE,
/* these are errors */
GIT_DIR_HIT_CEILING = -1,
GIT_DIR_HIT_MOUNT_POINT = -2,
GIT_DIR_INVALID_GITFILE = -3,
GIT_DIR_INVALID_OWNERSHIP = -4,
GIT_DIR_INVALID_FORMAT = -5,
GIT_DIR_CWD_FAILURE = -6,
};
enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
struct strbuf *gitdir);
/*
* Find the commondir and gitdir of the repository that contains the current
* working directory, without changing the working directory or other global
@ -640,8 +663,12 @@ void setup_work_tree(void);
* both have the same result appended to the buffer. The return value is
* either 0 upon success and non-zero if no repository was found.
*/
int discover_git_directory(struct strbuf *commondir,
struct strbuf *gitdir);
static inline int discover_git_directory(struct strbuf *commondir,
struct strbuf *gitdir)
{
return discover_git_directory_reason(commondir, gitdir) <= 0;
}
const char *setup_git_directory_gently(int *);
const char *setup_git_directory(void);
char *prefix_path(const char *prefix, int len, const char *path);

31
setup.c
Просмотреть файл

@ -1160,18 +1160,6 @@ static int ensure_valid_ownership(const char *gitfile,
return data.is_safe;
}
enum discovery_result {
GIT_DIR_NONE = 0,
GIT_DIR_EXPLICIT,
GIT_DIR_DISCOVERED,
GIT_DIR_BARE,
/* these are errors */
GIT_DIR_HIT_CEILING = -1,
GIT_DIR_HIT_MOUNT_POINT = -2,
GIT_DIR_INVALID_GITFILE = -3,
GIT_DIR_INVALID_OWNERSHIP = -4
};
/*
* We cannot decide in this function whether we are in the work tree or
* not, since the config can only be read _after_ this function was called.
@ -1318,21 +1306,22 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
}
}
int discover_git_directory(struct strbuf *commondir,
struct strbuf *gitdir)
enum discovery_result discover_git_directory_reason(struct strbuf *commondir,
struct strbuf *gitdir)
{
struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
size_t gitdir_offset = gitdir->len, cwd_len;
size_t commondir_offset = commondir->len;
struct repository_format candidate = REPOSITORY_FORMAT_INIT;
enum discovery_result result;
if (strbuf_getcwd(&dir))
return -1;
return GIT_DIR_CWD_FAILURE;
cwd_len = dir.len;
if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
if ((result = setup_git_directory_gently_1(&dir, gitdir, 0)) <= 0) {
strbuf_release(&dir);
return -1;
return result;
}
/*
@ -1362,7 +1351,7 @@ int discover_git_directory(struct strbuf *commondir,
strbuf_setlen(commondir, commondir_offset);
strbuf_setlen(gitdir, gitdir_offset);
clear_repository_format(&candidate);
return -1;
return GIT_DIR_INVALID_FORMAT;
}
/* take ownership of candidate.partial_clone */
@ -1371,7 +1360,7 @@ int discover_git_directory(struct strbuf *commondir,
candidate.partial_clone = NULL;
clear_repository_format(&candidate);
return 0;
return result;
}
const char *setup_git_directory_gently(int *nongit_ok)
@ -1462,9 +1451,11 @@ const char *setup_git_directory_gently(int *nongit_ok)
*nongit_ok = 1;
break;
case GIT_DIR_NONE:
case GIT_DIR_CWD_FAILURE:
case GIT_DIR_INVALID_FORMAT:
/*
* As a safeguard against setup_git_directory_gently_1 returning
* this value, fallthrough to BUG. Otherwise it is possible to
* these values, fallthrough to BUG. Otherwise it is possible to
* set startup_info->have_repository to 1 when we did nothing to
* find a repository.
*/