Merge branch 'nd/fixup-linked-gitdir'
authorJunio C Hamano <gitster@pobox.com>
Tue, 1 Sep 2015 23:31:06 +0000 (16:31 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 1 Sep 2015 23:31:07 +0000 (16:31 -0700)
The code in "multiple-worktree" support that attempted to recover
from an inconsistent state updated an incorrect file.

* nd/fixup-linked-gitdir:
setup: update the right file in multiple checkouts

1  2 
setup.c
diff --combined setup.c
index a206781d58d535887be3f8a86bfda56c5d119d95,465b42a1d7aecc3991c9dd2c592d8fa164ba545e..a17c51e61d75ac8280bf04d95c50d7bdfd6d7a0e
+++ b/setup.c
@@@ -402,67 -402,44 +402,67 @@@ static void update_linked_gitdir(const 
        struct strbuf path = STRBUF_INIT;
        struct stat st;
  
-       strbuf_addf(&path, "%s/gitfile", gitdir);
+       strbuf_addf(&path, "%s/gitdir", gitdir);
        if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
-               write_file_gently(path.buf, "%s", gitfile);
 -              write_file(path.buf, 1, "%s\n", gitfile);
++              write_file(path.buf, "%s", gitfile);
        strbuf_release(&path);
  }
  
  /*
   * 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;
 +      const int max_file_size = 1 << 20;  /* 1MB */
 +      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;
 +      }
 +      if (st.st_size > max_file_size) {
 +              error_code = READ_GITFILE_ERR_TOO_LARGE;
 +              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;
  
                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:
 +      if (return_error_code)
 +              *return_error_code = error_code;
 +      else if (error_code) {
 +              switch (error_code) {
 +              case READ_GITFILE_ERR_STAT_FAILED:
 +              case READ_GITFILE_ERR_NOT_A_FILE:
 +                      /* non-fatal; follow return path */
 +                      break;
 +              case READ_GITFILE_ERR_OPEN_FAILED:
 +                      die_errno("Error opening '%s'", path);
 +              case READ_GITFILE_ERR_TOO_LARGE:
 +                      die("Too large to be a .git file: '%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);
 +              }
 +      }
 +
        free(buf);
 -      return path;
 +      return error_code ? NULL : path;
  }
  
  static const char *setup_explicit_git_dir(const char *gitdirenv,