setup: add gentle version of read_gitfile

read_gitfile will die on most error cases. This makes it unsuitable
for speculative calls. Extract the core logic and provide a gentle
version that returns NULL on failure.

The first usecase of the new gentle version will be to probe for
submodules during git clean.

Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Erik Elfström <erik.elfstrom@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Erik Elfström 2015-06-09 20:24:35 +02:00 коммит произвёл Junio C Hamano
Родитель 7974889a05
Коммит a93bedada8
2 изменённых файлов: 75 добавлений и 20 удалений

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

@ -446,7 +446,16 @@ extern int get_common_dir(struct strbuf *sb, const char *gitdir);
extern const char *get_git_namespace(void);
extern const char *strip_namespace(const char *namespaced_ref);
extern const char *get_git_work_tree(void);
extern const char *read_gitfile(const char *path);
#define READ_GITFILE_ERR_STAT_FAILED 1
#define READ_GITFILE_ERR_NOT_A_FILE 2
#define READ_GITFILE_ERR_OPEN_FAILED 3
#define READ_GITFILE_ERR_READ_FAILED 4
#define READ_GITFILE_ERR_INVALID_FORMAT 5
#define READ_GITFILE_ERR_NO_PATH 6
#define READ_GITFILE_ERR_NOT_A_REPO 7
extern const char *read_gitfile_gently(const char *path, int *return_error_code);
#define read_gitfile(path) read_gitfile_gently((path), NULL)
extern const char *resolve_gitdir(const char *suspect);
extern void set_git_work_tree(const char *tree);

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

@ -406,35 +406,53 @@ static void update_linked_gitdir(const char *gitfile, const char *gitdir)
/*
* Try to read the location of the git directory from the .git file,
* return path to git directory if found.
*
* On failure, if return_error_code is not NULL, return_error_code
* will be set to an error code and NULL will be returned. If
* return_error_code is NULL the function will die instead (for most
* cases).
*/
const char *read_gitfile(const char *path)
const char *read_gitfile_gently(const char *path, int *return_error_code)
{
char *buf;
char *dir;
int error_code = 0;
char *buf = NULL;
char *dir = NULL;
const char *slash;
struct stat st;
int fd;
ssize_t len;
if (stat(path, &st))
return NULL;
if (!S_ISREG(st.st_mode))
return NULL;
if (stat(path, &st)) {
error_code = READ_GITFILE_ERR_STAT_FAILED;
goto cleanup_return;
}
if (!S_ISREG(st.st_mode)) {
error_code = READ_GITFILE_ERR_NOT_A_FILE;
goto cleanup_return;
}
fd = open(path, O_RDONLY);
if (fd < 0)
die_errno("Error opening '%s'", path);
if (fd < 0) {
error_code = READ_GITFILE_ERR_OPEN_FAILED;
goto cleanup_return;
}
buf = xmalloc(st.st_size + 1);
len = read_in_full(fd, buf, st.st_size);
close(fd);
if (len != st.st_size)
die("Error reading %s", path);
if (len != st.st_size) {
error_code = READ_GITFILE_ERR_READ_FAILED;
goto cleanup_return;
}
buf[len] = '\0';
if (!starts_with(buf, "gitdir: "))
die("Invalid gitfile format: %s", path);
if (!starts_with(buf, "gitdir: ")) {
error_code = READ_GITFILE_ERR_INVALID_FORMAT;
goto cleanup_return;
}
while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
len--;
if (len < 9)
die("No path in gitfile: %s", path);
if (len < 9) {
error_code = READ_GITFILE_ERR_NO_PATH;
goto cleanup_return;
}
buf[len] = '\0';
dir = buf + 8;
@ -448,14 +466,42 @@ const char *read_gitfile(const char *path)
free(buf);
buf = dir;
}
if (!is_git_directory(dir))
die("Not a git repository: %s", dir);
if (!is_git_directory(dir)) {
error_code = READ_GITFILE_ERR_NOT_A_REPO;
goto cleanup_return;
}
update_linked_gitdir(path, dir);
path = real_path(dir);
cleanup_return:
free(buf);
if (return_error_code)
*return_error_code = error_code;
if (error_code) {
if (return_error_code)
return NULL;
switch (error_code) {
case READ_GITFILE_ERR_STAT_FAILED:
case READ_GITFILE_ERR_NOT_A_FILE:
return NULL;
case READ_GITFILE_ERR_OPEN_FAILED:
die_errno("Error opening '%s'", path);
case READ_GITFILE_ERR_READ_FAILED:
die("Error reading %s", path);
case READ_GITFILE_ERR_INVALID_FORMAT:
die("Invalid gitfile format: %s", path);
case READ_GITFILE_ERR_NO_PATH:
die("No path in gitfile: %s", path);
case READ_GITFILE_ERR_NOT_A_REPO:
die("Not a git repository: %s", dir);
default:
assert(0);
}
}
return path;
}