File Coverage

deps/libgit2/src/submodule.c
Criterion Covered Total %
statement 0 1097 0.0
branch 0 742 0.0
condition n/a
subroutine n/a
pod n/a
total 0 1839 0.0


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