repository.con commit read-cache: fix index corruption with index v4 (0b90b88)
   1#include "cache.h"
   2#include "repository.h"
   3#include "config.h"
   4#include "submodule-config.h"
   5
   6/* The main repository */
   7static struct repository the_repo;
   8struct repository *the_repository = &the_repo;
   9
  10static char *git_path_from_env(const char *envvar, const char *git_dir,
  11                               const char *path, int fromenv)
  12{
  13        if (fromenv) {
  14                const char *value = getenv(envvar);
  15                if (value)
  16                        return xstrdup(value);
  17        }
  18
  19        return xstrfmt("%s/%s", git_dir, path);
  20}
  21
  22static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)
  23{
  24        if (fromenv) {
  25                const char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);
  26                if (value) {
  27                        strbuf_addstr(sb, value);
  28                        return 1;
  29                }
  30        }
  31
  32        return get_common_dir_noenv(sb, gitdir);
  33}
  34
  35static void repo_setup_env(struct repository *repo)
  36{
  37        struct strbuf sb = STRBUF_INIT;
  38
  39        repo->different_commondir = find_common_dir(&sb, repo->gitdir,
  40                                                    !repo->ignore_env);
  41        repo->commondir = strbuf_detach(&sb, NULL);
  42        repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,
  43                                            "objects", !repo->ignore_env);
  44        repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,
  45                                             "info/grafts", !repo->ignore_env);
  46        repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,
  47                                             "index", !repo->ignore_env);
  48}
  49
  50void repo_set_gitdir(struct repository *repo, const char *path)
  51{
  52        const char *gitfile = read_gitfile(path);
  53
  54        /*
  55         * NEEDSWORK: Eventually we want to be able to free gitdir and the rest
  56         * of the environment before reinitializing it again, but we have some
  57         * crazy code paths where we try to set gitdir with the current gitdir
  58         * and we don't want to free gitdir before copying the passed in value.
  59         */
  60        repo->gitdir = xstrdup(gitfile ? gitfile : path);
  61
  62        repo_setup_env(repo);
  63}
  64
  65/*
  66 * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
  67 * Return 0 upon success and a non-zero value upon failure.
  68 */
  69static int repo_init_gitdir(struct repository *repo, const char *gitdir)
  70{
  71        int ret = 0;
  72        int error = 0;
  73        char *abspath = NULL;
  74        const char *resolved_gitdir;
  75
  76        abspath = real_pathdup(gitdir, 0);
  77        if (!abspath) {
  78                ret = -1;
  79                goto out;
  80        }
  81
  82        /* 'gitdir' must reference the gitdir directly */
  83        resolved_gitdir = resolve_gitdir_gently(abspath, &error);
  84        if (!resolved_gitdir) {
  85                ret = -1;
  86                goto out;
  87        }
  88
  89        repo_set_gitdir(repo, resolved_gitdir);
  90
  91out:
  92        free(abspath);
  93        return ret;
  94}
  95
  96void repo_set_worktree(struct repository *repo, const char *path)
  97{
  98        repo->worktree = real_pathdup(path, 1);
  99}
 100
 101static int read_and_verify_repository_format(struct repository_format *format,
 102                                             const char *commondir)
 103{
 104        int ret = 0;
 105        struct strbuf sb = STRBUF_INIT;
 106
 107        strbuf_addf(&sb, "%s/config", commondir);
 108        read_repository_format(format, sb.buf);
 109        strbuf_reset(&sb);
 110
 111        if (verify_repository_format(format, &sb) < 0) {
 112                warning("%s", sb.buf);
 113                ret = -1;
 114        }
 115
 116        strbuf_release(&sb);
 117        return ret;
 118}
 119
 120/*
 121 * Initialize 'repo' based on the provided 'gitdir'.
 122 * Return 0 upon success and a non-zero value upon failure.
 123 */
 124int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
 125{
 126        struct repository_format format;
 127        memset(repo, 0, sizeof(*repo));
 128
 129        repo->ignore_env = 1;
 130
 131        if (repo_init_gitdir(repo, gitdir))
 132                goto error;
 133
 134        if (read_and_verify_repository_format(&format, repo->commondir))
 135                goto error;
 136
 137        if (worktree)
 138                repo_set_worktree(repo, worktree);
 139
 140        return 0;
 141
 142error:
 143        repo_clear(repo);
 144        return -1;
 145}
 146
 147/*
 148 * Initialize 'submodule' as the submodule given by 'path' in parent repository
 149 * 'superproject'.
 150 * Return 0 upon success and a non-zero value upon failure.
 151 */
 152int repo_submodule_init(struct repository *submodule,
 153                        struct repository *superproject,
 154                        const char *path)
 155{
 156        const struct submodule *sub;
 157        struct strbuf gitdir = STRBUF_INIT;
 158        struct strbuf worktree = STRBUF_INIT;
 159        int ret = 0;
 160
 161        sub = submodule_from_cache(superproject, &null_oid, path);
 162        if (!sub) {
 163                ret = -1;
 164                goto out;
 165        }
 166
 167        strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
 168        strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
 169
 170        if (repo_init(submodule, gitdir.buf, worktree.buf)) {
 171                /*
 172                 * If initilization fails then it may be due to the submodule
 173                 * not being populated in the superproject's worktree.  Instead
 174                 * we can try to initilize the submodule by finding it's gitdir
 175                 * in the superproject's 'modules' directory.  In this case the
 176                 * submodule would not have a worktree.
 177                 */
 178                strbuf_reset(&gitdir);
 179                strbuf_repo_git_path(&gitdir, superproject,
 180                                     "modules/%s", sub->name);
 181
 182                if (repo_init(submodule, gitdir.buf, NULL)) {
 183                        ret = -1;
 184                        goto out;
 185                }
 186        }
 187
 188        submodule->submodule_prefix = xstrfmt("%s%s/",
 189                                              superproject->submodule_prefix ?
 190                                              superproject->submodule_prefix :
 191                                              "", path);
 192
 193out:
 194        strbuf_release(&gitdir);
 195        strbuf_release(&worktree);
 196        return ret;
 197}
 198
 199void repo_clear(struct repository *repo)
 200{
 201        free(repo->gitdir);
 202        repo->gitdir = NULL;
 203        free(repo->commondir);
 204        repo->commondir = NULL;
 205        free(repo->objectdir);
 206        repo->objectdir = NULL;
 207        free(repo->graft_file);
 208        repo->graft_file = NULL;
 209        free(repo->index_file);
 210        repo->index_file = NULL;
 211        free(repo->worktree);
 212        repo->worktree = NULL;
 213        free(repo->submodule_prefix);
 214        repo->submodule_prefix = NULL;
 215
 216        if (repo->config) {
 217                git_configset_clear(repo->config);
 218                free(repo->config);
 219                repo->config = NULL;
 220        }
 221
 222        if (repo->submodule_cache) {
 223                submodule_cache_free(repo->submodule_cache);
 224                repo->submodule_cache = NULL;
 225        }
 226
 227        if (repo->index) {
 228                discard_index(repo->index);
 229                free(repo->index);
 230                repo->index = NULL;
 231        }
 232}
 233
 234int repo_read_index(struct repository *repo)
 235{
 236        if (!repo->index)
 237                repo->index = xcalloc(1, sizeof(*repo->index));
 238        else
 239                discard_index(repo->index);
 240
 241        return read_index_from(repo->index, repo->index_file);
 242}