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