Re: [PATCH v5 1/5] setup: add gentle version of read_gitfile
- From
Stefan Beller <sbeller@google.com>
- Date
- Apr 29, 2015, 23:47 UTC
- Message-ID
- <CAGZ79kY95mxKWwTPSB0S5c0eux1ButhuvGz91GQUz8WXt1w18w@mail.gmail.com>
- In-Reply-To
- <1430030985-14499-2-git-send-email-erik.elfstrom@gmail.com>
On Sat, Apr 25, 2015 at 11:49 PM, Erik Elfström <erik.elfstrom@gmail.com> wrote:
Show 91 quoted lines
> 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>
> ---
> cache.h | 11 ++++++++-
> setup.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++--------------
> 2 files changed, 75 insertions(+), 18 deletions(-)
>
> diff --git a/cache.h b/cache.h
> index 3d3244b..868e4d3 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -431,7 +431,16 @@ extern int set_git_dir(const char *path);
> 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);
>
> diff --git a/setup.c b/setup.c
> index 979b13f..c4538ca 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -335,35 +335,53 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
> /*
> * 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;Sorry for the late review.
So when you jump from here to the cleanup, there is no close(fd) involved? I think there are code paths now, which leak fd.
Show 70 quoted lines
> + }
> 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;
>
> @@ -378,11 +396,41 @@ const char *read_gitfile(const char *path)
> 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;
> + }
> 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;
> }
>
> --
> 2.4.0.rc3.8.gbb31afb
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html