2 * Copyright (C) 2009-2012 the libgit2 contributors
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.
12 #include "git2/submodule.h"
15 #define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC) do { \
16 (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \
17 GITERR_CHECK_ALLOC(P); \
18 (P)->base.type = GIT_ITERATOR_ ## NAME_UC; \
19 (P)->base.start = start ? git__strdup(start) : NULL; \
20 (P)->base.end = end ? git__strdup(end) : NULL; \
21 (P)->base.ignore_case = 0; \
22 (P)->base.current = NAME_LC ## _iterator__current; \
23 (P)->base.at_end = NAME_LC ## _iterator__at_end; \
24 (P)->base.advance = NAME_LC ## _iterator__advance; \
25 (P)->base.seek = NAME_LC ## _iterator__seek; \
26 (P)->base.reset = NAME_LC ## _iterator__reset; \
27 (P)->base.free = NAME_LC ## _iterator__free; \
28 if ((start && !(P)->base.start) || (end && !(P)->base.end)) \
33 static int empty_iterator__no_item(
34 git_iterator
*iter
, const git_index_entry
**entry
)
41 static int empty_iterator__at_end(git_iterator
*iter
)
47 static int empty_iterator__noop(git_iterator
*iter
)
53 static int empty_iterator__seek(git_iterator
*iter
, const char *prefix
)
60 static void empty_iterator__free(git_iterator
*iter
)
65 int git_iterator_for_nothing(git_iterator
**iter
)
67 git_iterator
*i
= git__calloc(1, sizeof(git_iterator
));
68 GITERR_CHECK_ALLOC(i
);
70 i
->type
= GIT_ITERATOR_EMPTY
;
71 i
->current
= empty_iterator__no_item
;
72 i
->at_end
= empty_iterator__at_end
;
73 i
->advance
= empty_iterator__no_item
;
74 i
->seek
= empty_iterator__seek
;
75 i
->reset
= empty_iterator__noop
;
76 i
->free
= empty_iterator__free
;
84 typedef struct tree_iterator_frame tree_iterator_frame
;
85 struct tree_iterator_frame
{
86 tree_iterator_frame
*next
, *prev
;
95 tree_iterator_frame
*stack
, *tail
;
96 git_index_entry entry
;
98 bool path_has_filename
;
101 static const git_tree_entry
*tree_iterator__tree_entry(tree_iterator
*ti
)
103 return (ti
->stack
== NULL
) ? NULL
:
104 git_tree_entry_byindex(ti
->stack
->tree
, ti
->stack
->index
);
107 static char *tree_iterator__current_filename(
108 tree_iterator
*ti
, const git_tree_entry
*te
)
110 if (!ti
->path_has_filename
) {
111 if (git_buf_joinpath(&ti
->path
, ti
->path
.ptr
, te
->filename
) < 0)
113 ti
->path_has_filename
= true;
119 static void tree_iterator__pop_frame(tree_iterator
*ti
)
121 tree_iterator_frame
*tf
= ti
->stack
;
122 ti
->stack
= tf
->next
;
123 if (ti
->stack
!= NULL
) {
124 git_tree_free(tf
->tree
); /* don't free the initial tree */
125 ti
->stack
->prev
= NULL
; /* disconnect prev */
130 static int tree_iterator__to_end(tree_iterator
*ti
)
132 while (ti
->stack
&& ti
->stack
->next
)
133 tree_iterator__pop_frame(ti
);
136 ti
->stack
->index
= git_tree_entrycount(ti
->stack
->tree
);
141 static int tree_iterator__current(
142 git_iterator
*self
, const git_index_entry
**entry
)
144 tree_iterator
*ti
= (tree_iterator
*)self
;
145 const git_tree_entry
*te
= tree_iterator__tree_entry(ti
);
153 ti
->entry
.mode
= te
->attr
;
154 git_oid_cpy(&ti
->entry
.oid
, &te
->oid
);
156 ti
->entry
.path
= tree_iterator__current_filename(ti
, te
);
157 if (ti
->entry
.path
== NULL
)
160 if (ti
->base
.end
&& git__prefixcmp(ti
->entry
.path
, ti
->base
.end
) > 0)
161 return tree_iterator__to_end(ti
);
169 static int tree_iterator__at_end(git_iterator
*self
)
171 return (tree_iterator__tree_entry((tree_iterator
*)self
) == NULL
);
174 static tree_iterator_frame
*tree_iterator__alloc_frame(
175 git_tree
*tree
, char *start
)
177 tree_iterator_frame
*tf
= git__calloc(1, sizeof(tree_iterator_frame
));
183 if (start
&& *start
) {
185 tf
->index
= git_tree__prefix_position(tree
, start
);
191 static int tree_iterator__expand_tree(tree_iterator
*ti
)
195 const git_tree_entry
*te
= tree_iterator__tree_entry(ti
);
196 tree_iterator_frame
*tf
;
199 while (te
!= NULL
&& git_tree_entry__is_tree(te
)) {
200 if (git_buf_joinpath(&ti
->path
, ti
->path
.ptr
, te
->filename
) < 0)
203 /* check that we have not passed the range end */
204 if (ti
->base
.end
!= NULL
&&
205 git__prefixcmp(ti
->path
.ptr
, ti
->base
.end
) > 0)
206 return tree_iterator__to_end(ti
);
208 if ((error
= git_tree_lookup(&subtree
, ti
->repo
, &te
->oid
)) < 0)
213 /* apply range start to new frame if relevant */
214 if (ti
->stack
->start
&&
215 git__prefixcmp(ti
->stack
->start
, te
->filename
) == 0)
217 size_t namelen
= strlen(te
->filename
);
218 if (ti
->stack
->start
[namelen
] == '/')
219 relpath
= ti
->stack
->start
+ namelen
+ 1;
222 if ((tf
= tree_iterator__alloc_frame(subtree
, relpath
)) == NULL
)
225 tf
->next
= ti
->stack
;
229 te
= tree_iterator__tree_entry(ti
);
235 static int tree_iterator__advance(
236 git_iterator
*self
, const git_index_entry
**entry
)
239 tree_iterator
*ti
= (tree_iterator
*)self
;
240 const git_tree_entry
*te
= NULL
;
245 if (ti
->path_has_filename
) {
246 git_buf_rtruncate_at_char(&ti
->path
, '/');
247 ti
->path_has_filename
= false;
250 while (ti
->stack
!= NULL
) {
251 te
= git_tree_entry_byindex(ti
->stack
->tree
, ++ti
->stack
->index
);
255 tree_iterator__pop_frame(ti
);
257 git_buf_rtruncate_at_char(&ti
->path
, '/');
260 if (te
&& git_tree_entry__is_tree(te
))
261 error
= tree_iterator__expand_tree(ti
);
264 error
= tree_iterator__current(self
, entry
);
269 static int tree_iterator__seek(git_iterator
*self
, const char *prefix
)
273 /* pop stack until matches prefix */
274 /* seek item in current frame matching prefix */
275 /* push stack which matches prefix */
279 static void tree_iterator__free(git_iterator
*self
)
281 tree_iterator
*ti
= (tree_iterator
*)self
;
282 while (ti
->stack
!= NULL
)
283 tree_iterator__pop_frame(ti
);
284 git_buf_free(&ti
->path
);
287 static int tree_iterator__reset(git_iterator
*self
)
289 tree_iterator
*ti
= (tree_iterator
*)self
;
291 while (ti
->stack
&& ti
->stack
->next
)
292 tree_iterator__pop_frame(ti
);
296 git_tree__prefix_position(ti
->stack
->tree
, ti
->base
.start
);
298 git_buf_clear(&ti
->path
);
300 return tree_iterator__expand_tree(ti
);
303 int git_iterator_for_tree_range(
305 git_repository
*repo
,
314 return git_iterator_for_nothing(iter
);
316 ITERATOR_BASE_INIT(ti
, tree
, TREE
);
319 ti
->stack
= ti
->tail
= tree_iterator__alloc_frame(tree
, ti
->base
.start
);
321 if ((error
= tree_iterator__expand_tree(ti
)) < 0)
322 git_iterator_free((git_iterator
*)ti
);
324 *iter
= (git_iterator
*)ti
;
337 static int index_iterator__current(
338 git_iterator
*self
, const git_index_entry
**entry
)
340 index_iterator
*ii
= (index_iterator
*)self
;
341 const git_index_entry
*ie
= git_index_get_byindex(ii
->index
, ii
->current
);
349 static int index_iterator__at_end(git_iterator
*self
)
351 index_iterator
*ii
= (index_iterator
*)self
;
352 return (ii
->current
>= git_index_entrycount(ii
->index
));
355 static void index_iterator__skip_conflicts(
358 size_t entrycount
= git_index_entrycount(ii
->index
);
359 const git_index_entry
*ie
;
361 while (ii
->current
< entrycount
) {
362 ie
= git_index_get_byindex(ii
->index
, ii
->current
);
365 (ii
->base
.end
!= NULL
&&
366 ITERATOR_PREFIXCMP(ii
->base
, ie
->path
, ii
->base
.end
) > 0)) {
367 ii
->current
= entrycount
;
371 if (git_index_entry_stage(ie
) == 0)
378 static int index_iterator__advance(
379 git_iterator
*self
, const git_index_entry
**entry
)
381 index_iterator
*ii
= (index_iterator
*)self
;
383 if (ii
->current
< git_index_entrycount(ii
->index
))
386 index_iterator__skip_conflicts(ii
);
388 return index_iterator__current(self
, entry
);
391 static int index_iterator__seek(git_iterator
*self
, const char *prefix
)
395 /* find last item before prefix */
399 static int index_iterator__reset(git_iterator
*self
)
401 index_iterator
*ii
= (index_iterator
*)self
;
402 ii
->current
= ii
->base
.start
?
403 git_index__prefix_position(ii
->index
, ii
->base
.start
) : 0;
404 index_iterator__skip_conflicts(ii
);
408 static void index_iterator__free(git_iterator
*self
)
410 index_iterator
*ii
= (index_iterator
*)self
;
412 git_index_free(ii
->index
);
416 int git_iterator_for_index_range(
424 ITERATOR_BASE_INIT(ii
, index
, INDEX
);
427 ii
->base
.ignore_case
= ii
->index
->ignore_case
;
429 index_iterator__reset((git_iterator
*)ii
);
431 *iter
= (git_iterator
*)ii
;
436 int git_iterator_for_repo_index_range(
438 git_repository
*repo
,
445 if ((error
= git_repository_index(&index
, repo
)) < 0)
448 if (!(error
= git_iterator_for_index_range(iter
, index
, start
, end
)))
449 ((index_iterator
*)(*iter
))->free_index
= true;
454 typedef struct workdir_iterator_frame workdir_iterator_frame
;
455 struct workdir_iterator_frame
{
456 workdir_iterator_frame
*next
;
464 git_repository
*repo
;
466 workdir_iterator_frame
*stack
;
468 git_index_entry entry
;
473 static int git_path_with_stat_cmp_case(const void *a
, const void *b
)
475 const git_path_with_stat
*path_with_stat_a
= a
;
476 const git_path_with_stat
*path_with_stat_b
= b
;
478 return strcmp(path_with_stat_a
->path
, path_with_stat_b
->path
);
481 static int git_path_with_stat_cmp_icase(const void *a
, const void *b
)
483 const git_path_with_stat
*path_with_stat_a
= a
;
484 const git_path_with_stat
*path_with_stat_b
= b
;
486 return strcasecmp(path_with_stat_a
->path
, path_with_stat_b
->path
);
489 GIT_INLINE(bool) path_is_dotgit(const git_path_with_stat
*ps
)
494 const char *path
= ps
->path
;
495 size_t len
= ps
->path_len
;
498 tolower(path
[len
- 1]) == 't' &&
499 tolower(path
[len
- 2]) == 'i' &&
500 tolower(path
[len
- 3]) == 'g' &&
501 path
[len
- 4] == '.' &&
502 (len
== 4 || path
[len
- 5] == '/');
506 static workdir_iterator_frame
*workdir_iterator__alloc_frame(workdir_iterator
*wi
)
508 workdir_iterator_frame
*wf
= git__calloc(1, sizeof(workdir_iterator_frame
));
509 git_vector_cmp entry_compare
= CASESELECT(wi
->base
.ignore_case
, git_path_with_stat_cmp_icase
, git_path_with_stat_cmp_case
);
513 if (git_vector_init(&wf
->entries
, 0, entry_compare
) != 0) {
520 static void workdir_iterator__free_frame(workdir_iterator_frame
*wf
)
523 git_path_with_stat
*path
;
525 git_vector_foreach(&wf
->entries
, i
, path
)
527 git_vector_free(&wf
->entries
);
531 static int workdir_iterator__update_entry(workdir_iterator
*wi
);
533 static int workdir_iterator__entry_cmp_case(const void *prefix
, const void *item
)
535 const git_path_with_stat
*ps
= item
;
536 return git__prefixcmp((const char *)prefix
, ps
->path
);
539 static int workdir_iterator__entry_cmp_icase(const void *prefix
, const void *item
)
541 const git_path_with_stat
*ps
= item
;
542 return git__prefixcmp_icase((const char *)prefix
, ps
->path
);
545 static int workdir_iterator__expand_dir(workdir_iterator
*wi
)
548 workdir_iterator_frame
*wf
= workdir_iterator__alloc_frame(wi
);
549 GITERR_CHECK_ALLOC(wf
);
551 error
= git_path_dirload_with_stat(wi
->path
.ptr
, wi
->root_len
, &wf
->entries
);
552 if (error
< 0 || wf
->entries
.length
== 0) {
553 workdir_iterator__free_frame(wf
);
554 return GIT_ENOTFOUND
;
557 git_vector_sort(&wf
->entries
);
560 wf
->start
= wi
->base
.start
;
561 else if (wi
->stack
->start
&&
562 ITERATOR_PREFIXCMP(wi
->base
, wi
->stack
->start
, wi
->path
.ptr
+ wi
->root_len
) == 0)
563 wf
->start
= wi
->stack
->start
;
569 CASESELECT(wi
->base
.ignore_case
, workdir_iterator__entry_cmp_icase
, workdir_iterator__entry_cmp_case
),
572 if (path_is_dotgit(git_vector_get(&wf
->entries
, wf
->index
)))
575 wf
->next
= wi
->stack
;
578 /* only push new ignores if this is not top level directory */
579 if (wi
->stack
->next
!= NULL
) {
580 ssize_t slash_pos
= git_buf_rfind_next(&wi
->path
, '/');
581 (void)git_ignore__push_dir(&wi
->ignores
, &wi
->path
.ptr
[slash_pos
+ 1]);
584 return workdir_iterator__update_entry(wi
);
587 static int workdir_iterator__current(
588 git_iterator
*self
, const git_index_entry
**entry
)
590 workdir_iterator
*wi
= (workdir_iterator
*)self
;
591 *entry
= (wi
->entry
.path
== NULL
) ? NULL
: &wi
->entry
;
595 static int workdir_iterator__at_end(git_iterator
*self
)
597 return (((workdir_iterator
*)self
)->entry
.path
== NULL
);
600 static int workdir_iterator__advance(
601 git_iterator
*self
, const git_index_entry
**entry
)
604 workdir_iterator
*wi
= (workdir_iterator
*)self
;
605 workdir_iterator_frame
*wf
;
606 git_path_with_stat
*next
;
611 if (wi
->entry
.path
== NULL
)
614 while ((wf
= wi
->stack
) != NULL
) {
615 next
= git_vector_get(&wf
->entries
, ++wf
->index
);
617 /* match git's behavior of ignoring anything named ".git" */
618 if (path_is_dotgit(next
))
620 /* else found a good entry */
624 /* pop workdir directory stack */
625 wi
->stack
= wf
->next
;
626 workdir_iterator__free_frame(wf
);
627 git_ignore__pop_dir(&wi
->ignores
);
629 if (wi
->stack
== NULL
) {
630 memset(&wi
->entry
, 0, sizeof(wi
->entry
));
635 error
= workdir_iterator__update_entry(wi
);
637 if (!error
&& entry
!= NULL
)
638 error
= workdir_iterator__current(self
, entry
);
643 static int workdir_iterator__seek(git_iterator
*self
, const char *prefix
)
647 /* pop stack until matching prefix */
648 /* find prefix item in current frame */
649 /* push subdirectories as deep as possible while matching */
653 static int workdir_iterator__reset(git_iterator
*self
)
655 workdir_iterator
*wi
= (workdir_iterator
*)self
;
656 while (wi
->stack
!= NULL
&& wi
->stack
->next
!= NULL
) {
657 workdir_iterator_frame
*wf
= wi
->stack
;
658 wi
->stack
= wf
->next
;
659 workdir_iterator__free_frame(wf
);
660 git_ignore__pop_dir(&wi
->ignores
);
663 wi
->stack
->index
= 0;
667 static void workdir_iterator__free(git_iterator
*self
)
669 workdir_iterator
*wi
= (workdir_iterator
*)self
;
671 while (wi
->stack
!= NULL
) {
672 workdir_iterator_frame
*wf
= wi
->stack
;
673 wi
->stack
= wf
->next
;
674 workdir_iterator__free_frame(wf
);
677 git_ignore__free(&wi
->ignores
);
678 git_buf_free(&wi
->path
);
681 static int workdir_iterator__update_entry(workdir_iterator
*wi
)
683 git_path_with_stat
*ps
= git_vector_get(&wi
->stack
->entries
, wi
->stack
->index
);
685 git_buf_truncate(&wi
->path
, wi
->root_len
);
686 memset(&wi
->entry
, 0, sizeof(wi
->entry
));
691 if (git_buf_put(&wi
->path
, ps
->path
, ps
->path_len
) < 0)
695 ITERATOR_PREFIXCMP(wi
->base
, wi
->path
.ptr
+ wi
->root_len
, wi
->base
.end
) > 0)
698 wi
->entry
.path
= ps
->path
;
700 /* skip over .git entries */
701 if (path_is_dotgit(ps
))
702 return workdir_iterator__advance((git_iterator
*)wi
, NULL
);
706 git_index_entry__init_from_stat(&wi
->entry
, &ps
->st
);
708 /* need different mode here to keep directories during iteration */
709 wi
->entry
.mode
= git_futils_canonical_mode(ps
->st
.st_mode
);
711 /* if this is a file type we don't handle, treat as ignored */
712 if (wi
->entry
.mode
== 0) {
717 /* detect submodules */
718 if (S_ISDIR(wi
->entry
.mode
)) {
719 int res
= git_submodule_lookup(NULL
, wi
->repo
, wi
->entry
.path
);
720 bool is_submodule
= (res
== 0);
721 if (res
== GIT_ENOTFOUND
)
724 /* if submodule, mark as GITLINK and remove trailing slash */
726 size_t len
= strlen(wi
->entry
.path
);
727 assert(wi
->entry
.path
[len
- 1] == '/');
728 wi
->entry
.path
[len
- 1] = '\0';
729 wi
->entry
.mode
= S_IFGITLINK
;
736 int git_iterator_for_workdir_range(
738 git_repository
*repo
,
743 workdir_iterator
*wi
;
746 assert(iter
&& repo
);
748 if ((error
= git_repository__ensure_not_bare(
749 repo
, "scan working directory")) < 0)
752 ITERATOR_BASE_INIT(wi
, workdir
, WORKDIR
);
755 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0) {
760 /* Match ignore_case flag for iterator to that of the index */
761 wi
->base
.ignore_case
= index
->ignore_case
;
763 if (git_buf_sets(&wi
->path
, git_repository_workdir(repo
)) < 0 ||
764 git_path_to_dir(&wi
->path
) < 0 ||
765 git_ignore__for_path(repo
, "", &wi
->ignores
) < 0)
771 wi
->root_len
= wi
->path
.size
;
773 if ((error
= workdir_iterator__expand_dir(wi
)) < 0) {
774 if (error
== GIT_ENOTFOUND
)
777 git_iterator_free((git_iterator
*)wi
);
782 *iter
= (git_iterator
*)wi
;
789 git_iterator
*wrapped
;
791 git_vector_cmp comparer
;
793 git_pool string_pool
;
794 unsigned int position
;
795 } spoolandsort_iterator
;
797 static int spoolandsort_iterator__current(
798 git_iterator
*self
, const git_index_entry
**entry
)
800 spoolandsort_iterator
*si
= (spoolandsort_iterator
*)self
;
802 if (si
->position
< si
->entries
.length
)
803 *entry
= (const git_index_entry
*)git_vector_get(
804 &si
->entries
, si
->position
);
811 static int spoolandsort_iterator__at_end(git_iterator
*self
)
813 spoolandsort_iterator
*si
= (spoolandsort_iterator
*)self
;
815 return 0 == si
->entries
.length
|| si
->entries
.length
- 1 <= si
->position
;
818 static int spoolandsort_iterator__advance(
819 git_iterator
*self
, const git_index_entry
**entry
)
821 spoolandsort_iterator
*si
= (spoolandsort_iterator
*)self
;
823 if (si
->position
< si
->entries
.length
)
824 *entry
= (const git_index_entry
*)git_vector_get(
825 &si
->entries
, ++si
->position
);
832 static int spoolandsort_iterator__seek(git_iterator
*self
, const char *prefix
)
840 static int spoolandsort_iterator__reset(git_iterator
*self
)
842 spoolandsort_iterator
*si
= (spoolandsort_iterator
*)self
;
849 static void spoolandsort_iterator__free(git_iterator
*self
)
851 spoolandsort_iterator
*si
= (spoolandsort_iterator
*)self
;
853 git_pool_clear(&si
->string_pool
);
854 git_pool_clear(&si
->entry_pool
);
855 git_vector_free(&si
->entries
);
856 git_iterator_free(si
->wrapped
);
859 int git_iterator_spoolandsort_range(
861 git_iterator
*towrap
,
862 git_vector_cmp comparer
,
867 spoolandsort_iterator
*si
;
868 const git_index_entry
*item
;
870 assert(iter
&& towrap
&& comparer
);
872 ITERATOR_BASE_INIT(si
, spoolandsort
, SPOOLANDSORT
);
873 si
->base
.ignore_case
= ignore_case
;
874 si
->wrapped
= towrap
;
875 si
->comparer
= comparer
;
878 if (git_vector_init(&si
->entries
, 16, si
->comparer
) < 0 ||
879 git_iterator_current(towrap
, &item
) < 0 ||
880 git_pool_init(&si
->entry_pool
, sizeof(git_index_entry
), 0) ||
881 git_pool_init(&si
->string_pool
, 1, 0))
889 git_index_entry
*clone
= git_pool_malloc(&si
->entry_pool
, 1);
890 memcpy(clone
, item
, sizeof(git_index_entry
));
894 clone
->path
= git_pool_strdup(&si
->string_pool
, item
->path
);
897 git_vector_insert(&si
->entries
, clone
);
899 if (git_iterator_advance(towrap
, &item
) < 0)
906 git_vector_sort(&si
->entries
);
908 *iter
= (git_iterator
*)si
;
913 int git_iterator_current_tree_entry(
914 git_iterator
*iter
, const git_tree_entry
**tree_entry
)
916 *tree_entry
= (iter
->type
!= GIT_ITERATOR_TREE
) ? NULL
:
917 tree_iterator__tree_entry((tree_iterator
*)iter
);
921 int git_iterator_current_parent_tree(
923 const char *parent_path
,
924 const git_tree
**tree_ptr
)
926 tree_iterator
*ti
= (tree_iterator
*)iter
;
927 tree_iterator_frame
*tf
;
928 const char *scan
= parent_path
;
930 if (iter
->type
!= GIT_ITERATOR_TREE
|| ti
->stack
== NULL
)
933 for (tf
= ti
->tail
; tf
!= NULL
; tf
= tf
->prev
) {
934 const git_tree_entry
*te
;
937 *tree_ptr
= tf
->tree
;
941 te
= git_tree_entry_byindex(tf
->tree
, tf
->index
);
943 if (strncmp(scan
, te
->filename
, te
->filename_len
) != 0)
946 scan
+= te
->filename_len
;
960 int git_iterator_current_is_ignored(git_iterator
*iter
)
962 workdir_iterator
*wi
= (workdir_iterator
*)iter
;
964 if (iter
->type
!= GIT_ITERATOR_WORKDIR
)
967 if (wi
->is_ignored
!= -1)
968 return wi
->is_ignored
;
970 if (git_ignore__lookup(&wi
->ignores
, wi
->entry
.path
, &wi
->is_ignored
) < 0)
973 return wi
->is_ignored
;
976 int git_iterator_advance_into_directory(
977 git_iterator
*iter
, const git_index_entry
**entry
)
979 workdir_iterator
*wi
= (workdir_iterator
*)iter
;
981 if (iter
->type
== GIT_ITERATOR_WORKDIR
&&
983 S_ISDIR(wi
->entry
.mode
) &&
984 !S_ISGITLINK(wi
->entry
.mode
))
986 if (workdir_iterator__expand_dir(wi
) < 0)
987 /* if error loading or if empty, skip the directory. */
988 return workdir_iterator__advance(iter
, entry
);
991 return entry
? git_iterator_current(iter
, entry
) : 0;
994 int git_iterator_cmp(
995 git_iterator
*iter
, const char *path_prefix
)
997 const git_index_entry
*entry
;
999 /* a "done" iterator is after every prefix */
1000 if (git_iterator_current(iter
, &entry
) < 0 ||
1004 /* a NULL prefix is after any valid iterator */
1008 return ITERATOR_PREFIXCMP(*iter
, entry
->path
, path_prefix
);
1011 int git_iterator_current_workdir_path(git_iterator
*iter
, git_buf
**path
)
1013 workdir_iterator
*wi
= (workdir_iterator
*)iter
;
1015 if (iter
->type
!= GIT_ITERATOR_WORKDIR
|| !wi
->entry
.path
)