Skip to content

Commit a93beda

Browse files
elfstromgitster
authored andcommitted
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>
1 parent 7974889 commit a93beda

File tree

2 files changed

+75
-20
lines changed

2 files changed

+75
-20
lines changed

cache.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,16 @@ extern int get_common_dir(struct strbuf *sb, const char *gitdir);
446446
extern const char *get_git_namespace(void);
447447
extern const char *strip_namespace(const char *namespaced_ref);
448448
extern const char *get_git_work_tree(void);
449-
extern const char *read_gitfile(const char *path);
449+
450+
#define READ_GITFILE_ERR_STAT_FAILED 1
451+
#define READ_GITFILE_ERR_NOT_A_FILE 2
452+
#define READ_GITFILE_ERR_OPEN_FAILED 3
453+
#define READ_GITFILE_ERR_READ_FAILED 4
454+
#define READ_GITFILE_ERR_INVALID_FORMAT 5
455+
#define READ_GITFILE_ERR_NO_PATH 6
456+
#define READ_GITFILE_ERR_NOT_A_REPO 7
457+
extern const char *read_gitfile_gently(const char *path, int *return_error_code);
458+
#define read_gitfile(path) read_gitfile_gently((path), NULL)
450459
extern const char *resolve_gitdir(const char *suspect);
451460
extern void set_git_work_tree(const char *tree);
452461

setup.c

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -406,35 +406,53 @@ static void update_linked_gitdir(const char *gitfile, const char *gitdir)
406406
/*
407407
* Try to read the location of the git directory from the .git file,
408408
* return path to git directory if found.
409+
*
410+
* On failure, if return_error_code is not NULL, return_error_code
411+
* will be set to an error code and NULL will be returned. If
412+
* return_error_code is NULL the function will die instead (for most
413+
* cases).
409414
*/
410-
const char *read_gitfile(const char *path)
415+
const char *read_gitfile_gently(const char *path, int *return_error_code)
411416
{
412-
char *buf;
413-
char *dir;
417+
int error_code = 0;
418+
char *buf = NULL;
419+
char *dir = NULL;
414420
const char *slash;
415421
struct stat st;
416422
int fd;
417423
ssize_t len;
418424

419-
if (stat(path, &st))
420-
return NULL;
421-
if (!S_ISREG(st.st_mode))
422-
return NULL;
425+
if (stat(path, &st)) {
426+
error_code = READ_GITFILE_ERR_STAT_FAILED;
427+
goto cleanup_return;
428+
}
429+
if (!S_ISREG(st.st_mode)) {
430+
error_code = READ_GITFILE_ERR_NOT_A_FILE;
431+
goto cleanup_return;
432+
}
423433
fd = open(path, O_RDONLY);
424-
if (fd < 0)
425-
die_errno("Error opening '%s'", path);
434+
if (fd < 0) {
435+
error_code = READ_GITFILE_ERR_OPEN_FAILED;
436+
goto cleanup_return;
437+
}
426438
buf = xmalloc(st.st_size + 1);
427439
len = read_in_full(fd, buf, st.st_size);
428440
close(fd);
429-
if (len != st.st_size)
430-
die("Error reading %s", path);
441+
if (len != st.st_size) {
442+
error_code = READ_GITFILE_ERR_READ_FAILED;
443+
goto cleanup_return;
444+
}
431445
buf[len] = '\0';
432-
if (!starts_with(buf, "gitdir: "))
433-
die("Invalid gitfile format: %s", path);
446+
if (!starts_with(buf, "gitdir: ")) {
447+
error_code = READ_GITFILE_ERR_INVALID_FORMAT;
448+
goto cleanup_return;
449+
}
434450
while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
435451
len--;
436-
if (len < 9)
437-
die("No path in gitfile: %s", path);
452+
if (len < 9) {
453+
error_code = READ_GITFILE_ERR_NO_PATH;
454+
goto cleanup_return;
455+
}
438456
buf[len] = '\0';
439457
dir = buf + 8;
440458

@@ -448,14 +466,42 @@ const char *read_gitfile(const char *path)
448466
free(buf);
449467
buf = dir;
450468
}
451-
452-
if (!is_git_directory(dir))
453-
die("Not a git repository: %s", dir);
454-
469+
if (!is_git_directory(dir)) {
470+
error_code = READ_GITFILE_ERR_NOT_A_REPO;
471+
goto cleanup_return;
472+
}
455473
update_linked_gitdir(path, dir);
456474
path = real_path(dir);
457475

476+
cleanup_return:
458477
free(buf);
478+
479+
if (return_error_code)
480+
*return_error_code = error_code;
481+
482+
if (error_code) {
483+
if (return_error_code)
484+
return NULL;
485+
486+
switch (error_code) {
487+
case READ_GITFILE_ERR_STAT_FAILED:
488+
case READ_GITFILE_ERR_NOT_A_FILE:
489+
return NULL;
490+
case READ_GITFILE_ERR_OPEN_FAILED:
491+
die_errno("Error opening '%s'", path);
492+
case READ_GITFILE_ERR_READ_FAILED:
493+
die("Error reading %s", path);
494+
case READ_GITFILE_ERR_INVALID_FORMAT:
495+
die("Invalid gitfile format: %s", path);
496+
case READ_GITFILE_ERR_NO_PATH:
497+
die("No path in gitfile: %s", path);
498+
case READ_GITFILE_ERR_NOT_A_REPO:
499+
die("Not a git repository: %s", dir);
500+
default:
501+
assert(0);
502+
}
503+
}
504+
459505
return path;
460506
}
461507

0 commit comments

Comments
 (0)