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