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           static const char *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             #ifndef GIT_DEPRECATE_HARD
1244 0           int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
1245             {
1246 0           return git_submodule_update_options_init(opts, version);
1247             }
1248             #endif
1249              
1250 0           int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
1251             {
1252             int error;
1253             unsigned int submodule_status;
1254 0           git_config *config = NULL;
1255             const char *submodule_url;
1256 0           git_repository *sub_repo = NULL;
1257 0           git_remote *remote = NULL;
1258 0           git_object *target_commit = NULL;
1259 0           git_buf buf = GIT_BUF_INIT;
1260 0           git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
1261 0           git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
1262              
1263 0 0         assert(sm);
1264              
1265 0 0         if (_update_options)
1266 0           memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));
1267              
1268 0 0         GIT_ERROR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
1269              
1270             /* Copy over the remote callbacks */
1271 0           memcpy(&clone_options.fetch_opts, &update_options.fetch_opts, sizeof(git_fetch_options));
1272              
1273             /* Get the status of the submodule to determine if it is already initialized */
1274 0 0         if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0)
1275 0           goto done;
1276              
1277             /*
1278             * If submodule work dir is not already initialized, check to see
1279             * what we need to do (initialize, clone, return error...)
1280             */
1281 0 0         if (submodule_status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) {
1282             /*
1283             * Work dir is not initialized, check to see if the submodule
1284             * info has been copied into .git/config
1285             */
1286 0 0         if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
    0          
1287 0           (error = git_buf_printf(&buf, "submodule.%s.url", git_submodule_name(sm))) < 0)
1288             goto done;
1289              
1290 0 0         if ((error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0) {
1291             /*
1292             * If the error is not "not found" or if it is "not found" and we are not
1293             * initializing the submodule, then return error.
1294             */
1295 0 0         if (error != GIT_ENOTFOUND)
1296 0           goto done;
1297              
1298 0 0         if (!init) {
1299 0           git_error_set(GIT_ERROR_SUBMODULE, "submodule is not initialized");
1300 0           error = GIT_ERROR;
1301 0           goto done;
1302             }
1303              
1304             /* The submodule has not been initialized yet - initialize it now.*/
1305 0 0         if ((error = git_submodule_init(sm, 0)) < 0)
1306 0           goto done;
1307              
1308 0           git_config_free(config);
1309 0           config = NULL;
1310              
1311 0 0         if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
    0          
1312 0           (error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0)
1313             goto done;
1314             }
1315              
1316             /** submodule is initialized - now clone it **/
1317             /* override repo creation */
1318 0           clone_options.repository_cb = git_submodule_update_repo_init_cb;
1319 0           clone_options.repository_cb_payload = sm;
1320              
1321             /*
1322             * Do not perform checkout as part of clone, instead we
1323             * will checkout the specific commit manually.
1324             */
1325 0           clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
1326              
1327 0 0         if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
    0          
1328 0           (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 ||
1329 0           (error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
1330             goto done;
1331             } else {
1332             const git_oid *oid;
1333              
1334             /**
1335             * Work dir is initialized - look up the commit in the parent repository's index,
1336             * update the workdir contents of the subrepository, and set the subrepository's
1337             * head to the new commit.
1338             */
1339 0 0         if ((error = git_submodule_open(&sub_repo, sm)) < 0)
1340 0           goto done;
1341              
1342 0 0         if ((oid = git_submodule_index_id(sm)) == NULL) {
1343 0           git_error_set(GIT_ERROR_SUBMODULE, "could not get ID of submodule in index");
1344 0           error = -1;
1345 0           goto done;
1346             }
1347              
1348             /* Look up the target commit in the submodule. */
1349 0 0         if ((error = git_object_lookup(&target_commit, sub_repo, oid, GIT_OBJECT_COMMIT)) < 0) {
1350             /* If it isn't found then fetch and try again. */
1351 0 0         if (error != GIT_ENOTFOUND || !update_options.allow_fetch ||
    0          
    0          
1352 0 0         (error = lookup_default_remote(&remote, sub_repo)) < 0 ||
1353 0 0         (error = git_remote_fetch(remote, NULL, &update_options.fetch_opts, NULL)) < 0 ||
1354 0           (error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJECT_COMMIT)) < 0)
1355             goto done;
1356             }
1357              
1358 0 0         if ((error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
    0          
1359 0           (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0)
1360             goto done;
1361              
1362             /* Invalidate the wd flags as the workdir has been updated. */
1363 0           sm->flags = sm->flags &
1364             ~(GIT_SUBMODULE_STATUS_IN_WD |
1365             GIT_SUBMODULE_STATUS__WD_OID_VALID |
1366             GIT_SUBMODULE_STATUS__WD_SCANNED);
1367             }
1368              
1369             done:
1370 0           git_buf_dispose(&buf);
1371 0           git_config_free(config);
1372 0           git_object_free(target_commit);
1373 0           git_remote_free(remote);
1374 0           git_repository_free(sub_repo);
1375              
1376 0           return error;
1377             }
1378              
1379 0           int git_submodule_init(git_submodule *sm, int overwrite)
1380             {
1381             int error;
1382             const char *val;
1383 0           git_buf key = GIT_BUF_INIT, effective_submodule_url = GIT_BUF_INIT;
1384 0           git_config *cfg = NULL;
1385              
1386 0 0         if (!sm->url) {
1387 0           git_error_set(GIT_ERROR_SUBMODULE,
1388             "no URL configured for submodule '%s'", sm->name);
1389 0           return -1;
1390             }
1391              
1392 0 0         if ((error = git_repository_config(&cfg, sm->repo)) < 0)
1393 0           return error;
1394              
1395             /* write "submodule.NAME.url" */
1396              
1397 0 0         if ((error = git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
    0          
1398 0 0         (error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
1399 0           (error = git_config__update_entry(
1400 0           cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
1401             goto cleanup;
1402              
1403             /* write "submodule.NAME.update" if not default */
1404              
1405 0           val = (sm->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
1406 0 0         NULL : submodule_update_to_str(sm->update);
1407              
1408 0 0         if ((error = git_buf_printf(&key, "submodule.%s.update", sm->name)) < 0 ||
1409 0           (error = git_config__update_entry(
1410 0           cfg, key.ptr, val, overwrite != 0, false)) < 0)
1411             goto cleanup;
1412              
1413             /* success */
1414              
1415             cleanup:
1416 0           git_config_free(cfg);
1417 0           git_buf_dispose(&key);
1418 0           git_buf_dispose(&effective_submodule_url);
1419              
1420 0           return error;
1421             }
1422              
1423 0           int git_submodule_sync(git_submodule *sm)
1424             {
1425 0           git_buf key = GIT_BUF_INIT, url = GIT_BUF_INIT, remote_name = GIT_BUF_INIT;
1426 0           git_repository *smrepo = NULL;
1427 0           git_config *cfg = NULL;
1428 0           int error = 0;
1429              
1430 0 0         if (!sm->url) {
1431 0           git_error_set(GIT_ERROR_SUBMODULE, "no URL configured for submodule '%s'", sm->name);
1432 0           return -1;
1433             }
1434              
1435             /* copy URL over to config only if it already exists */
1436 0 0         if ((error = git_repository_config__weakptr(&cfg, sm->repo)) < 0 ||
    0          
1437 0 0         (error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
1438 0 0         (error = git_submodule_resolve_url(&url, sm->repo, sm->url)) < 0 ||
1439 0           (error = git_config__update_entry(cfg, key.ptr, url.ptr, true, true)) < 0)
1440             goto out;
1441              
1442 0 0         if (!(sm->flags & GIT_SUBMODULE_STATUS_IN_WD))
1443 0           goto out;
1444              
1445             /* if submodule exists in the working directory, update remote url */
1446 0 0         if ((error = git_submodule_open(&smrepo, sm)) < 0 ||
    0          
1447 0           (error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
1448             goto out;
1449              
1450 0 0         if (lookup_head_remote_key(&remote_name, smrepo) == 0) {
1451 0 0         if ((error = git_buf_join3(&key, '.', "remote", remote_name.ptr, "url")) < 0)
1452 0           goto out;
1453 0 0         } else if ((error = git_buf_sets(&key, "remote.origin.url")) < 0) {
1454 0           goto out;
1455             }
1456              
1457 0 0         if ((error = git_config__update_entry(cfg, key.ptr, url.ptr, true, false)) < 0)
1458 0           goto out;
1459              
1460             out:
1461 0           git_repository_free(smrepo);
1462 0           git_buf_dispose(&remote_name);
1463 0           git_buf_dispose(&key);
1464 0           git_buf_dispose(&url);
1465 0           return error;
1466             }
1467              
1468 0           static int git_submodule__open(
1469             git_repository **subrepo, git_submodule *sm, bool bare)
1470             {
1471             int error;
1472 0           git_buf path = GIT_BUF_INIT;
1473 0           unsigned int flags = GIT_REPOSITORY_OPEN_NO_SEARCH;
1474             const char *wd;
1475              
1476 0 0         assert(sm && subrepo);
    0          
1477              
1478 0 0         if (git_repository__ensure_not_bare(
1479             sm->repo, "open submodule repository") < 0)
1480 0           return GIT_EBAREREPO;
1481              
1482 0           wd = git_repository_workdir(sm->repo);
1483              
1484 0           if (git_buf_joinpath(&path, wd, sm->path) < 0 ||
1485 0           git_buf_joinpath(&path, path.ptr, DOT_GIT) < 0)
1486 0           return -1;
1487              
1488 0           sm->flags = sm->flags &
1489             ~(GIT_SUBMODULE_STATUS_IN_WD |
1490             GIT_SUBMODULE_STATUS__WD_OID_VALID |
1491             GIT_SUBMODULE_STATUS__WD_SCANNED);
1492              
1493 0 0         if (bare)
1494 0           flags |= GIT_REPOSITORY_OPEN_BARE;
1495              
1496 0           error = git_repository_open_ext(subrepo, path.ptr, flags, wd);
1497              
1498             /* if we opened the submodule successfully, grab HEAD OID, etc. */
1499 0 0         if (!error) {
1500 0           sm->flags |= GIT_SUBMODULE_STATUS_IN_WD |
1501             GIT_SUBMODULE_STATUS__WD_SCANNED;
1502              
1503 0 0         if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_FILE))
1504 0           sm->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
1505             else
1506 0           git_error_clear();
1507 0 0         } else if (git_path_exists(path.ptr)) {
1508 0           sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED |
1509             GIT_SUBMODULE_STATUS_IN_WD;
1510             } else {
1511 0           git_buf_rtruncate_at_char(&path, '/'); /* remove "/.git" */
1512              
1513 0 0         if (git_path_isdir(path.ptr))
1514 0           sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
1515             }
1516              
1517 0           git_buf_dispose(&path);
1518              
1519 0           return error;
1520             }
1521              
1522 0           int git_submodule_open_bare(git_repository **subrepo, git_submodule *sm)
1523             {
1524 0           return git_submodule__open(subrepo, sm, true);
1525             }
1526              
1527 0           int git_submodule_open(git_repository **subrepo, git_submodule *sm)
1528             {
1529 0           return git_submodule__open(subrepo, sm, false);
1530             }
1531              
1532 0           static void submodule_update_from_index_entry(
1533             git_submodule *sm, const git_index_entry *ie)
1534             {
1535 0           bool already_found = (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) != 0;
1536              
1537 0 0         if (!S_ISGITLINK(ie->mode)) {
1538 0 0         if (!already_found)
1539 0           sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
1540             } else {
1541 0 0         if (already_found)
1542 0           sm->flags |= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
1543             else
1544 0           git_oid_cpy(&sm->index_oid, &ie->id);
1545              
1546 0           sm->flags |= GIT_SUBMODULE_STATUS_IN_INDEX |
1547             GIT_SUBMODULE_STATUS__INDEX_OID_VALID;
1548             }
1549 0           }
1550              
1551 0           static int submodule_update_index(git_submodule *sm)
1552             {
1553             git_index *index;
1554             const git_index_entry *ie;
1555              
1556 0 0         if (git_repository_index__weakptr(&index, sm->repo) < 0)
1557 0           return -1;
1558              
1559 0           sm->flags = sm->flags &
1560             ~(GIT_SUBMODULE_STATUS_IN_INDEX |
1561             GIT_SUBMODULE_STATUS__INDEX_OID_VALID);
1562              
1563 0 0         if (!(ie = git_index_get_bypath(index, sm->path, 0)))
1564 0           return 0;
1565              
1566 0           submodule_update_from_index_entry(sm, ie);
1567              
1568 0           return 0;
1569             }
1570              
1571 0           static void submodule_update_from_head_data(
1572             git_submodule *sm, mode_t mode, const git_oid *id)
1573             {
1574 0 0         if (!S_ISGITLINK(mode))
1575 0           sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
1576             else {
1577 0           git_oid_cpy(&sm->head_oid, id);
1578              
1579 0           sm->flags |= GIT_SUBMODULE_STATUS_IN_HEAD |
1580             GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
1581             }
1582 0           }
1583              
1584 0           static int submodule_update_head(git_submodule *submodule)
1585             {
1586 0           git_tree *head = NULL;
1587 0           git_tree_entry *te = NULL;
1588              
1589 0           submodule->flags = submodule->flags &
1590             ~(GIT_SUBMODULE_STATUS_IN_HEAD |
1591             GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
1592              
1593             /* if we can't look up file in current head, then done */
1594 0           if (git_repository_head_tree(&head, submodule->repo) < 0 ||
1595 0           git_tree_entry_bypath(&te, head, submodule->path) < 0)
1596 0           git_error_clear();
1597             else
1598 0           submodule_update_from_head_data(submodule, te->attr, git_tree_entry_id(te));
1599              
1600 0           git_tree_entry_free(te);
1601 0           git_tree_free(head);
1602 0           return 0;
1603             }
1604              
1605 0           int git_submodule_reload(git_submodule *sm, int force)
1606             {
1607 0           git_config *mods = NULL;
1608             int error;
1609              
1610             GIT_UNUSED(force);
1611              
1612 0 0         assert(sm);
1613              
1614 0 0         if ((error = git_submodule_name_is_valid(sm->repo, sm->name, 0)) <= 0)
1615             /* This should come with a warning, but we've no API for that */
1616 0           goto out;
1617              
1618 0 0         if (git_repository_is_bare(sm->repo))
1619 0           goto out;
1620              
1621             /* refresh config data */
1622 0 0         if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
    0          
1623 0           goto out;
1624              
1625 0 0         if (mods != NULL && (error = submodule_read_config(sm, mods)) < 0)
    0          
1626 0           goto out;
1627              
1628             /* refresh wd data */
1629 0           sm->flags &=
1630             ~(GIT_SUBMODULE_STATUS_IN_WD |
1631             GIT_SUBMODULE_STATUS__WD_OID_VALID |
1632             GIT_SUBMODULE_STATUS__WD_FLAGS);
1633              
1634 0 0         if ((error = submodule_load_from_wd_lite(sm)) < 0 ||
    0          
1635 0           (error = submodule_update_index(sm)) < 0 ||
1636             (error = submodule_update_head(sm)) < 0)
1637             goto out;
1638              
1639             out:
1640 0           git_config_free(mods);
1641 0           return error;
1642             }
1643              
1644 0           static void submodule_copy_oid_maybe(
1645             git_oid *tgt, const git_oid *src, bool valid)
1646             {
1647 0 0         if (tgt) {
1648 0 0         if (valid)
1649 0           memcpy(tgt, src, sizeof(*tgt));
1650             else
1651 0           memset(tgt, 0, sizeof(*tgt));
1652             }
1653 0           }
1654              
1655 0           int git_submodule__status(
1656             unsigned int *out_status,
1657             git_oid *out_head_id,
1658             git_oid *out_index_id,
1659             git_oid *out_wd_id,
1660             git_submodule *sm,
1661             git_submodule_ignore_t ign)
1662             {
1663             unsigned int status;
1664 0           git_repository *smrepo = NULL;
1665              
1666 0 0         if (ign == GIT_SUBMODULE_IGNORE_UNSPECIFIED)
1667 0           ign = sm->ignore;
1668              
1669             /* only return location info if ignore == all */
1670 0 0         if (ign == GIT_SUBMODULE_IGNORE_ALL) {
1671 0           *out_status = (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS);
1672 0           return 0;
1673             }
1674              
1675             /* If the user has requested caching submodule state, performing these
1676             * expensive operations (especially `submodule_update_head`, which is
1677             * bottlenecked on `git_repository_head_tree`) eliminates much of the
1678             * advantage. We will, therefore, interpret the request for caching to
1679             * apply here to and skip them.
1680             */
1681              
1682 0 0         if (sm->repo->submodule_cache == NULL) {
1683             /* refresh the index OID */
1684 0 0         if (submodule_update_index(sm) < 0)
1685 0           return -1;
1686              
1687             /* refresh the HEAD OID */
1688 0 0         if (submodule_update_head(sm) < 0)
1689 0           return -1;
1690             }
1691              
1692             /* for ignore == dirty, don't scan the working directory */
1693 0 0         if (ign == GIT_SUBMODULE_IGNORE_DIRTY) {
1694             /* git_submodule_open_bare will load WD OID data */
1695 0 0         if (git_submodule_open_bare(&smrepo, sm) < 0)
1696 0           git_error_clear();
1697             else
1698 0           git_repository_free(smrepo);
1699 0           smrepo = NULL;
1700 0 0         } else if (git_submodule_open(&smrepo, sm) < 0) {
1701 0           git_error_clear();
1702 0           smrepo = NULL;
1703             }
1704              
1705 0           status = GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(sm->flags);
1706              
1707 0           submodule_get_index_status(&status, sm);
1708 0           submodule_get_wd_status(&status, sm, smrepo, ign);
1709              
1710 0           git_repository_free(smrepo);
1711              
1712 0           *out_status = status;
1713              
1714 0           submodule_copy_oid_maybe(out_head_id, &sm->head_oid,
1715 0           (sm->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID) != 0);
1716 0           submodule_copy_oid_maybe(out_index_id, &sm->index_oid,
1717 0           (sm->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID) != 0);
1718 0           submodule_copy_oid_maybe(out_wd_id, &sm->wd_oid,
1719 0           (sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) != 0);
1720              
1721 0           return 0;
1722             }
1723              
1724 0           int git_submodule_status(unsigned int *status, git_repository *repo, const char *name, git_submodule_ignore_t ignore)
1725             {
1726             git_submodule *sm;
1727             int error;
1728              
1729 0 0         assert(status && repo && name);
    0          
    0          
1730              
1731 0 0         if ((error = git_submodule_lookup(&sm, repo, name)) < 0)
1732 0           return error;
1733              
1734 0           error = git_submodule__status(status, NULL, NULL, NULL, sm, ignore);
1735 0           git_submodule_free(sm);
1736              
1737 0           return error;
1738             }
1739              
1740 0           int git_submodule_location(unsigned int *location, git_submodule *sm)
1741             {
1742 0 0         assert(location && sm);
    0          
1743              
1744 0           return git_submodule__status(
1745             location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
1746             }
1747              
1748             /*
1749             * INTERNAL FUNCTIONS
1750             */
1751              
1752 0           static int submodule_alloc(
1753             git_submodule **out, git_repository *repo, const char *name)
1754             {
1755             size_t namelen;
1756             git_submodule *sm;
1757              
1758 0 0         if (!name || !(namelen = strlen(name))) {
    0          
1759 0           git_error_set(GIT_ERROR_SUBMODULE, "invalid submodule name");
1760 0           return -1;
1761             }
1762              
1763 0           sm = git__calloc(1, sizeof(git_submodule));
1764 0 0         GIT_ERROR_CHECK_ALLOC(sm);
1765              
1766 0           sm->name = sm->path = git__strdup(name);
1767 0 0         if (!sm->name) {
1768 0           git__free(sm);
1769 0           return -1;
1770             }
1771              
1772 0           GIT_REFCOUNT_INC(sm);
1773 0           sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE;
1774 0           sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT;
1775 0           sm->fetch_recurse = sm->fetch_recurse_default = GIT_SUBMODULE_RECURSE_NO;
1776 0           sm->repo = repo;
1777 0           sm->branch = NULL;
1778              
1779 0           *out = sm;
1780 0           return 0;
1781             }
1782              
1783 0           static void submodule_release(git_submodule *sm)
1784             {
1785 0 0         if (!sm)
1786 0           return;
1787              
1788 0 0         if (sm->repo) {
1789 0           sm->repo = NULL;
1790             }
1791              
1792 0 0         if (sm->path != sm->name)
1793 0           git__free(sm->path);
1794 0           git__free(sm->name);
1795 0           git__free(sm->url);
1796 0           git__free(sm->branch);
1797 0           git__memzero(sm, sizeof(*sm));
1798 0           git__free(sm);
1799             }
1800              
1801 0           void git_submodule_free(git_submodule *sm)
1802             {
1803 0 0         if (!sm)
1804 0           return;
1805 0 0         GIT_REFCOUNT_DEC(sm, submodule_release);
    0          
1806             }
1807              
1808 0           static int submodule_config_error(const char *property, const char *value)
1809             {
1810 0           git_error_set(GIT_ERROR_INVALID,
1811             "invalid value for submodule '%s' property: '%s'", property, value);
1812 0           return -1;
1813             }
1814              
1815 0           int git_submodule_parse_ignore(git_submodule_ignore_t *out, const char *value)
1816             {
1817             int val;
1818              
1819 0 0         if (git_config_lookup_map_value(
1820             &val, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value) < 0) {
1821 0           *out = GIT_SUBMODULE_IGNORE_NONE;
1822 0           return submodule_config_error("ignore", value);
1823             }
1824              
1825 0           *out = (git_submodule_ignore_t)val;
1826 0           return 0;
1827             }
1828              
1829 0           int git_submodule_parse_update(git_submodule_update_t *out, const char *value)
1830             {
1831             int val;
1832              
1833 0 0         if (git_config_lookup_map_value(
1834             &val, _sm_update_map, ARRAY_SIZE(_sm_update_map), value) < 0) {
1835 0           *out = GIT_SUBMODULE_UPDATE_CHECKOUT;
1836 0           return submodule_config_error("update", value);
1837             }
1838              
1839 0           *out = (git_submodule_update_t)val;
1840 0           return 0;
1841             }
1842              
1843 0           static int submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
1844             {
1845             int val;
1846              
1847 0 0         if (git_config_lookup_map_value(
1848             &val, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), value) < 0) {
1849 0           *out = GIT_SUBMODULE_RECURSE_YES;
1850 0           return submodule_config_error("recurse", value);
1851             }
1852              
1853 0           *out = (git_submodule_recurse_t)val;
1854 0           return 0;
1855             }
1856              
1857 0           static int get_value(const char **out, git_config *cfg, git_buf *buf, const char *name, const char *field)
1858             {
1859             int error;
1860              
1861 0           git_buf_clear(buf);
1862              
1863 0 0         if ((error = git_buf_printf(buf, "submodule.%s.%s", name, field)) < 0 ||
    0          
1864 0           (error = git_config_get_string(out, cfg, buf->ptr)) < 0)
1865 0           return error;
1866              
1867 0           return error;
1868             }
1869              
1870 0           static bool looks_like_command_line_option(const char *s)
1871             {
1872 0 0         if (s && s[0] == '-')
    0          
1873 0           return true;
1874              
1875 0           return false;
1876             }
1877              
1878 0           static int submodule_read_config(git_submodule *sm, git_config *cfg)
1879             {
1880 0           git_buf key = GIT_BUF_INIT;
1881             const char *value;
1882 0           int error, in_config = 0;
1883              
1884             /*
1885             * TODO: Look up path in index and if it is present but not a GITLINK
1886             * then this should be deleted (at least to match git's behavior)
1887             */
1888              
1889 0 0         if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) {
1890 0           in_config = 1;
1891             /* We would warn here if we had that API */
1892 0 0         if (!looks_like_command_line_option(value)) {
1893             /*
1894             * TODO: if case insensitive filesystem, then the following strcmp
1895             * should be strcasecmp
1896             */
1897 0 0         if (strcmp(sm->name, value) != 0) {
1898 0 0         if (sm->path != sm->name)
1899 0           git__free(sm->path);
1900 0           sm->path = git__strdup(value);
1901 0 0         GIT_ERROR_CHECK_ALLOC(sm->path);
1902             }
1903              
1904             }
1905 0 0         } else if (error != GIT_ENOTFOUND) {
1906 0           goto cleanup;
1907             }
1908              
1909 0 0         if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
1910             /* We would warn here if we had that API */
1911 0 0         if (!looks_like_command_line_option(value)) {
1912 0           in_config = 1;
1913 0           sm->url = git__strdup(value);
1914 0 0         GIT_ERROR_CHECK_ALLOC(sm->url);
1915             }
1916 0 0         } else if (error != GIT_ENOTFOUND) {
1917 0           goto cleanup;
1918             }
1919              
1920 0 0         if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) {
1921 0           in_config = 1;
1922 0           sm->branch = git__strdup(value);
1923 0 0         GIT_ERROR_CHECK_ALLOC(sm->branch);
1924 0 0         } else if (error != GIT_ENOTFOUND) {
1925 0           goto cleanup;
1926             }
1927              
1928 0 0         if ((error = get_value(&value, cfg, &key, sm->name, "update")) == 0) {
1929 0           in_config = 1;
1930 0 0         if ((error = git_submodule_parse_update(&sm->update, value)) < 0)
1931 0           goto cleanup;
1932 0           sm->update_default = sm->update;
1933 0 0         } else if (error != GIT_ENOTFOUND) {
1934 0           goto cleanup;
1935             }
1936              
1937 0 0         if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) {
1938 0           in_config = 1;
1939 0 0         if ((error = submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
1940 0           goto cleanup;
1941 0           sm->fetch_recurse_default = sm->fetch_recurse;
1942 0 0         } else if (error != GIT_ENOTFOUND) {
1943 0           goto cleanup;
1944             }
1945              
1946 0 0         if ((error = get_value(&value, cfg, &key, sm->name, "ignore")) == 0) {
1947 0           in_config = 1;
1948 0 0         if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0)
1949 0           goto cleanup;
1950 0           sm->ignore_default = sm->ignore;
1951 0 0         } else if (error != GIT_ENOTFOUND) {
1952 0           goto cleanup;
1953             }
1954              
1955 0 0         if (in_config)
1956 0           sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
1957              
1958 0           error = 0;
1959              
1960             cleanup:
1961 0           git_buf_dispose(&key);
1962 0           return error;
1963             }
1964              
1965 0           static int submodule_load_each(const git_config_entry *entry, void *payload)
1966             {
1967 0           lfc_data *data = payload;
1968             const char *namestart, *property;
1969 0           git_strmap *map = data->map;
1970 0           git_buf name = GIT_BUF_INIT;
1971             git_submodule *sm;
1972             int error, isvalid;
1973              
1974 0 0         if (git__prefixcmp(entry->name, "submodule.") != 0)
1975 0           return 0;
1976              
1977 0           namestart = entry->name + strlen("submodule.");
1978 0           property = strrchr(namestart, '.');
1979              
1980 0 0         if (!property || (property == namestart))
    0          
1981 0           return 0;
1982              
1983 0           property++;
1984              
1985 0 0         if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
1986 0           return error;
1987              
1988 0           isvalid = git_submodule_name_is_valid(data->repo, name.ptr, 0);
1989 0 0         if (isvalid <= 0) {
1990 0           error = isvalid;
1991 0           goto done;
1992             }
1993              
1994             /*
1995             * Now that we have the submodule's name, we can use that to
1996             * figure out whether it's in the map. If it's not, we create
1997             * a new submodule, load the config and insert it. If it's
1998             * already inserted, we've already loaded it, so we skip.
1999             */
2000 0 0         if (git_strmap_exists(map, name.ptr)) {
2001 0           error = 0;
2002 0           goto done;
2003             }
2004              
2005 0 0         if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0)
2006 0           goto done;
2007              
2008 0 0         if ((error = submodule_read_config(sm, data->mods)) < 0) {
2009 0           git_submodule_free(sm);
2010 0           goto done;
2011             }
2012              
2013 0 0         if ((error = git_strmap_set(map, sm->name, sm)) < 0)
2014 0           goto done;
2015              
2016 0           error = 0;
2017              
2018             done:
2019 0           git_buf_dispose(&name);
2020 0           return error;
2021             }
2022              
2023 0           static int submodule_load_from_wd_lite(git_submodule *sm)
2024             {
2025 0           git_buf path = GIT_BUF_INIT;
2026              
2027 0 0         if (git_buf_joinpath(&path, git_repository_workdir(sm->repo), sm->path) < 0)
2028 0           return -1;
2029              
2030 0 0         if (git_path_isdir(path.ptr))
2031 0           sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
2032              
2033 0 0         if (git_path_contains(&path, DOT_GIT))
2034 0           sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;
2035              
2036 0           git_buf_dispose(&path);
2037 0           return 0;
2038             }
2039              
2040             /**
2041             * Requests a snapshot of $WORK_TREE/.gitmodules.
2042             *
2043             * Returns GIT_ENOTFOUND in case no .gitmodules file exist
2044             */
2045 0           static int gitmodules_snapshot(git_config **snap, git_repository *repo)
2046             {
2047 0           const char *workdir = git_repository_workdir(repo);
2048 0           git_config *mods = NULL;
2049 0           git_buf path = GIT_BUF_INIT;
2050             int error;
2051              
2052 0 0         if (!workdir)
2053 0           return GIT_ENOTFOUND;
2054              
2055 0 0         if ((error = git_buf_joinpath(&path, workdir, GIT_MODULES_FILE)) < 0)
2056 0           return error;
2057              
2058 0 0         if ((error = git_config_open_ondisk(&mods, path.ptr)) < 0)
2059 0           goto cleanup;
2060 0           git_buf_dispose(&path);
2061              
2062 0 0         if ((error = git_config_snapshot(snap, mods)) < 0)
2063 0           goto cleanup;
2064              
2065 0           error = 0;
2066              
2067             cleanup:
2068 0 0         if (mods)
2069 0           git_config_free(mods);
2070 0           git_buf_dispose(&path);
2071              
2072 0           return error;
2073             }
2074              
2075 0           static git_config_backend *open_gitmodules(
2076             git_repository *repo,
2077             int okay_to_create)
2078             {
2079 0           const char *workdir = git_repository_workdir(repo);
2080 0           git_buf path = GIT_BUF_INIT;
2081 0           git_config_backend *mods = NULL;
2082              
2083 0 0         if (workdir != NULL) {
2084 0 0         if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0)
2085 0           return NULL;
2086              
2087 0 0         if (okay_to_create || git_path_isfile(path.ptr)) {
    0          
2088             /* git_config_backend_from_file should only fail if OOM */
2089 0 0         if (git_config_backend_from_file(&mods, path.ptr) < 0)
2090 0           mods = NULL;
2091             /* open should only fail here if the file is malformed */
2092 0 0         else if (git_config_backend_open(mods, GIT_CONFIG_LEVEL_LOCAL, repo) < 0) {
2093 0           git_config_backend_free(mods);
2094 0           mods = NULL;
2095             }
2096             }
2097             }
2098              
2099 0           git_buf_dispose(&path);
2100              
2101 0           return mods;
2102             }
2103              
2104             /* Lookup name of remote of the local tracking branch HEAD points to */
2105 0           static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
2106             {
2107             int error;
2108 0           git_reference *head = NULL;
2109 0           git_buf upstream_name = GIT_BUF_INIT;
2110              
2111             /* lookup and dereference HEAD */
2112 0 0         if ((error = git_repository_head(&head, repo)) < 0)
2113 0           return error;
2114              
2115             /**
2116             * If head does not refer to a branch, then return
2117             * GIT_ENOTFOUND to indicate that we could not find
2118             * a remote key for the local tracking branch HEAD points to.
2119             **/
2120 0 0         if (!git_reference_is_branch(head)) {
2121 0           git_error_set(GIT_ERROR_INVALID,
2122             "HEAD does not refer to a branch.");
2123 0           error = GIT_ENOTFOUND;
2124 0           goto done;
2125             }
2126              
2127             /* lookup remote tracking branch of HEAD */
2128 0 0         if ((error = git_branch_upstream_name(
2129             &upstream_name,
2130             repo,
2131             git_reference_name(head))) < 0)
2132 0           goto done;
2133              
2134             /* lookup remote of remote tracking branch */
2135 0 0         if ((error = git_branch_remote_name(remote_name, repo, upstream_name.ptr)) < 0)
2136 0           goto done;
2137              
2138             done:
2139 0           git_buf_dispose(&upstream_name);
2140 0           git_reference_free(head);
2141              
2142 0           return error;
2143             }
2144              
2145             /* Lookup the remote of the local tracking branch HEAD points to */
2146 0           static int lookup_head_remote(git_remote **remote, git_repository *repo)
2147             {
2148             int error;
2149 0           git_buf remote_name = GIT_BUF_INIT;
2150              
2151             /* lookup remote of remote tracking branch name */
2152 0 0         if (!(error = lookup_head_remote_key(&remote_name, repo)))
2153 0           error = git_remote_lookup(remote, repo, remote_name.ptr);
2154              
2155 0           git_buf_dispose(&remote_name);
2156              
2157 0           return error;
2158             }
2159              
2160             /* Lookup remote, either from HEAD or fall back on origin */
2161 0           static int lookup_default_remote(git_remote **remote, git_repository *repo)
2162             {
2163 0           int error = lookup_head_remote(remote, repo);
2164              
2165             /* if that failed, use 'origin' instead */
2166 0 0         if (error == GIT_ENOTFOUND || error == GIT_EUNBORNBRANCH)
    0          
2167 0           error = git_remote_lookup(remote, repo, "origin");
2168              
2169 0 0         if (error == GIT_ENOTFOUND)
2170 0           git_error_set(
2171             GIT_ERROR_SUBMODULE,
2172             "cannot get default remote for submodule - no local tracking "
2173             "branch for HEAD and origin does not exist");
2174              
2175 0           return error;
2176             }
2177              
2178 0           static int get_url_base(git_buf *url, git_repository *repo)
2179             {
2180             int error;
2181 0           git_worktree *wt = NULL;
2182 0           git_remote *remote = NULL;
2183              
2184 0 0         if ((error = lookup_default_remote(&remote, repo)) == 0) {
2185 0           error = git_buf_sets(url, git_remote_url(remote));
2186 0           goto out;
2187 0 0         } else if (error != GIT_ENOTFOUND)
2188 0           goto out;
2189             else
2190 0           git_error_clear();
2191              
2192             /* if repository does not have a default remote, use workdir instead */
2193 0 0         if (git_repository_is_worktree(repo)) {
2194 0 0         if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
2195 0           goto out;
2196 0           error = git_buf_sets(url, wt->parent_path);
2197             } else
2198 0           error = git_buf_sets(url, git_repository_workdir(repo));
2199              
2200             out:
2201 0           git_remote_free(remote);
2202 0           git_worktree_free(wt);
2203              
2204 0           return error;
2205             }
2206              
2207 0           static void submodule_get_index_status(unsigned int *status, git_submodule *sm)
2208             {
2209 0           const git_oid *head_oid = git_submodule_head_id(sm);
2210 0           const git_oid *index_oid = git_submodule_index_id(sm);
2211              
2212 0           *status = *status & ~GIT_SUBMODULE_STATUS__INDEX_FLAGS;
2213              
2214 0 0         if (!head_oid) {
2215 0 0         if (index_oid)
2216 0           *status |= GIT_SUBMODULE_STATUS_INDEX_ADDED;
2217             }
2218 0 0         else if (!index_oid)
2219 0           *status |= GIT_SUBMODULE_STATUS_INDEX_DELETED;
2220 0 0         else if (!git_oid_equal(head_oid, index_oid))
2221 0           *status |= GIT_SUBMODULE_STATUS_INDEX_MODIFIED;
2222 0           }
2223              
2224              
2225 0           static void submodule_get_wd_status(
2226             unsigned int *status,
2227             git_submodule *sm,
2228             git_repository *sm_repo,
2229             git_submodule_ignore_t ign)
2230             {
2231 0           const git_oid *index_oid = git_submodule_index_id(sm);
2232 0           const git_oid *wd_oid =
2233 0 0         (sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) ? &sm->wd_oid : NULL;
2234 0           git_tree *sm_head = NULL;
2235 0           git_index *index = NULL;
2236 0           git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
2237             git_diff *diff;
2238              
2239 0           *status = *status & ~GIT_SUBMODULE_STATUS__WD_FLAGS;
2240              
2241 0 0         if (!index_oid) {
2242 0 0         if (wd_oid)
2243 0           *status |= GIT_SUBMODULE_STATUS_WD_ADDED;
2244             }
2245 0 0         else if (!wd_oid) {
2246 0 0         if ((sm->flags & GIT_SUBMODULE_STATUS__WD_SCANNED) != 0 &&
    0          
2247 0           (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0)
2248 0           *status |= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED;
2249             else
2250 0           *status |= GIT_SUBMODULE_STATUS_WD_DELETED;
2251             }
2252 0 0         else if (!git_oid_equal(index_oid, wd_oid))
2253 0           *status |= GIT_SUBMODULE_STATUS_WD_MODIFIED;
2254              
2255             /* if we have no repo, then we're done */
2256 0 0         if (!sm_repo)
2257 0           return;
2258              
2259             /* the diffs below could be optimized with an early termination
2260             * option to the git_diff functions, but for now this is sufficient
2261             * (and certainly no worse that what core git does).
2262             */
2263              
2264 0 0         if (ign == GIT_SUBMODULE_IGNORE_NONE)
2265 0           opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
2266              
2267 0           (void)git_repository_index__weakptr(&index, sm_repo);
2268              
2269             /* if we don't have an unborn head, check diff with index */
2270 0 0         if (git_repository_head_tree(&sm_head, sm_repo) < 0)
2271 0           git_error_clear();
2272             else {
2273             /* perform head to index diff on submodule */
2274 0 0         if (git_diff_tree_to_index(&diff, sm_repo, sm_head, index, &opt) < 0)
2275 0           git_error_clear();
2276             else {
2277 0 0         if (git_diff_num_deltas(diff) > 0)
2278 0           *status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED;
2279 0           git_diff_free(diff);
2280 0           diff = NULL;
2281             }
2282              
2283 0           git_tree_free(sm_head);
2284             }
2285              
2286             /* perform index-to-workdir diff on submodule */
2287 0 0         if (git_diff_index_to_workdir(&diff, sm_repo, index, &opt) < 0)
2288 0           git_error_clear();
2289             else {
2290 0           size_t untracked =
2291 0           git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED);
2292              
2293 0 0         if (untracked > 0)
2294 0           *status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED;
2295              
2296 0 0         if (git_diff_num_deltas(diff) != untracked)
2297 0           *status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED;
2298              
2299 0           git_diff_free(diff);
2300 0           diff = NULL;
2301             }
2302             }