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>

Erik Elfström committed Jun 9, 2015 at 20:24 UTC a93bedada88dc15b0143708e1cb87c8fe9b9c705
2 files changed +75 -20
cache.h
+10 -1
@@ -446,7 +446,16 @@ extern int get_common_dir(struct strbuf *sb, const char *gitdir);
446 extern const char *get_git_namespace(void);
447 extern const char *strip_namespace(const char *namespaced_ref);
448 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)
459 extern const char *resolve_gitdir(const char *suspect);
460 extern void set_git_work_tree(const char *tree);
461
setup.c
+65 -19
@@ -406,35 +406,53 @@ static void update_linked_gitdir(const char *gitfile, const char *gitdir)
406 /*
407 * Try to read the location of the git directory from the .git file,
408 * 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).
414 */
410 -const char *read_gitfile(const char *path)
415 +const char *read_gitfile_gently(const char *path, int *return_error_code)
416 {
412 - char *buf;
413 - char *dir;
417 + int error_code = 0;
418 + char *buf = NULL;
419 + char *dir = NULL;
420 const char *slash;
421 struct stat st;
422 int fd;
423 ssize_t len;
424
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 + }
433 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 + }
438 buf = xmalloc(st.st_size + 1);
439 len = read_in_full(fd, buf, st.st_size);
440 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 + }
445 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 + }
450 while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
451 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 + }
456 buf[len] = '\0';
457 dir = buf + 8;
458
@@ -448,14 +466,42 @@ const char *read_gitfile(const char *path)
466 free(buf);
467 buf = dir;
468 }
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 + }
473 update_linked_gitdir(path, dir);
474 path = real_path(dir);
475
476 +cleanup_return:
477 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 +
505 return path;
506 }
507