]> git.proxmox.com Git - libgit2.git/blob - src/submodule.c
submodule: avoid passing NULL pointers to strncmp
[libgit2.git] / src / submodule.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8 #include "common.h"
9 #include "git2/config.h"
10 #include "git2/sys/config.h"
11 #include "git2/types.h"
12 #include "git2/index.h"
13 #include "buffer.h"
14 #include "buf_text.h"
15 #include "vector.h"
16 #include "posix.h"
17 #include "config_file.h"
18 #include "config.h"
19 #include "repository.h"
20 #include "submodule.h"
21 #include "tree.h"
22 #include "iterator.h"
23 #include "path.h"
24 #include "index.h"
25
26 #define GIT_MODULES_FILE ".gitmodules"
27
28 static git_cvar_map _sm_update_map[] = {
29 {GIT_CVAR_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
30 {GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
31 {GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
32 {GIT_CVAR_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
33 {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
34 {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
35 };
36
37 static git_cvar_map _sm_ignore_map[] = {
38 {GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
39 {GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
40 {GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
41 {GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
42 {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
43 {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
44 };
45
46 static git_cvar_map _sm_recurse_map[] = {
47 {GIT_CVAR_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
48 {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
49 {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
50 };
51
52 enum {
53 CACHE_OK = 0,
54 CACHE_REFRESH = 1,
55 CACHE_FLUSH = 2
56 };
57 enum {
58 GITMODULES_EXISTING = 0,
59 GITMODULES_CREATE = 1,
60 };
61
62 static kh_inline khint_t str_hash_no_trailing_slash(const char *s)
63 {
64 khint_t h;
65
66 for (h = 0; *s; ++s)
67 if (s[1] != '\0' || *s != '/')
68 h = (h << 5) - h + *s;
69
70 return h;
71 }
72
73 static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b)
74 {
75 size_t alen = a ? strlen(a) : 0;
76 size_t blen = b ? strlen(b) : 0;
77
78 if (alen > 0 && a[alen - 1] == '/')
79 alen--;
80 if (blen > 0 && b[blen - 1] == '/')
81 blen--;
82
83 return (alen == 0 && blen == 0) ||
84 (alen == blen && strncmp(a, b, alen) == 0);
85 }
86
87 __KHASH_IMPL(
88 str, static kh_inline, const char *, void *, 1,
89 str_hash_no_trailing_slash, str_equal_no_trailing_slash)
90
91 static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name);
92 static git_config_backend *open_gitmodules(git_repository *repo, int gitmod);
93 static git_config *gitmodules_snapshot(git_repository *repo);
94 static int get_url_base(git_buf *url, git_repository *repo);
95 static int lookup_head_remote_key(git_buf *remote_key, git_repository *repo);
96 static int submodule_load_each(const git_config_entry *entry, void *payload);
97 static int submodule_read_config(git_submodule *sm, git_config *cfg);
98 static int submodule_load_from_wd_lite(git_submodule *);
99 static void submodule_get_index_status(unsigned int *, git_submodule *);
100 static void submodule_get_wd_status(unsigned int *, git_submodule *, git_repository *, git_submodule_ignore_t);
101 static void submodule_update_from_index_entry(git_submodule *sm, const git_index_entry *ie);
102 static void submodule_update_from_head_data(git_submodule *sm, mode_t mode, const git_oid *id);
103
104 static int submodule_cmp(const void *a, const void *b)
105 {
106 return strcmp(((git_submodule *)a)->name, ((git_submodule *)b)->name);
107 }
108
109 static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix)
110 {
111 ssize_t idx = git_buf_rfind(key, '.');
112 git_buf_truncate(key, (size_t)(idx + 1));
113 return git_buf_puts(key, suffix);
114 }
115
116 /*
117 * PUBLIC APIS
118 */
119
120 static void submodule_set_lookup_error(int error, const char *name)
121 {
122 if (!error)
123 return;
124
125 giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ?
126 "No submodule named '%s'" :
127 "Submodule '%s' has not been added yet", name);
128 }
129
130 typedef struct {
131 const char *path;
132 char *name;
133 } fbp_data;
134
135 static int find_by_path(const git_config_entry *entry, void *payload)
136 {
137 fbp_data *data = payload;
138
139 if (!strcmp(entry->value, data->path)) {
140 const char *fdot, *ldot;
141 fdot = strchr(entry->name, '.');
142 ldot = strrchr(entry->name, '.');
143 data->name = git__strndup(fdot + 1, ldot - fdot - 1);
144 GITERR_CHECK_ALLOC(data->name);
145 }
146
147 return 0;
148 }
149
150 /**
151 * Find out the name of a submodule from its path
152 */
153 static int name_from_path(git_buf *out, git_config *cfg, const char *path)
154 {
155 const char *key = "submodule\\..*\\.path";
156 git_config_iterator *iter;
157 git_config_entry *entry;
158 int error;
159
160 if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
161 return error;
162
163 while ((error = git_config_next(&entry, iter)) == 0) {
164 const char *fdot, *ldot;
165 /* TODO: this should maybe be strcasecmp on a case-insensitive fs */
166 if (strcmp(path, entry->value) != 0)
167 continue;
168
169 fdot = strchr(entry->name, '.');
170 ldot = strrchr(entry->name, '.');
171
172 git_buf_clear(out);
173 git_buf_put(out, fdot + 1, ldot - fdot - 1);
174 goto cleanup;
175 }
176
177 if (error == GIT_ITEROVER) {
178 giterr_set(GITERR_SUBMODULE, "could not find a submodule name for '%s'", path);
179 error = GIT_ENOTFOUND;
180 }
181
182 cleanup:
183 git_config_iterator_free(iter);
184 return error;
185 }
186
187 int git_submodule_lookup(
188 git_submodule **out, /* NULL if user only wants to test existence */
189 git_repository *repo,
190 const char *name) /* trailing slash is allowed */
191 {
192 int error;
193 unsigned int location;
194 git_submodule *sm;
195
196 assert(repo && name);
197
198 if ((error = submodule_alloc(&sm, repo, name)) < 0)
199 return error;
200
201 if ((error = git_submodule_reload(sm, false)) < 0) {
202 git_submodule_free(sm);
203 return error;
204 }
205
206 if ((error = git_submodule_location(&location, sm)) < 0) {
207 git_submodule_free(sm);
208 return error;
209 }
210
211 /* If it's not configured or we're looking by path */
212 if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
213 git_config_backend *mods;
214 const char *pattern = "submodule\\..*\\.path";
215 git_buf path = GIT_BUF_INIT;
216 fbp_data data = { NULL, NULL };
217
218 git_buf_puts(&path, name);
219 while (path.ptr[path.size-1] == '/') {
220 path.ptr[--path.size] = '\0';
221 }
222 data.path = path.ptr;
223
224 mods = open_gitmodules(repo, GITMODULES_EXISTING);
225
226 if (mods)
227 error = git_config_file_foreach_match(mods, pattern, find_by_path, &data);
228
229 git_config_file_free(mods);
230
231 if (error < 0) {
232 git_submodule_free(sm);
233 git_buf_free(&path);
234 return error;
235 }
236
237 if (data.name) {
238 git__free(sm->name);
239 sm->name = data.name;
240 sm->path = git_buf_detach(&path);
241
242 /* Try to load again with the right name */
243 if ((error = git_submodule_reload(sm, false)) < 0) {
244 git_submodule_free(sm);
245 return error;
246 }
247 }
248
249 git_buf_free(&path);
250 }
251
252 if ((error = git_submodule_location(&location, sm)) < 0) {
253 git_submodule_free(sm);
254 return error;
255 }
256
257 /* If we still haven't found it, do the WD check */
258 if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
259 git_submodule_free(sm);
260 error = GIT_ENOTFOUND;
261
262 /* If it's not configured, we still check if there's a repo at the path */
263 if (git_repository_workdir(repo)) {
264 git_buf path = GIT_BUF_INIT;
265 if (git_buf_join3(&path,
266 '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
267 return -1;
268
269 if (git_path_exists(path.ptr))
270 error = GIT_EEXISTS;
271
272 git_buf_free(&path);
273 }
274
275 submodule_set_lookup_error(error, name);
276 return error;
277 }
278
279 if (out)
280 *out = sm;
281 else
282 git_submodule_free(sm);
283
284 return 0;
285 }
286
287 static void submodule_free_dup(void *sm)
288 {
289 git_submodule_free(sm);
290 }
291
292 static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
293 {
294 int error = 0;
295 khiter_t pos;
296 git_submodule *sm = NULL;
297
298 pos = git_strmap_lookup_index(map, name);
299 if (git_strmap_valid_index(map, pos)) {
300 sm = git_strmap_value_at(map, pos);
301 goto done;
302 }
303
304 /* if the submodule doesn't exist yet in the map, create it */
305 if ((error = submodule_alloc(&sm, repo, name)) < 0)
306 return error;
307
308 pos = kh_put(str, map, sm->name, &error);
309 /* nobody can beat us to adding it */
310 assert(error != 0);
311 if (error < 0) {
312 git_submodule_free(sm);
313 return error;
314 }
315
316 git_strmap_set_value_at(map, pos, sm);
317
318 done:
319 GIT_REFCOUNT_INC(sm);
320 *out = sm;
321 return 0;
322 }
323
324 static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cfg)
325 {
326 int error;
327 git_iterator *i;
328 const git_index_entry *entry;
329 git_buf name = GIT_BUF_INIT;
330
331 if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
332 return error;
333
334 while (!(error = git_iterator_advance(&entry, i))) {
335 khiter_t pos = git_strmap_lookup_index(map, entry->path);
336 git_submodule *sm;
337
338 git_buf_clear(&name);
339 if (!name_from_path(&name, cfg, entry->path)) {
340 git_strmap_lookup_index(map, name.ptr);
341 }
342
343 if (git_strmap_valid_index(map, pos)) {
344 sm = git_strmap_value_at(map, pos);
345
346 if (S_ISGITLINK(entry->mode))
347 submodule_update_from_index_entry(sm, entry);
348 else
349 sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
350 } else if (S_ISGITLINK(entry->mode)) {
351 if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name.ptr ? name.ptr : entry->path)) {
352 submodule_update_from_index_entry(sm, entry);
353 git_submodule_free(sm);
354 }
355 }
356 }
357
358 if (error == GIT_ITEROVER)
359 error = 0;
360
361 git_buf_free(&name);
362 git_iterator_free(i);
363
364 return error;
365 }
366
367 static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg)
368 {
369 int error;
370 git_iterator *i;
371 const git_index_entry *entry;
372 git_buf name = GIT_BUF_INIT;
373
374 if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
375 return error;
376
377 while (!(error = git_iterator_advance(&entry, i))) {
378 khiter_t pos = git_strmap_lookup_index(map, entry->path);
379 git_submodule *sm;
380
381 git_buf_clear(&name);
382 if (!name_from_path(&name, cfg, entry->path)) {
383 git_strmap_lookup_index(map, name.ptr);
384 }
385
386 if (git_strmap_valid_index(map, pos)) {
387 sm = git_strmap_value_at(map, pos);
388
389 if (S_ISGITLINK(entry->mode))
390 submodule_update_from_head_data(sm, entry->mode, &entry->id);
391 else
392 sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
393 } else if (S_ISGITLINK(entry->mode)) {
394 if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name.ptr ? name.ptr : entry->path)) {
395 submodule_update_from_head_data(
396 sm, entry->mode, &entry->id);
397 git_submodule_free(sm);
398 }
399 }
400 }
401
402 if (error == GIT_ITEROVER)
403 error = 0;
404
405 git_buf_free(&name);
406 git_iterator_free(i);
407
408 return error;
409 }
410
411 /* If have_sm is true, sm is populated, otherwise map an repo are. */
412 typedef struct {
413 git_config *mods;
414 git_strmap *map;
415 git_repository *repo;
416 } lfc_data;
417
418 static int all_submodules(git_repository *repo, git_strmap *map)
419 {
420 int error = 0;
421 git_index *idx = NULL;
422 git_tree *head = NULL;
423 const char *wd = NULL;
424 git_buf path = GIT_BUF_INIT;
425 git_submodule *sm;
426 git_config *mods = NULL;
427 uint32_t mask;
428
429 assert(repo && map);
430
431 /* get sources that we will need to check */
432 if (git_repository_index(&idx, repo) < 0)
433 giterr_clear();
434 if (git_repository_head_tree(&head, repo) < 0)
435 giterr_clear();
436
437 wd = git_repository_workdir(repo);
438 if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
439 goto cleanup;
440
441 /* clear submodule flags that are to be refreshed */
442 mask = 0;
443 mask |= GIT_SUBMODULE_STATUS_IN_INDEX |
444 GIT_SUBMODULE_STATUS__INDEX_FLAGS |
445 GIT_SUBMODULE_STATUS__INDEX_OID_VALID |
446 GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
447
448 mask |= GIT_SUBMODULE_STATUS_IN_HEAD |
449 GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
450 mask |= GIT_SUBMODULE_STATUS_IN_CONFIG;
451 if (mask != 0)
452 mask |= GIT_SUBMODULE_STATUS_IN_WD |
453 GIT_SUBMODULE_STATUS__WD_SCANNED |
454 GIT_SUBMODULE_STATUS__WD_FLAGS |
455 GIT_SUBMODULE_STATUS__WD_OID_VALID;
456
457 /* add submodule information from .gitmodules */
458 if (wd) {
459 lfc_data data = { 0 };
460 data.map = map;
461 data.repo = repo;
462
463 if ((mods = gitmodules_snapshot(repo)) == NULL)
464 goto cleanup;
465
466 data.mods = mods;
467 if ((error = git_config_foreach(
468 mods, submodule_load_each, &data)) < 0)
469 goto cleanup;
470 }
471 /* add back submodule information from index */
472 if (idx) {
473 if ((error = submodules_from_index(map, idx, mods)) < 0)
474 goto cleanup;
475 }
476 /* add submodule information from HEAD */
477 if (head) {
478 if ((error = submodules_from_head(map, head, mods)) < 0)
479 goto cleanup;
480 }
481 /* shallow scan submodules in work tree as needed */
482 if (wd && mask != 0) {
483 git_strmap_foreach_value(map, sm, {
484 submodule_load_from_wd_lite(sm);
485 });
486 }
487
488 cleanup:
489 git_config_free(mods);
490 /* TODO: if we got an error, mark submodule config as invalid? */
491 git_index_free(idx);
492 git_tree_free(head);
493 git_buf_free(&path);
494 return error;
495 }
496
497 int git_submodule_foreach(
498 git_repository *repo,
499 git_submodule_cb callback,
500 void *payload)
501 {
502 git_vector snapshot = GIT_VECTOR_INIT;
503 git_strmap *submodules;
504 git_submodule *sm;
505 int error;
506 size_t i;
507
508 if ((error = git_strmap_alloc(&submodules)) < 0)
509 return error;
510
511 if ((error = all_submodules(repo, submodules)) < 0)
512 goto done;
513
514 if (!(error = git_vector_init(
515 &snapshot, kh_size(submodules), submodule_cmp))) {
516
517 git_strmap_foreach_value(submodules, sm, {
518 if ((error = git_vector_insert(&snapshot, sm)) < 0)
519 break;
520 GIT_REFCOUNT_INC(sm);
521 });
522 }
523
524 if (error < 0)
525 goto done;
526
527 git_vector_uniq(&snapshot, submodule_free_dup);
528
529 git_vector_foreach(&snapshot, i, sm) {
530 if ((error = callback(sm, sm->name, payload)) != 0) {
531 giterr_set_after_callback(error);
532 break;
533 }
534 }
535
536 done:
537 git_vector_foreach(&snapshot, i, sm)
538 git_submodule_free(sm);
539 git_vector_free(&snapshot);
540
541 git_strmap_foreach_value(submodules, sm, {
542 git_submodule_free(sm);
543 });
544 git_strmap_free(submodules);
545
546 return error;
547 }
548
549 static int submodule_repo_init(
550 git_repository **out,
551 git_repository *parent_repo,
552 const char *path,
553 const char *url,
554 bool use_gitlink)
555 {
556 int error = 0;
557 git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
558 git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
559 git_repository *subrepo = NULL;
560
561 error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
562 if (error < 0)
563 goto cleanup;
564
565 initopt.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_REINIT;
566 initopt.origin_url = url;
567
568 /* init submodule repository and add origin remote as needed */
569
570 /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
571 * gitlink in the sub-repo workdir directory to that repository
572 *
573 * Old style: sub-repo goes directly into repo/<name>/.git/
574 */
575 if (use_gitlink) {
576 error = git_buf_join3(
577 &repodir, '/', git_repository_path(parent_repo), "modules", path);
578 if (error < 0)
579 goto cleanup;
580
581 initopt.workdir_path = workdir.ptr;
582 initopt.flags |=
583 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
584 GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
585
586 error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
587 } else
588 error = git_repository_init_ext(&subrepo, workdir.ptr, &initopt);
589
590 cleanup:
591 git_buf_free(&workdir);
592 git_buf_free(&repodir);
593
594 *out = subrepo;
595
596 return error;
597 }
598
599 int git_submodule_add_setup(
600 git_submodule **out,
601 git_repository *repo,
602 const char *url,
603 const char *path,
604 int use_gitlink)
605 {
606 int error = 0;
607 git_config_backend *mods = NULL;
608 git_submodule *sm = NULL;
609 git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
610 git_repository *subrepo = NULL;
611
612 assert(repo && url && path);
613
614 /* see if there is already an entry for this submodule */
615
616 if (git_submodule_lookup(NULL, repo, path) < 0)
617 giterr_clear();
618 else {
619 giterr_set(GITERR_SUBMODULE,
620 "Attempt to add submodule '%s' that already exists", path);
621 return GIT_EEXISTS;
622 }
623
624 /* validate and normalize path */
625
626 if (git__prefixcmp(path, git_repository_workdir(repo)) == 0)
627 path += strlen(git_repository_workdir(repo));
628
629 if (git_path_root(path) >= 0) {
630 giterr_set(GITERR_SUBMODULE, "Submodule path must be a relative path");
631 error = -1;
632 goto cleanup;
633 }
634
635 /* update .gitmodules */
636
637 if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
638 giterr_set(GITERR_SUBMODULE,
639 "Adding submodules to a bare repository is not supported");
640 return -1;
641 }
642
643 if ((error = git_buf_printf(&name, "submodule.%s.path", path)) < 0 ||
644 (error = git_config_file_set_string(mods, name.ptr, path)) < 0)
645 goto cleanup;
646
647 if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
648 (error = git_config_file_set_string(mods, name.ptr, url)) < 0)
649 goto cleanup;
650
651 git_buf_clear(&name);
652
653 /* init submodule repository and add origin remote as needed */
654
655 error = git_buf_joinpath(&name, git_repository_workdir(repo), path);
656 if (error < 0)
657 goto cleanup;
658
659 /* if the repo does not already exist, then init a new repo and add it.
660 * Otherwise, just add the existing repo.
661 */
662 if (!(git_path_exists(name.ptr) &&
663 git_path_contains(&name, DOT_GIT))) {
664
665 /* resolve the actual URL to use */
666 if ((error = git_submodule_resolve_url(&real_url, repo, url)) < 0)
667 goto cleanup;
668
669 if ((error = submodule_repo_init(&subrepo, repo, path, real_url.ptr, use_gitlink)) < 0)
670 goto cleanup;
671 }
672
673 if ((error = git_submodule_lookup(&sm, repo, path)) < 0)
674 goto cleanup;
675
676 error = git_submodule_init(sm, false);
677
678 cleanup:
679 if (error && sm) {
680 git_submodule_free(sm);
681 sm = NULL;
682 }
683 if (out != NULL)
684 *out = sm;
685
686 git_config_file_free(mods);
687 git_repository_free(subrepo);
688 git_buf_free(&real_url);
689 git_buf_free(&name);
690
691 return error;
692 }
693
694 int git_submodule_repo_init(
695 git_repository **out,
696 const git_submodule *sm,
697 int use_gitlink)
698 {
699 int error;
700 git_repository *sub_repo = NULL;
701 const char *configured_url;
702 git_config *cfg = NULL;
703 git_buf buf = GIT_BUF_INIT;
704
705 assert(out && sm);
706
707 /* get the configured remote url of the submodule */
708 if ((error = git_buf_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
709 (error = git_repository_config_snapshot(&cfg, sm->repo)) < 0 ||
710 (error = git_config_get_string(&configured_url, cfg, buf.ptr)) < 0 ||
711 (error = submodule_repo_init(&sub_repo, sm->repo, sm->path, configured_url, use_gitlink)) < 0)
712 goto done;
713
714 *out = sub_repo;
715
716 done:
717 git_config_free(cfg);
718 git_buf_free(&buf);
719 return error;
720 }
721
722 int git_submodule_add_finalize(git_submodule *sm)
723 {
724 int error;
725 git_index *index;
726
727 assert(sm);
728
729 if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
730 (error = git_index_add_bypath(index, GIT_MODULES_FILE)) < 0)
731 return error;
732
733 return git_submodule_add_to_index(sm, true);
734 }
735
736 int git_submodule_add_to_index(git_submodule *sm, int write_index)
737 {
738 int error;
739 git_repository *sm_repo = NULL;
740 git_index *index;
741 git_buf path = GIT_BUF_INIT;
742 git_commit *head;
743 git_index_entry entry;
744 struct stat st;
745
746 assert(sm);
747
748 /* force reload of wd OID by git_submodule_open */
749 sm->flags = sm->flags & ~GIT_SUBMODULE_STATUS__WD_OID_VALID;
750
751 if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
752 (error = git_buf_joinpath(
753 &path, git_repository_workdir(sm->repo), sm->path)) < 0 ||
754 (error = git_submodule_open(&sm_repo, sm)) < 0)
755 goto cleanup;
756
757 /* read stat information for submodule working directory */
758 if (p_stat(path.ptr, &st) < 0) {
759 giterr_set(GITERR_SUBMODULE,
760 "Cannot add submodule without working directory");
761 error = -1;
762 goto cleanup;
763 }
764
765 memset(&entry, 0, sizeof(entry));
766 entry.path = sm->path;
767 git_index_entry__init_from_stat(
768 &entry, &st, !(git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE));
769
770 /* calling git_submodule_open will have set sm->wd_oid if possible */
771 if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) {
772 giterr_set(GITERR_SUBMODULE,
773 "Cannot add submodule without HEAD to index");
774 error = -1;
775 goto cleanup;
776 }
777 git_oid_cpy(&entry.id, &sm->wd_oid);
778
779 if ((error = git_commit_lookup(&head, sm_repo, &sm->wd_oid)) < 0)
780 goto cleanup;
781
782 entry.ctime.seconds = (int32_t)git_commit_time(head);
783 entry.ctime.nanoseconds = 0;
784 entry.mtime.seconds = (int32_t)git_commit_time(head);
785 entry.mtime.nanoseconds = 0;
786
787 git_commit_free(head);
788
789 /* add it */
790 error = git_index_add(index, &entry);
791
792 /* write it, if requested */
793 if (!error && write_index) {
794 error = git_index_write(index);
795
796 if (!error)
797 git_oid_cpy(&sm->index_oid, &sm->wd_oid);
798 }
799
800 cleanup:
801 git_repository_free(sm_repo);
802 git_buf_free(&path);
803 return error;
804 }
805
806 const char *git_submodule_update_to_str(git_submodule_update_t update)
807 {
808 int i;
809 for (i = 0; i < (int)ARRAY_SIZE(_sm_update_map); ++i)
810 if (_sm_update_map[i].map_value == (int)update)
811 return _sm_update_map[i].str_match;
812 return NULL;
813 }
814
815 git_repository *git_submodule_owner(git_submodule *submodule)
816 {
817 assert(submodule);
818 return submodule->repo;
819 }
820
821 const char *git_submodule_name(git_submodule *submodule)
822 {
823 assert(submodule);
824 return submodule->name;
825 }
826
827 const char *git_submodule_path(git_submodule *submodule)
828 {
829 assert(submodule);
830 return submodule->path;
831 }
832
833 const char *git_submodule_url(git_submodule *submodule)
834 {
835 assert(submodule);
836 return submodule->url;
837 }
838
839 int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
840 {
841 int error = 0;
842 git_buf normalized = GIT_BUF_INIT;
843
844 assert(out && repo && url);
845
846 git_buf_sanitize(out);
847
848 /* We do this in all platforms in case someone on Windows created the .gitmodules */
849 if (strchr(url, '\\')) {
850 if ((error = git_path_normalize_slashes(&normalized, url)) < 0)
851 return error;
852
853 url = normalized.ptr;
854 }
855
856
857 if (git_path_is_relative(url)) {
858 if (!(error = get_url_base(out, repo)))
859 error = git_path_apply_relative(out, url);
860 } else if (strchr(url, ':') != NULL || url[0] == '/') {
861 error = git_buf_sets(out, url);
862 } else {
863 giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL");
864 error = -1;
865 }
866
867 git_buf_free(&normalized);
868 return error;
869 }
870
871 static int write_var(git_repository *repo, const char *name, const char *var, const char *val)
872 {
873 git_buf key = GIT_BUF_INIT;
874 git_config_backend *mods;
875 int error;
876
877 mods = open_gitmodules(repo, GITMODULES_CREATE);
878 if (!mods)
879 return -1;
880
881 if ((error = git_buf_printf(&key, "submodule.%s.%s", name, var)) < 0)
882 goto cleanup;
883
884 if (val)
885 error = git_config_file_set_string(mods, key.ptr, val);
886 else
887 error = git_config_file_delete(mods, key.ptr);
888
889 git_buf_free(&key);
890
891 cleanup:
892 git_config_file_free(mods);
893 return error;
894 }
895
896 static int write_mapped_var(git_repository *repo, const char *name, git_cvar_map *maps, size_t nmaps, const char *var, int ival)
897 {
898 git_cvar_t type;
899 const char *val;
900
901 if (git_config_lookup_map_enum(&type, &val, maps, nmaps, ival) < 0) {
902 giterr_set(GITERR_SUBMODULE, "invalid value for %s", var);
903 return -1;
904 }
905
906 if (type == GIT_CVAR_TRUE)
907 val = "true";
908
909 return write_var(repo, name, var, val);
910 }
911
912 const char *git_submodule_branch(git_submodule *submodule)
913 {
914 assert(submodule);
915 return submodule->branch;
916 }
917
918 int git_submodule_set_branch(git_repository *repo, const char *name, const char *branch)
919 {
920
921 assert(repo && name);
922
923 return write_var(repo, name, "branch", branch);
924 }
925
926 int git_submodule_set_url(git_repository *repo, const char *name, const char *url)
927 {
928 assert(repo && name && url);
929
930 return write_var(repo, name, "url", url);
931 }
932
933 const git_oid *git_submodule_index_id(git_submodule *submodule)
934 {
935 assert(submodule);
936
937 if (submodule->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID)
938 return &submodule->index_oid;
939 else
940 return NULL;
941 }
942
943 const git_oid *git_submodule_head_id(git_submodule *submodule)
944 {
945 assert(submodule);
946
947 if (submodule->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID)
948 return &submodule->head_oid;
949 else
950 return NULL;
951 }
952
953 const git_oid *git_submodule_wd_id(git_submodule *submodule)
954 {
955 assert(submodule);
956
957 /* load unless we think we have a valid oid */
958 if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
959 git_repository *subrepo;
960
961 /* calling submodule open grabs the HEAD OID if possible */
962 if (!git_submodule_open_bare(&subrepo, submodule))
963 git_repository_free(subrepo);
964 else
965 giterr_clear();
966 }
967
968 if (submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)
969 return &submodule->wd_oid;
970 else
971 return NULL;
972 }
973
974 git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule)
975 {
976 assert(submodule);
977 return (submodule->ignore < GIT_SUBMODULE_IGNORE_NONE) ?
978 GIT_SUBMODULE_IGNORE_NONE : submodule->ignore;
979 }
980
981 int git_submodule_set_ignore(git_repository *repo, const char *name, git_submodule_ignore_t ignore)
982 {
983 assert(repo && name);
984
985 return write_mapped_var(repo, name, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), "ignore", ignore);
986 }
987
988 git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
989 {
990 assert(submodule);
991 return (submodule->update < GIT_SUBMODULE_UPDATE_CHECKOUT) ?
992 GIT_SUBMODULE_UPDATE_CHECKOUT : submodule->update;
993 }
994
995 int git_submodule_set_update(git_repository *repo, const char *name, git_submodule_update_t update)
996 {
997 assert(repo && name);
998
999 return write_mapped_var(repo, name, _sm_update_map, ARRAY_SIZE(_sm_update_map), "update", update);
1000 }
1001
1002 git_submodule_recurse_t git_submodule_fetch_recurse_submodules(
1003 git_submodule *submodule)
1004 {
1005 assert(submodule);
1006 return submodule->fetch_recurse;
1007 }
1008
1009 int git_submodule_set_fetch_recurse_submodules(git_repository *repo, const char *name, git_submodule_recurse_t recurse)
1010 {
1011 assert(repo && name);
1012
1013 return write_mapped_var(repo, name, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), "fetchRecurseSubmodules", recurse);
1014 }
1015
1016 static int submodule_repo_create(
1017 git_repository **out,
1018 git_repository *parent_repo,
1019 const char *path)
1020 {
1021 int error = 0;
1022 git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
1023 git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
1024 git_repository *subrepo = NULL;
1025
1026 initopt.flags =
1027 GIT_REPOSITORY_INIT_MKPATH |
1028 GIT_REPOSITORY_INIT_NO_REINIT |
1029 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
1030 GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
1031
1032 /* Workdir: path to sub-repo working directory */
1033 error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
1034 if (error < 0)
1035 goto cleanup;
1036
1037 initopt.workdir_path = workdir.ptr;
1038
1039 /**
1040 * Repodir: path to the sub-repo. sub-repo goes in:
1041 * <repo-dir>/modules/<name>/ with a gitlink in the
1042 * sub-repo workdir directory to that repository.
1043 */
1044 error = git_buf_join3(
1045 &repodir, '/', git_repository_path(parent_repo), "modules", path);
1046 if (error < 0)
1047 goto cleanup;
1048
1049 error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
1050
1051 cleanup:
1052 git_buf_free(&workdir);
1053 git_buf_free(&repodir);
1054
1055 *out = subrepo;
1056
1057 return error;
1058 }
1059
1060 /**
1061 * Callback to override sub-repository creation when
1062 * cloning a sub-repository.
1063 */
1064 static int git_submodule_update_repo_init_cb(
1065 git_repository **out,
1066 const char *path,
1067 int bare,
1068 void *payload)
1069 {
1070 git_submodule *sm;
1071
1072 GIT_UNUSED(bare);
1073
1074 sm = payload;
1075
1076 return submodule_repo_create(out, sm->repo, path);
1077 }
1078
1079 int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
1080 {
1081 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1082 opts, version, git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_INIT);
1083 return 0;
1084 }
1085
1086 int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
1087 {
1088 int error;
1089 unsigned int submodule_status;
1090 git_config *config = NULL;
1091 const char *submodule_url;
1092 git_repository *sub_repo = NULL;
1093 git_remote *remote = NULL;
1094 git_object *target_commit = NULL;
1095 git_buf buf = GIT_BUF_INIT;
1096 git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
1097 git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
1098
1099 assert(sm);
1100
1101 if (_update_options)
1102 memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));
1103
1104 GITERR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
1105
1106 /* Copy over the remote callbacks */
1107 memcpy(&clone_options.fetch_opts, &update_options.fetch_opts, sizeof(git_fetch_options));
1108
1109 /* Get the status of the submodule to determine if it is already initialized */
1110 if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0)
1111 goto done;
1112
1113 /*
1114 * If submodule work dir is not already initialized, check to see
1115 * what we need to do (initialize, clone, return error...)
1116 */
1117 if (submodule_status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) {
1118 /*
1119 * Work dir is not initialized, check to see if the submodule
1120 * info has been copied into .git/config
1121 */
1122 if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
1123 (error = git_buf_printf(&buf, "submodule.%s.url", git_submodule_name(sm))) < 0)
1124 goto done;
1125
1126 if ((error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0) {
1127 /*
1128 * If the error is not "not found" or if it is "not found" and we are not
1129 * initializing the submodule, then return error.
1130 */
1131 if (error != GIT_ENOTFOUND)
1132 goto done;
1133
1134 if (error == GIT_ENOTFOUND && !init) {
1135 giterr_set(GITERR_SUBMODULE, "Submodule is not initialized.");
1136 error = GIT_ERROR;
1137 goto done;
1138 }
1139
1140 /* The submodule has not been initialized yet - initialize it now.*/
1141 if ((error = git_submodule_init(sm, 0)) < 0)
1142 goto done;
1143
1144 git_config_free(config);
1145 config = NULL;
1146
1147 if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
1148 (error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0)
1149 goto done;
1150 }
1151
1152 /** submodule is initialized - now clone it **/
1153 /* override repo creation */
1154 clone_options.repository_cb = git_submodule_update_repo_init_cb;
1155 clone_options.repository_cb_payload = sm;
1156
1157 /*
1158 * Do not perform checkout as part of clone, instead we
1159 * will checkout the specific commit manually.
1160 */
1161 clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
1162 update_options.checkout_opts.checkout_strategy = update_options.clone_checkout_strategy;
1163
1164 if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
1165 (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 ||
1166 (error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
1167 goto done;
1168 } else {
1169 /**
1170 * Work dir is initialized - look up the commit in the parent repository's index,
1171 * update the workdir contents of the subrepository, and set the subrepository's
1172 * head to the new commit.
1173 */
1174 if ((error = git_submodule_open(&sub_repo, sm)) < 0 ||
1175 (error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJ_COMMIT)) < 0 ||
1176 (error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
1177 (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0)
1178 goto done;
1179
1180 /* Invalidate the wd flags as the workdir has been updated. */
1181 sm->flags = sm->flags &
1182 ~(GIT_SUBMODULE_STATUS_IN_WD |
1183 GIT_SUBMODULE_STATUS__WD_OID_VALID |
1184 GIT_SUBMODULE_STATUS__WD_SCANNED);
1185 }
1186
1187 done:
1188 git_buf_free(&buf);
1189 git_config_free(config);
1190 git_object_free(target_commit);
1191 git_remote_free(remote);
1192 git_repository_free(sub_repo);
1193
1194 return error;
1195 }
1196
1197 int git_submodule_init(git_submodule *sm, int overwrite)
1198 {
1199 int error;
1200 const char *val;
1201 git_buf key = GIT_BUF_INIT, effective_submodule_url = GIT_BUF_INIT;
1202 git_config *cfg = NULL;
1203
1204 if (!sm->url) {
1205 giterr_set(GITERR_SUBMODULE,
1206 "No URL configured for submodule '%s'", sm->name);
1207 return -1;
1208 }
1209
1210 if ((error = git_repository_config(&cfg, sm->repo)) < 0)
1211 return error;
1212
1213 /* write "submodule.NAME.url" */
1214
1215 if ((error = git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
1216 (error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
1217 (error = git_config__update_entry(
1218 cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
1219 goto cleanup;
1220
1221 /* write "submodule.NAME.update" if not default */
1222
1223 val = (sm->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
1224 NULL : git_submodule_update_to_str(sm->update);
1225
1226 if ((error = git_buf_printf(&key, "submodule.%s.update", sm->name)) < 0 ||
1227 (error = git_config__update_entry(
1228 cfg, key.ptr, val, overwrite != 0, false)) < 0)
1229 goto cleanup;
1230
1231 /* success */
1232
1233 cleanup:
1234 git_config_free(cfg);
1235 git_buf_free(&key);
1236 git_buf_free(&effective_submodule_url);
1237
1238 return error;
1239 }
1240
1241 int git_submodule_sync(git_submodule *sm)
1242 {
1243 int error = 0;
1244 git_config *cfg = NULL;
1245 git_buf key = GIT_BUF_INIT;
1246 git_repository *smrepo = NULL;
1247
1248 if (!sm->url) {
1249 giterr_set(GITERR_SUBMODULE,
1250 "No URL configured for submodule '%s'", sm->name);
1251 return -1;
1252 }
1253
1254 /* copy URL over to config only if it already exists */
1255
1256 if (!(error = git_repository_config__weakptr(&cfg, sm->repo)) &&
1257 !(error = git_buf_printf(&key, "submodule.%s.url", sm->name)))
1258 error = git_config__update_entry(cfg, key.ptr, sm->url, true, true);
1259
1260 /* if submodule exists in the working directory, update remote url */
1261
1262 if (!error &&
1263 (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
1264 !(error = git_submodule_open(&smrepo, sm)))
1265 {
1266 git_buf remote_name = GIT_BUF_INIT;
1267
1268 if ((error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
1269 /* return error from reading submodule config */;
1270 else if ((error = lookup_head_remote_key(&remote_name, smrepo)) < 0) {
1271 giterr_clear();
1272 error = git_buf_sets(&key, "remote.origin.url");
1273 } else {
1274 error = git_buf_join3(
1275 &key, '.', "remote", remote_name.ptr, "url");
1276 git_buf_free(&remote_name);
1277 }
1278
1279 if (!error)
1280 error = git_config__update_entry(cfg, key.ptr, sm->url, true, false);
1281
1282 git_repository_free(smrepo);
1283 }
1284
1285 git_buf_free(&key);
1286
1287 return error;
1288 }
1289
1290 static int git_submodule__open(
1291 git_repository **subrepo, git_submodule *sm, bool bare)
1292 {
1293 int error;
1294 git_buf path = GIT_BUF_INIT;
1295 unsigned int flags = GIT_REPOSITORY_OPEN_NO_SEARCH;
1296 const char *wd;
1297
1298 assert(sm && subrepo);
1299
1300 if (git_repository__ensure_not_bare(
1301 sm->repo, "open submodule repository") < 0)
1302 return GIT_EBAREREPO;
1303
1304 wd = git_repository_workdir(sm->repo);
1305
1306 if (git_buf_joinpath(&path, wd, sm->path) < 0 ||
1307 git_buf_joinpath(&path, path.ptr, DOT_GIT) < 0)
1308 return -1;
1309
1310 sm->flags = sm->flags &
1311 ~(GIT_SUBMODULE_STATUS_IN_WD |
1312 GIT_SUBMODULE_STATUS__WD_OID_VALID |
1313 GIT_SUBMODULE_STATUS__WD_SCANNED);
1314
1315 if (bare)
1316 flags |= GIT_REPOSITORY_OPEN_BARE;
1317
1318 error = git_repository_open_ext(subrepo, path.ptr, flags, wd);
1319
1320 /* if we opened the submodule successfully, grab HEAD OID, etc. */
1321 if (!error) {
1322 sm->flags |= GIT_SUBMODULE_STATUS_IN_WD |
1323 GIT_SUBMODULE_STATUS__WD_SCANNED;
1324
1325 if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_FILE))
1326 sm->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
1327 else
1328 giterr_clear();
1329 } else if (git_path_exists(path.ptr)) {
1330 sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED |
1331 GIT_SUBMODULE_STATUS_IN_WD;
1332 } else {
1333 git_buf_rtruncate_at_char(&path, '/'); /* remove "/.git" */
1334
1335 if (git_path_isdir(path.ptr))
1336 sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
1337 }
1338
1339 git_buf_free(&path);
1340
1341 return error;
1342 }
1343
1344 int git_submodule_open_bare(git_repository **subrepo, git_submodule *sm)
1345 {
1346 return git_submodule__open(subrepo, sm, true);
1347 }
1348
1349 int git_submodule_open(git_repository **subrepo, git_submodule *sm)
1350 {
1351 return git_submodule__open(subrepo, sm, false);
1352 }
1353
1354 static void submodule_update_from_index_entry(
1355 git_submodule *sm, const git_index_entry *ie)
1356 {
1357 bool already_found = (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) != 0;
1358
1359 if (!S_ISGITLINK(ie->mode)) {
1360 if (!already_found)
1361 sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
1362 } else {
1363 if (already_found)
1364 sm->flags |= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
1365 else
1366 git_oid_cpy(&sm->index_oid, &ie->id);
1367
1368 sm->flags |= GIT_SUBMODULE_STATUS_IN_INDEX |
1369 GIT_SUBMODULE_STATUS__INDEX_OID_VALID;
1370 }
1371 }
1372
1373 static int submodule_update_index(git_submodule *sm)
1374 {
1375 git_index *index;
1376 const git_index_entry *ie;
1377
1378 if (git_repository_index__weakptr(&index, sm->repo) < 0)
1379 return -1;
1380
1381 sm->flags = sm->flags &
1382 ~(GIT_SUBMODULE_STATUS_IN_INDEX |
1383 GIT_SUBMODULE_STATUS__INDEX_OID_VALID);
1384
1385 if (!(ie = git_index_get_bypath(index, sm->path, 0)))
1386 return 0;
1387
1388 submodule_update_from_index_entry(sm, ie);
1389
1390 return 0;
1391 }
1392
1393 static void submodule_update_from_head_data(
1394 git_submodule *sm, mode_t mode, const git_oid *id)
1395 {
1396 if (!S_ISGITLINK(mode))
1397 sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
1398 else {
1399 git_oid_cpy(&sm->head_oid, id);
1400
1401 sm->flags |= GIT_SUBMODULE_STATUS_IN_HEAD |
1402 GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
1403 }
1404 }
1405
1406 static int submodule_update_head(git_submodule *submodule)
1407 {
1408 git_tree *head = NULL;
1409 git_tree_entry *te = NULL;
1410
1411 submodule->flags = submodule->flags &
1412 ~(GIT_SUBMODULE_STATUS_IN_HEAD |
1413 GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
1414
1415 /* if we can't look up file in current head, then done */
1416 if (git_repository_head_tree(&head, submodule->repo) < 0 ||
1417 git_tree_entry_bypath(&te, head, submodule->path) < 0)
1418 giterr_clear();
1419 else
1420 submodule_update_from_head_data(submodule, te->attr, &te->oid);
1421
1422 git_tree_entry_free(te);
1423 git_tree_free(head);
1424 return 0;
1425 }
1426
1427 int git_submodule_reload(git_submodule *sm, int force)
1428 {
1429 int error = 0;
1430 git_config *mods;
1431
1432 GIT_UNUSED(force);
1433
1434 assert(sm);
1435
1436 if (!git_repository_is_bare(sm->repo)) {
1437 /* refresh config data */
1438 mods = gitmodules_snapshot(sm->repo);
1439 if (mods != NULL) {
1440 error = submodule_read_config(sm, mods);
1441 git_config_free(mods);
1442
1443 if (error < 0)
1444 return error;
1445 }
1446
1447 /* refresh wd data */
1448 sm->flags &=
1449 ~(GIT_SUBMODULE_STATUS_IN_WD |
1450 GIT_SUBMODULE_STATUS__WD_OID_VALID |
1451 GIT_SUBMODULE_STATUS__WD_FLAGS);
1452
1453 error = submodule_load_from_wd_lite(sm);
1454 }
1455
1456 if (error == 0 && (error = submodule_update_index(sm)) == 0)
1457 error = submodule_update_head(sm);
1458
1459 return error;
1460 }
1461
1462 static void submodule_copy_oid_maybe(
1463 git_oid *tgt, const git_oid *src, bool valid)
1464 {
1465 if (tgt) {
1466 if (valid)
1467 memcpy(tgt, src, sizeof(*tgt));
1468 else
1469 memset(tgt, 0, sizeof(*tgt));
1470 }
1471 }
1472
1473 int git_submodule__status(
1474 unsigned int *out_status,
1475 git_oid *out_head_id,
1476 git_oid *out_index_id,
1477 git_oid *out_wd_id,
1478 git_submodule *sm,
1479 git_submodule_ignore_t ign)
1480 {
1481 unsigned int status;
1482 git_repository *smrepo = NULL;
1483
1484 if (ign == GIT_SUBMODULE_IGNORE_UNSPECIFIED)
1485 ign = sm->ignore;
1486
1487 /* only return location info if ignore == all */
1488 if (ign == GIT_SUBMODULE_IGNORE_ALL) {
1489 *out_status = (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS);
1490 return 0;
1491 }
1492
1493 /* refresh the index OID */
1494 if (submodule_update_index(sm) < 0)
1495 return -1;
1496
1497 /* refresh the HEAD OID */
1498 if (submodule_update_head(sm) < 0)
1499 return -1;
1500
1501 /* for ignore == dirty, don't scan the working directory */
1502 if (ign == GIT_SUBMODULE_IGNORE_DIRTY) {
1503 /* git_submodule_open_bare will load WD OID data */
1504 if (git_submodule_open_bare(&smrepo, sm) < 0)
1505 giterr_clear();
1506 else
1507 git_repository_free(smrepo);
1508 smrepo = NULL;
1509 } else if (git_submodule_open(&smrepo, sm) < 0) {
1510 giterr_clear();
1511 smrepo = NULL;
1512 }
1513
1514 status = GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(sm->flags);
1515
1516 submodule_get_index_status(&status, sm);
1517 submodule_get_wd_status(&status, sm, smrepo, ign);
1518
1519 git_repository_free(smrepo);
1520
1521 *out_status = status;
1522
1523 submodule_copy_oid_maybe(out_head_id, &sm->head_oid,
1524 (sm->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID) != 0);
1525 submodule_copy_oid_maybe(out_index_id, &sm->index_oid,
1526 (sm->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID) != 0);
1527 submodule_copy_oid_maybe(out_wd_id, &sm->wd_oid,
1528 (sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) != 0);
1529
1530 return 0;
1531 }
1532
1533 int git_submodule_status(unsigned int *status, git_repository *repo, const char *name, git_submodule_ignore_t ignore)
1534 {
1535 git_submodule *sm;
1536 int error;
1537
1538 assert(status && repo && name);
1539
1540 if ((error = git_submodule_lookup(&sm, repo, name)) < 0)
1541 return error;
1542
1543 error = git_submodule__status(status, NULL, NULL, NULL, sm, ignore);
1544 git_submodule_free(sm);
1545
1546 return error;
1547 }
1548
1549 int git_submodule_location(unsigned int *location, git_submodule *sm)
1550 {
1551 assert(location && sm);
1552
1553 return git_submodule__status(
1554 location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
1555 }
1556
1557
1558 /*
1559 * INTERNAL FUNCTIONS
1560 */
1561
1562 static int submodule_alloc(
1563 git_submodule **out, git_repository *repo, const char *name)
1564 {
1565 size_t namelen;
1566 git_submodule *sm;
1567
1568 if (!name || !(namelen = strlen(name))) {
1569 giterr_set(GITERR_SUBMODULE, "Invalid submodule name");
1570 return -1;
1571 }
1572
1573 sm = git__calloc(1, sizeof(git_submodule));
1574 GITERR_CHECK_ALLOC(sm);
1575
1576 sm->name = sm->path = git__strdup(name);
1577 if (!sm->name) {
1578 git__free(sm);
1579 return -1;
1580 }
1581
1582 GIT_REFCOUNT_INC(sm);
1583 sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE;
1584 sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT;
1585 sm->fetch_recurse = sm->fetch_recurse_default = GIT_SUBMODULE_RECURSE_NO;
1586 sm->repo = repo;
1587 sm->branch = NULL;
1588
1589 *out = sm;
1590 return 0;
1591 }
1592
1593 static void submodule_release(git_submodule *sm)
1594 {
1595 if (!sm)
1596 return;
1597
1598 if (sm->repo) {
1599 sm->repo = NULL;
1600 }
1601
1602 if (sm->path != sm->name)
1603 git__free(sm->path);
1604 git__free(sm->name);
1605 git__free(sm->url);
1606 git__free(sm->branch);
1607 git__memzero(sm, sizeof(*sm));
1608 git__free(sm);
1609 }
1610
1611 void git_submodule_free(git_submodule *sm)
1612 {
1613 if (!sm)
1614 return;
1615 GIT_REFCOUNT_DEC(sm, submodule_release);
1616 }
1617
1618 static int submodule_config_error(const char *property, const char *value)
1619 {
1620 giterr_set(GITERR_INVALID,
1621 "Invalid value for submodule '%s' property: '%s'", property, value);
1622 return -1;
1623 }
1624
1625 int git_submodule_parse_ignore(git_submodule_ignore_t *out, const char *value)
1626 {
1627 int val;
1628
1629 if (git_config_lookup_map_value(
1630 &val, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value) < 0) {
1631 *out = GIT_SUBMODULE_IGNORE_NONE;
1632 return submodule_config_error("ignore", value);
1633 }
1634
1635 *out = (git_submodule_ignore_t)val;
1636 return 0;
1637 }
1638
1639 int git_submodule_parse_update(git_submodule_update_t *out, const char *value)
1640 {
1641 int val;
1642
1643 if (git_config_lookup_map_value(
1644 &val, _sm_update_map, ARRAY_SIZE(_sm_update_map), value) < 0) {
1645 *out = GIT_SUBMODULE_UPDATE_CHECKOUT;
1646 return submodule_config_error("update", value);
1647 }
1648
1649 *out = (git_submodule_update_t)val;
1650 return 0;
1651 }
1652
1653 int git_submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
1654 {
1655 int val;
1656
1657 if (git_config_lookup_map_value(
1658 &val, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), value) < 0) {
1659 *out = GIT_SUBMODULE_RECURSE_YES;
1660 return submodule_config_error("recurse", value);
1661 }
1662
1663 *out = (git_submodule_recurse_t)val;
1664 return 0;
1665 }
1666
1667 static int get_value(const char **out, git_config *cfg, git_buf *buf, const char *name, const char *field)
1668 {
1669 int error;
1670
1671 git_buf_clear(buf);
1672
1673 if ((error = git_buf_printf(buf, "submodule.%s.%s", name, field)) < 0 ||
1674 (error = git_config_get_string(out, cfg, buf->ptr)) < 0)
1675 return error;
1676
1677 return error;
1678 }
1679
1680 static int submodule_read_config(git_submodule *sm, git_config *cfg)
1681 {
1682 git_buf key = GIT_BUF_INIT;
1683 const char *value;
1684 int error, in_config = 0;
1685
1686 /*
1687 * TODO: Look up path in index and if it is present but not a GITLINK
1688 * then this should be deleted (at least to match git's behavior)
1689 */
1690
1691 if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) {
1692 in_config = 1;
1693 /*
1694 * TODO: if case insensitive filesystem, then the following strcmp
1695 * should be strcasecmp
1696 */
1697 if (strcmp(sm->name, value) != 0) {
1698 if (sm->path != sm->name)
1699 git__free(sm->path);
1700 sm->path = git__strdup(value);
1701 GITERR_CHECK_ALLOC(sm->path);
1702 }
1703 } else if (error != GIT_ENOTFOUND) {
1704 goto cleanup;
1705 }
1706
1707 if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
1708 in_config = 1;
1709 sm->url = git__strdup(value);
1710 GITERR_CHECK_ALLOC(sm->url);
1711 } else if (error != GIT_ENOTFOUND) {
1712 goto cleanup;
1713 }
1714
1715 if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) {
1716 in_config = 1;
1717 sm->branch = git__strdup(value);
1718 GITERR_CHECK_ALLOC(sm->branch);
1719 } else if (error != GIT_ENOTFOUND) {
1720 goto cleanup;
1721 }
1722
1723 if ((error = get_value(&value, cfg, &key, sm->name, "update")) == 0) {
1724 in_config = 1;
1725 if ((error = git_submodule_parse_update(&sm->update, value)) < 0)
1726 goto cleanup;
1727 sm->update_default = sm->update;
1728 } else if (error != GIT_ENOTFOUND) {
1729 goto cleanup;
1730 }
1731
1732 if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) {
1733 in_config = 1;
1734 if ((error = git_submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
1735 goto cleanup;
1736 sm->fetch_recurse_default = sm->fetch_recurse;
1737 } else if (error != GIT_ENOTFOUND) {
1738 goto cleanup;
1739 }
1740
1741 if ((error = get_value(&value, cfg, &key, sm->name, "ignore")) == 0) {
1742 in_config = 1;
1743 if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0)
1744 goto cleanup;
1745 sm->ignore_default = sm->ignore;
1746 } else if (error != GIT_ENOTFOUND) {
1747 goto cleanup;
1748 }
1749
1750 if (in_config)
1751 sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
1752
1753 error = 0;
1754
1755 cleanup:
1756 git_buf_free(&key);
1757 return error;
1758 }
1759
1760 static int submodule_load_each(const git_config_entry *entry, void *payload)
1761 {
1762 lfc_data *data = payload;
1763 const char *namestart, *property;
1764 git_strmap_iter pos;
1765 git_strmap *map = data->map;
1766 git_buf name = GIT_BUF_INIT;
1767 git_submodule *sm;
1768 int error;
1769
1770 if (git__prefixcmp(entry->name, "submodule.") != 0)
1771 return 0;
1772
1773 namestart = entry->name + strlen("submodule.");
1774 property = strrchr(namestart, '.');
1775
1776 if (!property || (property == namestart))
1777 return 0;
1778
1779 property++;
1780
1781 if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
1782 return error;
1783
1784 /*
1785 * Now that we have the submodule's name, we can use that to
1786 * figure out whether it's in the map. If it's not, we create
1787 * a new submodule, load the config and insert it. If it's
1788 * already inserted, we've already loaded it, so we skip.
1789 */
1790 pos = git_strmap_lookup_index(map, name.ptr);
1791 if (git_strmap_valid_index(map, pos)) {
1792 error = 0;
1793 goto done;
1794 }
1795
1796 if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0)
1797 goto done;
1798
1799 if ((error = submodule_read_config(sm, data->mods)) < 0) {
1800 git_submodule_free(sm);
1801 goto done;
1802 }
1803
1804 git_strmap_insert(map, sm->name, sm, error);
1805 assert(error != 0);
1806 if (error < 0)
1807 goto done;
1808
1809 error = 0;
1810
1811 done:
1812 git_buf_free(&name);
1813 return error;
1814 }
1815
1816 static int submodule_load_from_wd_lite(git_submodule *sm)
1817 {
1818 git_buf path = GIT_BUF_INIT;
1819
1820 if (git_buf_joinpath(&path, git_repository_workdir(sm->repo), sm->path) < 0)
1821 return -1;
1822
1823 if (git_path_isdir(path.ptr))
1824 sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
1825
1826 if (git_path_contains(&path, DOT_GIT))
1827 sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;
1828
1829 git_buf_free(&path);
1830 return 0;
1831 }
1832
1833 /**
1834 * Returns a snapshot of $WORK_TREE/.gitmodules.
1835 *
1836 * We ignore any errors and just pretend the file isn't there.
1837 */
1838 static git_config *gitmodules_snapshot(git_repository *repo)
1839 {
1840 const char *workdir = git_repository_workdir(repo);
1841 git_config *mods = NULL, *snap = NULL;
1842 git_buf path = GIT_BUF_INIT;
1843
1844 if (workdir != NULL) {
1845 if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0)
1846 return NULL;
1847
1848 if (git_config_open_ondisk(&mods, path.ptr) < 0)
1849 mods = NULL;
1850 }
1851
1852 git_buf_free(&path);
1853
1854 if (mods) {
1855 git_config_snapshot(&snap, mods);
1856 git_config_free(mods);
1857 }
1858
1859 return snap;
1860 }
1861
1862 static git_config_backend *open_gitmodules(
1863 git_repository *repo,
1864 int okay_to_create)
1865 {
1866 const char *workdir = git_repository_workdir(repo);
1867 git_buf path = GIT_BUF_INIT;
1868 git_config_backend *mods = NULL;
1869
1870 if (workdir != NULL) {
1871 if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0)
1872 return NULL;
1873
1874 if (okay_to_create || git_path_isfile(path.ptr)) {
1875 /* git_config_file__ondisk should only fail if OOM */
1876 if (git_config_file__ondisk(&mods, path.ptr) < 0)
1877 mods = NULL;
1878 /* open should only fail here if the file is malformed */
1879 else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL) < 0) {
1880 git_config_file_free(mods);
1881 mods = NULL;
1882 }
1883 }
1884 }
1885
1886 git_buf_free(&path);
1887
1888 return mods;
1889 }
1890
1891 /* Lookup name of remote of the local tracking branch HEAD points to */
1892 static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
1893 {
1894 int error;
1895 git_reference *head = NULL;
1896 git_buf upstream_name = GIT_BUF_INIT;
1897
1898 /* lookup and dereference HEAD */
1899 if ((error = git_repository_head(&head, repo)) < 0)
1900 return error;
1901
1902 /**
1903 * If head does not refer to a branch, then return
1904 * GIT_ENOTFOUND to indicate that we could not find
1905 * a remote key for the local tracking branch HEAD points to.
1906 **/
1907 if (!git_reference_is_branch(head)) {
1908 giterr_set(GITERR_INVALID,
1909 "HEAD does not refer to a branch.");
1910 error = GIT_ENOTFOUND;
1911 goto done;
1912 }
1913
1914 /* lookup remote tracking branch of HEAD */
1915 if ((error = git_branch_upstream_name(
1916 &upstream_name,
1917 repo,
1918 git_reference_name(head))) < 0)
1919 goto done;
1920
1921 /* lookup remote of remote tracking branch */
1922 if ((error = git_branch_remote_name(remote_name, repo, upstream_name.ptr)) < 0)
1923 goto done;
1924
1925 done:
1926 git_buf_free(&upstream_name);
1927 git_reference_free(head);
1928
1929 return error;
1930 }
1931
1932 /* Lookup the remote of the local tracking branch HEAD points to */
1933 static int lookup_head_remote(git_remote **remote, git_repository *repo)
1934 {
1935 int error;
1936 git_buf remote_name = GIT_BUF_INIT;
1937
1938 /* lookup remote of remote tracking branch name */
1939 if (!(error = lookup_head_remote_key(&remote_name, repo)))
1940 error = git_remote_lookup(remote, repo, remote_name.ptr);
1941
1942 git_buf_free(&remote_name);
1943
1944 return error;
1945 }
1946
1947 /* Lookup remote, either from HEAD or fall back on origin */
1948 static int lookup_default_remote(git_remote **remote, git_repository *repo)
1949 {
1950 int error = lookup_head_remote(remote, repo);
1951
1952 /* if that failed, use 'origin' instead */
1953 if (error == GIT_ENOTFOUND)
1954 error = git_remote_lookup(remote, repo, "origin");
1955
1956 if (error == GIT_ENOTFOUND)
1957 giterr_set(
1958 GITERR_SUBMODULE,
1959 "Cannot get default remote for submodule - no local tracking "
1960 "branch for HEAD and origin does not exist");
1961
1962 return error;
1963 }
1964
1965 static int get_url_base(git_buf *url, git_repository *repo)
1966 {
1967 int error;
1968 git_remote *remote = NULL;
1969
1970 if (!(error = lookup_default_remote(&remote, repo))) {
1971 error = git_buf_sets(url, git_remote_url(remote));
1972 git_remote_free(remote);
1973 }
1974 else if (error == GIT_ENOTFOUND) {
1975 /* if repository does not have a default remote, use workdir instead */
1976 giterr_clear();
1977 error = git_buf_sets(url, git_repository_workdir(repo));
1978 }
1979
1980 return error;
1981 }
1982
1983 static void submodule_get_index_status(unsigned int *status, git_submodule *sm)
1984 {
1985 const git_oid *head_oid = git_submodule_head_id(sm);
1986 const git_oid *index_oid = git_submodule_index_id(sm);
1987
1988 *status = *status & ~GIT_SUBMODULE_STATUS__INDEX_FLAGS;
1989
1990 if (!head_oid) {
1991 if (index_oid)
1992 *status |= GIT_SUBMODULE_STATUS_INDEX_ADDED;
1993 }
1994 else if (!index_oid)
1995 *status |= GIT_SUBMODULE_STATUS_INDEX_DELETED;
1996 else if (!git_oid_equal(head_oid, index_oid))
1997 *status |= GIT_SUBMODULE_STATUS_INDEX_MODIFIED;
1998 }
1999
2000
2001 static void submodule_get_wd_status(
2002 unsigned int *status,
2003 git_submodule *sm,
2004 git_repository *sm_repo,
2005 git_submodule_ignore_t ign)
2006 {
2007 const git_oid *index_oid = git_submodule_index_id(sm);
2008 const git_oid *wd_oid =
2009 (sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) ? &sm->wd_oid : NULL;
2010 git_tree *sm_head = NULL;
2011 git_index *index = NULL;
2012 git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
2013 git_diff *diff;
2014
2015 *status = *status & ~GIT_SUBMODULE_STATUS__WD_FLAGS;
2016
2017 if (!index_oid) {
2018 if (wd_oid)
2019 *status |= GIT_SUBMODULE_STATUS_WD_ADDED;
2020 }
2021 else if (!wd_oid) {
2022 if ((sm->flags & GIT_SUBMODULE_STATUS__WD_SCANNED) != 0 &&
2023 (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0)
2024 *status |= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED;
2025 else
2026 *status |= GIT_SUBMODULE_STATUS_WD_DELETED;
2027 }
2028 else if (!git_oid_equal(index_oid, wd_oid))
2029 *status |= GIT_SUBMODULE_STATUS_WD_MODIFIED;
2030
2031 /* if we have no repo, then we're done */
2032 if (!sm_repo)
2033 return;
2034
2035 /* the diffs below could be optimized with an early termination
2036 * option to the git_diff functions, but for now this is sufficient
2037 * (and certainly no worse that what core git does).
2038 */
2039
2040 if (ign == GIT_SUBMODULE_IGNORE_NONE)
2041 opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
2042
2043 (void)git_repository_index__weakptr(&index, sm_repo);
2044
2045 /* if we don't have an unborn head, check diff with index */
2046 if (git_repository_head_tree(&sm_head, sm_repo) < 0)
2047 giterr_clear();
2048 else {
2049 /* perform head to index diff on submodule */
2050 if (git_diff_tree_to_index(&diff, sm_repo, sm_head, index, &opt) < 0)
2051 giterr_clear();
2052 else {
2053 if (git_diff_num_deltas(diff) > 0)
2054 *status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED;
2055 git_diff_free(diff);
2056 diff = NULL;
2057 }
2058
2059 git_tree_free(sm_head);
2060 }
2061
2062 /* perform index-to-workdir diff on submodule */
2063 if (git_diff_index_to_workdir(&diff, sm_repo, index, &opt) < 0)
2064 giterr_clear();
2065 else {
2066 size_t untracked =
2067 git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED);
2068
2069 if (untracked > 0)
2070 *status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED;
2071
2072 if (git_diff_num_deltas(diff) != untracked)
2073 *status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED;
2074
2075 git_diff_free(diff);
2076 diff = NULL;
2077 }
2078 }