diff: handle NULs in get_string_hash()
[git] / repository.c
1 #include "cache.h"
2 #include "repository.h"
3 #include "config.h"
4 #include "submodule-config.h"
5
6 /* The main repository */
7 static struct repository the_repo = {
8         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, 0, 0
9 };
10 struct repository *the_repository = &the_repo;
11
12 static 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
24 static 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
37 static 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
56 void 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
67 /*
68  * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
69  * Return 0 upon success and a non-zero value upon failure.
70  */
71 static int repo_init_gitdir(struct repository *repo, const char *gitdir)
72 {
73         int ret = 0;
74         int error = 0;
75         char *abspath = NULL;
76         const char *resolved_gitdir;
77
78         abspath = real_pathdup(gitdir, 0);
79         if (!abspath) {
80                 ret = -1;
81                 goto out;
82         }
83
84         /* 'gitdir' must reference the gitdir directly */
85         resolved_gitdir = resolve_gitdir_gently(abspath, &error);
86         if (!resolved_gitdir) {
87                 ret = -1;
88                 goto out;
89         }
90
91         repo_set_gitdir(repo, resolved_gitdir);
92
93 out:
94         free(abspath);
95         return ret;
96 }
97
98 void repo_set_worktree(struct repository *repo, const char *path)
99 {
100         repo->worktree = real_pathdup(path, 1);
101 }
102
103 static int read_and_verify_repository_format(struct repository_format *format,
104                                              const char *commondir)
105 {
106         int ret = 0;
107         struct strbuf sb = STRBUF_INIT;
108
109         strbuf_addf(&sb, "%s/config", commondir);
110         read_repository_format(format, sb.buf);
111         strbuf_reset(&sb);
112
113         if (verify_repository_format(format, &sb) < 0) {
114                 warning("%s", sb.buf);
115                 ret = -1;
116         }
117
118         strbuf_release(&sb);
119         return ret;
120 }
121
122 /*
123  * Initialize 'repo' based on the provided 'gitdir'.
124  * Return 0 upon success and a non-zero value upon failure.
125  */
126 int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
127 {
128         struct repository_format format;
129         memset(repo, 0, sizeof(*repo));
130
131         repo->ignore_env = 1;
132
133         if (repo_init_gitdir(repo, gitdir))
134                 goto error;
135
136         if (read_and_verify_repository_format(&format, repo->commondir))
137                 goto error;
138
139         if (worktree)
140                 repo_set_worktree(repo, worktree);
141
142         return 0;
143
144 error:
145         repo_clear(repo);
146         return -1;
147 }
148
149 /*
150  * Initialize 'submodule' as the submodule given by 'path' in parent repository
151  * 'superproject'.
152  * Return 0 upon success and a non-zero value upon failure.
153  */
154 int repo_submodule_init(struct repository *submodule,
155                         struct repository *superproject,
156                         const char *path)
157 {
158         const struct submodule *sub;
159         struct strbuf gitdir = STRBUF_INIT;
160         struct strbuf worktree = STRBUF_INIT;
161         int ret = 0;
162
163         sub = submodule_from_cache(superproject, &null_oid, path);
164         if (!sub) {
165                 ret = -1;
166                 goto out;
167         }
168
169         strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
170         strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
171
172         if (repo_init(submodule, gitdir.buf, worktree.buf)) {
173                 /*
174                  * If initilization fails then it may be due to the submodule
175                  * not being populated in the superproject's worktree.  Instead
176                  * we can try to initilize the submodule by finding it's gitdir
177                  * in the superproject's 'modules' directory.  In this case the
178                  * submodule would not have a worktree.
179                  */
180                 strbuf_reset(&gitdir);
181                 strbuf_repo_git_path(&gitdir, superproject,
182                                      "modules/%s", sub->name);
183
184                 if (repo_init(submodule, gitdir.buf, NULL)) {
185                         ret = -1;
186                         goto out;
187                 }
188         }
189
190         submodule->submodule_prefix = xstrfmt("%s%s/",
191                                               superproject->submodule_prefix ?
192                                               superproject->submodule_prefix :
193                                               "", path);
194
195 out:
196         strbuf_release(&gitdir);
197         strbuf_release(&worktree);
198         return ret;
199 }
200
201 void repo_clear(struct repository *repo)
202 {
203         FREE_AND_NULL(repo->gitdir);
204         FREE_AND_NULL(repo->commondir);
205         FREE_AND_NULL(repo->objectdir);
206         FREE_AND_NULL(repo->graft_file);
207         FREE_AND_NULL(repo->index_file);
208         FREE_AND_NULL(repo->worktree);
209         FREE_AND_NULL(repo->submodule_prefix);
210
211         if (repo->config) {
212                 git_configset_clear(repo->config);
213                 FREE_AND_NULL(repo->config);
214         }
215
216         if (repo->submodule_cache) {
217                 submodule_cache_free(repo->submodule_cache);
218                 repo->submodule_cache = NULL;
219         }
220
221         if (repo->index) {
222                 discard_index(repo->index);
223                 FREE_AND_NULL(repo->index);
224         }
225 }
226
227 int repo_read_index(struct repository *repo)
228 {
229         if (!repo->index)
230                 repo->index = xcalloc(1, sizeof(*repo->index));
231
232         return read_index_from(repo->index, repo->index_file);
233 }