File Coverage

deps/libgit2/src/libgit2/submodule.c
Criterion Covered Total %
statement 5 1145 0.4
branch 1 766 0.1
condition n/a
subroutine n/a
pod n/a
total 6 1911 0.3


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