rugged 0.25.0b2 → 0.25.0b3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/ext/rugged/extconf.rb +3 -1
- data/ext/rugged/rugged.c +1 -1
- data/ext/rugged/rugged.h +1 -1
- data/ext/rugged/rugged_blob.c +29 -38
- data/ext/rugged/rugged_commit.c +215 -78
- data/ext/rugged/rugged_rebase.c +18 -11
- data/ext/rugged/rugged_remote.c +2 -2
- data/ext/rugged/rugged_tree.c +132 -0
- data/lib/rugged/version.rb +1 -1
- data/vendor/libgit2/CMakeLists.txt +11 -3
- data/vendor/libgit2/include/git2.h +1 -0
- data/vendor/libgit2/include/git2/blob.h +39 -28
- data/vendor/libgit2/include/git2/commit.h +30 -0
- data/vendor/libgit2/include/git2/common.h +16 -1
- data/vendor/libgit2/include/git2/merge.h +10 -1
- data/vendor/libgit2/include/git2/proxy.h +92 -0
- data/vendor/libgit2/include/git2/refs.h +11 -0
- data/vendor/libgit2/include/git2/remote.h +17 -4
- data/vendor/libgit2/include/git2/signature.h +13 -0
- data/vendor/libgit2/include/git2/sys/merge.h +177 -0
- data/vendor/libgit2/include/git2/sys/remote.h +16 -0
- data/vendor/libgit2/include/git2/sys/stream.h +2 -1
- data/vendor/libgit2/include/git2/sys/transport.h +3 -1
- data/vendor/libgit2/include/git2/tag.h +9 -0
- data/vendor/libgit2/include/git2/tree.h +55 -0
- data/vendor/libgit2/src/annotated_commit.c +99 -80
- data/vendor/libgit2/src/annotated_commit.h +5 -2
- data/vendor/libgit2/src/array.h +40 -0
- data/vendor/libgit2/src/blame.c +8 -3
- data/vendor/libgit2/src/blame_git.c +2 -1
- data/vendor/libgit2/src/blob.c +71 -39
- data/vendor/libgit2/src/branch.c +2 -1
- data/vendor/libgit2/src/checkout.c +66 -42
- data/vendor/libgit2/src/commit.c +67 -3
- data/vendor/libgit2/src/config_cache.c +2 -1
- data/vendor/libgit2/src/config_file.c +32 -27
- data/vendor/libgit2/src/curl_stream.c +89 -6
- data/vendor/libgit2/src/delta-apply.c +36 -5
- data/vendor/libgit2/src/delta-apply.h +12 -0
- data/vendor/libgit2/src/describe.c +3 -2
- data/vendor/libgit2/src/diff.c +13 -20
- data/vendor/libgit2/src/diff_tform.c +5 -3
- data/vendor/libgit2/src/filebuf.c +12 -2
- data/vendor/libgit2/src/filebuf.h +1 -0
- data/vendor/libgit2/src/fnmatch.c +18 -5
- data/vendor/libgit2/src/global.c +18 -0
- data/vendor/libgit2/src/global.h +1 -0
- data/vendor/libgit2/src/ignore.c +11 -3
- data/vendor/libgit2/src/index.c +11 -5
- data/vendor/libgit2/src/indexer.c +11 -7
- data/vendor/libgit2/src/iterator.c +1575 -1468
- data/vendor/libgit2/src/iterator.h +52 -69
- data/vendor/libgit2/src/merge.c +160 -63
- data/vendor/libgit2/src/merge.h +61 -2
- data/vendor/libgit2/src/merge_driver.c +397 -0
- data/vendor/libgit2/src/merge_driver.h +60 -0
- data/vendor/libgit2/src/merge_file.c +11 -49
- data/vendor/libgit2/src/netops.c +12 -10
- data/vendor/libgit2/src/object.c +3 -6
- data/vendor/libgit2/src/object_api.c +19 -1
- data/vendor/libgit2/src/odb_loose.c +1 -1
- data/vendor/libgit2/src/openssl_stream.c +16 -3
- data/vendor/libgit2/src/pack-objects.c +3 -1
- data/vendor/libgit2/src/pack.c +5 -9
- data/vendor/libgit2/src/path.c +14 -0
- data/vendor/libgit2/src/path.h +12 -0
- data/vendor/libgit2/src/pathspec.c +1 -1
- data/vendor/libgit2/src/posix.c +7 -0
- data/vendor/libgit2/src/posix.h +1 -0
- data/vendor/libgit2/src/proxy.c +32 -0
- data/vendor/libgit2/src/proxy.h +14 -0
- data/vendor/libgit2/src/push.c +7 -7
- data/vendor/libgit2/src/rebase.c +61 -31
- data/vendor/libgit2/src/refdb_fs.c +1 -0
- data/vendor/libgit2/src/refs.c +16 -1
- data/vendor/libgit2/src/remote.c +20 -6
- data/vendor/libgit2/src/repository.c +1 -1
- data/vendor/libgit2/src/reset.c +1 -1
- data/vendor/libgit2/src/settings.c +23 -1
- data/vendor/libgit2/src/signature.c +26 -1
- data/vendor/libgit2/src/stransport_stream.c +5 -2
- data/vendor/libgit2/src/stream.h +2 -2
- data/vendor/libgit2/src/submodule.c +3 -2
- data/vendor/libgit2/src/tag.c +8 -2
- data/vendor/libgit2/src/transports/http.c +32 -9
- data/vendor/libgit2/src/transports/local.c +4 -1
- data/vendor/libgit2/src/transports/smart.c +6 -0
- data/vendor/libgit2/src/transports/smart.h +1 -0
- data/vendor/libgit2/src/transports/smart_protocol.c +61 -17
- data/vendor/libgit2/src/transports/winhttp.c +130 -11
- data/vendor/libgit2/src/tree.c +329 -98
- data/vendor/libgit2/src/tree.h +4 -5
- data/vendor/libgit2/src/unix/map.c +5 -0
- data/vendor/libgit2/src/win32/map.c +24 -5
- data/vendor/libgit2/src/xdiff/xprepare.c +2 -1
- metadata +10 -4
- data/vendor/libgit2/Makefile.embed +0 -60
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#define INCLUDE_delta_apply_h__
|
|
9
9
|
|
|
10
10
|
#include "odb.h"
|
|
11
|
+
#include "pack.h"
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Apply a git binary delta to recover the original content.
|
|
@@ -47,4 +48,15 @@ extern int git__delta_read_header(
|
|
|
47
48
|
size_t *base_sz,
|
|
48
49
|
size_t *res_sz);
|
|
49
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Read the header of a git binary delta
|
|
53
|
+
*
|
|
54
|
+
* This variant reads just enough from the packfile stream to read the
|
|
55
|
+
* delta header.
|
|
56
|
+
*/
|
|
57
|
+
extern int git__delta_read_header_fromstream(
|
|
58
|
+
size_t *base_sz,
|
|
59
|
+
size_t *res_sz,
|
|
60
|
+
git_packfile_stream *stream);
|
|
61
|
+
|
|
50
62
|
#endif
|
|
@@ -197,7 +197,7 @@ static int commit_name_dup(struct commit_name **out, struct commit_name *in)
|
|
|
197
197
|
name->tag = NULL;
|
|
198
198
|
name->path = NULL;
|
|
199
199
|
|
|
200
|
-
if (in->tag &&
|
|
200
|
+
if (in->tag && git_tag_dup(&name->tag, in->tag) < 0)
|
|
201
201
|
return -1;
|
|
202
202
|
|
|
203
203
|
name->path = git__strdup(in->path);
|
|
@@ -582,7 +582,8 @@ static int describe(
|
|
|
582
582
|
best = (struct possible_tag *)git_vector_get(&all_matches, 0);
|
|
583
583
|
|
|
584
584
|
if (gave_up_on) {
|
|
585
|
-
git_pqueue_insert(&list, gave_up_on)
|
|
585
|
+
if ((error = git_pqueue_insert(&list, gave_up_on)) < 0)
|
|
586
|
+
goto cleanup;
|
|
586
587
|
seen_commits--;
|
|
587
588
|
}
|
|
588
589
|
if ((error = finish_depth_computation(
|
data/vendor/libgit2/src/diff.c
CHANGED
|
@@ -826,8 +826,7 @@ static int maybe_modified(
|
|
|
826
826
|
*/
|
|
827
827
|
} else if (git_oid_iszero(&nitem->id) && new_is_workdir) {
|
|
828
828
|
bool use_ctime = ((diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) != 0);
|
|
829
|
-
git_index *index;
|
|
830
|
-
git_iterator_index(&index, info->new_iter);
|
|
829
|
+
git_index *index = git_iterator_index(info->new_iter);
|
|
831
830
|
|
|
832
831
|
status = GIT_DELTA_UNMODIFIED;
|
|
833
832
|
|
|
@@ -980,15 +979,14 @@ static int iterator_advance_into(
|
|
|
980
979
|
return error;
|
|
981
980
|
}
|
|
982
981
|
|
|
983
|
-
static int
|
|
982
|
+
static int iterator_advance_over(
|
|
984
983
|
const git_index_entry **entry,
|
|
985
984
|
git_iterator_status_t *status,
|
|
986
985
|
git_iterator *iterator)
|
|
987
986
|
{
|
|
988
|
-
int error;
|
|
987
|
+
int error = git_iterator_advance_over(entry, status, iterator);
|
|
989
988
|
|
|
990
|
-
if (
|
|
991
|
-
entry, status, iterator)) == GIT_ITEROVER) {
|
|
989
|
+
if (error == GIT_ITEROVER) {
|
|
992
990
|
*entry = NULL;
|
|
993
991
|
error = 0;
|
|
994
992
|
}
|
|
@@ -1056,7 +1054,7 @@ static int handle_unmatched_new_item(
|
|
|
1056
1054
|
return iterator_advance(&info->nitem, info->new_iter);
|
|
1057
1055
|
|
|
1058
1056
|
/* iterate into dir looking for an actual untracked file */
|
|
1059
|
-
if ((error =
|
|
1057
|
+
if ((error = iterator_advance_over(
|
|
1060
1058
|
&info->nitem, &untracked_state, info->new_iter)) < 0)
|
|
1061
1059
|
return error;
|
|
1062
1060
|
|
|
@@ -1085,17 +1083,13 @@ static int handle_unmatched_new_item(
|
|
|
1085
1083
|
if (recurse_into_dir) {
|
|
1086
1084
|
error = iterator_advance_into(&info->nitem, info->new_iter);
|
|
1087
1085
|
|
|
1088
|
-
/* if
|
|
1089
|
-
if (error
|
|
1090
|
-
|
|
1091
|
-
|
|
1086
|
+
/* if directory is empty, can't advance into it, so skip it */
|
|
1087
|
+
if (error == GIT_ENOTFOUND) {
|
|
1088
|
+
giterr_clear();
|
|
1089
|
+
error = iterator_advance(&info->nitem, info->new_iter);
|
|
1090
|
+
}
|
|
1092
1091
|
|
|
1093
|
-
|
|
1094
|
-
* it or ignore it
|
|
1095
|
-
*/
|
|
1096
|
-
if (contains_oitem)
|
|
1097
|
-
return iterator_advance(&info->nitem, info->new_iter);
|
|
1098
|
-
delta_type = GIT_DELTA_IGNORED;
|
|
1092
|
+
return error;
|
|
1099
1093
|
}
|
|
1100
1094
|
}
|
|
1101
1095
|
|
|
@@ -1231,9 +1225,8 @@ int git_diff__from_iterators(
|
|
|
1231
1225
|
|
|
1232
1226
|
/* make iterators have matching icase behavior */
|
|
1233
1227
|
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE)) {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
goto cleanup;
|
|
1228
|
+
git_iterator_set_ignore_case(old_iter, true);
|
|
1229
|
+
git_iterator_set_ignore_case(new_iter, true);
|
|
1237
1230
|
}
|
|
1238
1231
|
|
|
1239
1232
|
/* finish initialization */
|
|
@@ -261,7 +261,7 @@ static int normalize_find_opts(
|
|
|
261
261
|
if (!given ||
|
|
262
262
|
(given->flags & GIT_DIFF_FIND_ALL) == GIT_DIFF_FIND_BY_CONFIG)
|
|
263
263
|
{
|
|
264
|
-
if (
|
|
264
|
+
if (cfg) {
|
|
265
265
|
char *rule =
|
|
266
266
|
git_config__get_string_force(cfg, "diff.renames", "true");
|
|
267
267
|
int boolval;
|
|
@@ -318,8 +318,10 @@ static int normalize_find_opts(
|
|
|
318
318
|
#undef USE_DEFAULT
|
|
319
319
|
|
|
320
320
|
if (!opts->rename_limit) {
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
if (cfg) {
|
|
322
|
+
opts->rename_limit = git_config__get_int_force(
|
|
323
|
+
cfg, "diff.renamelimit", DEFAULT_RENAME_LIMIT);
|
|
324
|
+
}
|
|
323
325
|
|
|
324
326
|
if (opts->rename_limit <= 0)
|
|
325
327
|
opts->rename_limit = DEFAULT_RENAME_LIMIT;
|
|
@@ -70,6 +70,7 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode)
|
|
|
70
70
|
git_file source;
|
|
71
71
|
char buffer[FILEIO_BUFSIZE];
|
|
72
72
|
ssize_t read_bytes;
|
|
73
|
+
int error;
|
|
73
74
|
|
|
74
75
|
source = p_open(file->path_original, O_RDONLY);
|
|
75
76
|
if (source < 0) {
|
|
@@ -80,7 +81,8 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode)
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
while ((read_bytes = p_read(source, buffer, sizeof(buffer))) > 0) {
|
|
83
|
-
p_write(file->fd, buffer, read_bytes)
|
|
84
|
+
if ((error = p_write(file->fd, buffer, read_bytes)) < 0)
|
|
85
|
+
break;
|
|
84
86
|
if (file->compute_digest)
|
|
85
87
|
git_hash_update(&file->digest, buffer, read_bytes);
|
|
86
88
|
}
|
|
@@ -90,6 +92,9 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode)
|
|
|
90
92
|
if (read_bytes < 0) {
|
|
91
93
|
giterr_set(GITERR_OS, "Failed to read file '%s'", file->path_original);
|
|
92
94
|
return -1;
|
|
95
|
+
} else if (error < 0) {
|
|
96
|
+
giterr_set(GITERR_OS, "Failed to write file '%s'", file->path_lock);
|
|
97
|
+
return -1;
|
|
93
98
|
}
|
|
94
99
|
}
|
|
95
100
|
|
|
@@ -267,6 +272,11 @@ cleanup:
|
|
|
267
272
|
}
|
|
268
273
|
|
|
269
274
|
int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode)
|
|
275
|
+
{
|
|
276
|
+
return git_filebuf_open_withsize(file, path, flags, mode, WRITE_BUFFER_SIZE);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mode_t mode, size_t size)
|
|
270
280
|
{
|
|
271
281
|
int compression, error = -1;
|
|
272
282
|
size_t path_len, alloc_len;
|
|
@@ -281,7 +291,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
|
|
|
281
291
|
if (flags & GIT_FILEBUF_DO_NOT_BUFFER)
|
|
282
292
|
file->do_not_buffer = true;
|
|
283
293
|
|
|
284
|
-
file->buf_size =
|
|
294
|
+
file->buf_size = size;
|
|
285
295
|
file->buf_pos = 0;
|
|
286
296
|
file->fd = -1;
|
|
287
297
|
file->last_error = BUFERR_OK;
|
|
@@ -79,6 +79,7 @@ int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len);
|
|
|
79
79
|
int git_filebuf_printf(git_filebuf *file, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
|
|
80
80
|
|
|
81
81
|
int git_filebuf_open(git_filebuf *lock, const char *path, int flags, mode_t mode);
|
|
82
|
+
int git_filebuf_open_withsize(git_filebuf *file, const char *path, int flags, mode_t mode, size_t size);
|
|
82
83
|
int git_filebuf_commit(git_filebuf *lock);
|
|
83
84
|
int git_filebuf_commit_at(git_filebuf *lock, const char *path);
|
|
84
85
|
void git_filebuf_cleanup(git_filebuf *lock);
|
|
@@ -93,11 +93,24 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
|
|
|
93
93
|
* It will be restored if/when we recurse below.
|
|
94
94
|
*/
|
|
95
95
|
if (c == '*') {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
c = *++pattern;
|
|
97
|
+
/* star-star-slash is at the end, match by default */
|
|
98
|
+
if (c == EOS)
|
|
99
|
+
return 0;
|
|
100
|
+
/* Double-star must be at end or between slashes */
|
|
101
|
+
if (c != '/')
|
|
102
|
+
return (FNM_NOMATCH);
|
|
103
|
+
|
|
104
|
+
c = *++pattern;
|
|
105
|
+
do {
|
|
106
|
+
int e = p_fnmatchx(pattern, string, recurs_flags, recurs);
|
|
107
|
+
if (e != FNM_NOMATCH)
|
|
108
|
+
return e;
|
|
109
|
+
string = strchr(string, '/');
|
|
110
|
+
} while (string++);
|
|
111
|
+
|
|
112
|
+
/* If we get here, we didn't find a match */
|
|
113
|
+
return FNM_NOMATCH;
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
if (*string == '.' && (flags & FNM_PERIOD) &&
|
data/vendor/libgit2/src/global.c
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#include "hash.h"
|
|
10
10
|
#include "sysdir.h"
|
|
11
11
|
#include "filter.h"
|
|
12
|
+
#include "merge_driver.h"
|
|
12
13
|
#include "openssl_stream.h"
|
|
13
14
|
#include "thread-utils.h"
|
|
14
15
|
#include "git2/global.h"
|
|
@@ -27,6 +28,7 @@ static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
|
|
|
27
28
|
static git_atomic git__n_shutdown_callbacks;
|
|
28
29
|
static git_atomic git__n_inits;
|
|
29
30
|
char *git__user_agent;
|
|
31
|
+
char *git__ssl_ciphers;
|
|
30
32
|
|
|
31
33
|
void git__on_shutdown(git_global_shutdown_fn callback)
|
|
32
34
|
{
|
|
@@ -58,6 +60,7 @@ static int init_common(void)
|
|
|
58
60
|
if ((ret = git_hash_global_init()) == 0 &&
|
|
59
61
|
(ret = git_sysdir_global_init()) == 0 &&
|
|
60
62
|
(ret = git_filter_global_init()) == 0 &&
|
|
63
|
+
(ret = git_merge_driver_global_init()) == 0 &&
|
|
61
64
|
(ret = git_transport_ssh_global_init()) == 0)
|
|
62
65
|
ret = git_openssl_stream_global_init();
|
|
63
66
|
|
|
@@ -83,6 +86,7 @@ static void shutdown_common(void)
|
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
git__free(git__user_agent);
|
|
89
|
+
git__free(git__ssl_ciphers);
|
|
86
90
|
|
|
87
91
|
#if defined(GIT_MSVC_CRTDBG)
|
|
88
92
|
git_win32__crtdbg_stacktrace_cleanup();
|
|
@@ -222,6 +226,20 @@ void git__free_tls_data(void)
|
|
|
222
226
|
TlsSetValue(_tls_index, NULL);
|
|
223
227
|
}
|
|
224
228
|
|
|
229
|
+
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
|
|
230
|
+
{
|
|
231
|
+
/* This is how Windows lets us know our thread is being shut down */
|
|
232
|
+
if (fdwReason == DLL_THREAD_DETACH) {
|
|
233
|
+
git__free_tls_data();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/*
|
|
237
|
+
* Windows pays attention to this during library loading. We don't do anything
|
|
238
|
+
* so we trivially succeed.
|
|
239
|
+
*/
|
|
240
|
+
return TRUE;
|
|
241
|
+
}
|
|
242
|
+
|
|
225
243
|
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
|
|
226
244
|
|
|
227
245
|
static pthread_key_t _tls_key;
|
data/vendor/libgit2/src/global.h
CHANGED
data/vendor/libgit2/src/ignore.c
CHANGED
|
@@ -263,10 +263,18 @@ int git_ignore__for_path(
|
|
|
263
263
|
goto cleanup;
|
|
264
264
|
|
|
265
265
|
/* given a unrooted path in a non-bare repo, resolve it */
|
|
266
|
-
if (workdir && git_path_root(path) < 0)
|
|
267
|
-
|
|
268
|
-
|
|
266
|
+
if (workdir && git_path_root(path) < 0) {
|
|
267
|
+
git_buf local = GIT_BUF_INIT;
|
|
268
|
+
|
|
269
|
+
if ((error = git_path_dirname_r(&local, path)) < 0 ||
|
|
270
|
+
(error = git_path_resolve_relative(&local, 0)) < 0 ||
|
|
271
|
+
(error = git_path_to_dir(&local)) < 0 ||
|
|
272
|
+
(error = git_buf_joinpath(&ignores->dir, workdir, local.ptr)) < 0)
|
|
273
|
+
{;} /* Nothing, we just want to stop on the first error */
|
|
274
|
+
git_buf_free(&local);
|
|
275
|
+
} else {
|
|
269
276
|
error = git_buf_joinpath(&ignores->dir, path, "");
|
|
277
|
+
}
|
|
270
278
|
if (error < 0)
|
|
271
279
|
goto cleanup;
|
|
272
280
|
|
data/vendor/libgit2/src/index.c
CHANGED
|
@@ -963,14 +963,20 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
|
|
|
963
963
|
*reuc_out = reuc = reuc_entry_alloc(path);
|
|
964
964
|
GITERR_CHECK_ALLOC(reuc);
|
|
965
965
|
|
|
966
|
-
if ((reuc->mode[0] = ancestor_mode) > 0)
|
|
966
|
+
if ((reuc->mode[0] = ancestor_mode) > 0) {
|
|
967
|
+
assert(ancestor_oid);
|
|
967
968
|
git_oid_cpy(&reuc->oid[0], ancestor_oid);
|
|
969
|
+
}
|
|
968
970
|
|
|
969
|
-
if ((reuc->mode[1] = our_mode) > 0)
|
|
971
|
+
if ((reuc->mode[1] = our_mode) > 0) {
|
|
972
|
+
assert(our_oid);
|
|
970
973
|
git_oid_cpy(&reuc->oid[1], our_oid);
|
|
974
|
+
}
|
|
971
975
|
|
|
972
|
-
if ((reuc->mode[2] = their_mode) > 0)
|
|
976
|
+
if ((reuc->mode[2] = their_mode) > 0) {
|
|
977
|
+
assert(their_oid);
|
|
973
978
|
git_oid_cpy(&reuc->oid[2], their_oid);
|
|
979
|
+
}
|
|
974
980
|
|
|
975
981
|
return 0;
|
|
976
982
|
}
|
|
@@ -2830,7 +2836,7 @@ static int read_tree_cb(
|
|
|
2830
2836
|
return -1;
|
|
2831
2837
|
|
|
2832
2838
|
entry->mode = tentry->attr;
|
|
2833
|
-
entry->id
|
|
2839
|
+
git_oid_cpy(&entry->id, git_tree_entry_id(tentry));
|
|
2834
2840
|
|
|
2835
2841
|
/* look for corresponding old entry and copy data to new entry */
|
|
2836
2842
|
if (data->old_entries != NULL &&
|
|
@@ -3002,7 +3008,7 @@ int git_index_read_index(
|
|
|
3002
3008
|
|
|
3003
3009
|
if (error < 0) {
|
|
3004
3010
|
giterr_set(GITERR_INDEX, "failed to insert entry");
|
|
3005
|
-
|
|
3011
|
+
goto done;
|
|
3006
3012
|
}
|
|
3007
3013
|
|
|
3008
3014
|
if (diff <= 0) {
|
|
@@ -449,7 +449,7 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
|
|
|
449
449
|
static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t size)
|
|
450
450
|
{
|
|
451
451
|
git_file fd = idx->pack->mwf.fd;
|
|
452
|
-
size_t
|
|
452
|
+
size_t mmap_alignment;
|
|
453
453
|
size_t page_offset;
|
|
454
454
|
git_off_t page_start;
|
|
455
455
|
unsigned char *map_data;
|
|
@@ -458,11 +458,11 @@ static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t
|
|
|
458
458
|
|
|
459
459
|
assert(data && size);
|
|
460
460
|
|
|
461
|
-
if ((error =
|
|
461
|
+
if ((error = git__mmap_alignment(&mmap_alignment)) < 0)
|
|
462
462
|
return error;
|
|
463
463
|
|
|
464
|
-
/* the offset needs to be at the
|
|
465
|
-
page_offset = offset %
|
|
464
|
+
/* the offset needs to be at the mmap boundary for the platform */
|
|
465
|
+
page_offset = offset % mmap_alignment;
|
|
466
466
|
page_start = offset - page_offset;
|
|
467
467
|
|
|
468
468
|
if ((error = p_mmap(&map, page_offset + size, GIT_PROT_WRITE, GIT_MAP_SHARED, fd, page_start)) < 0)
|
|
@@ -777,7 +777,6 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats)
|
|
|
777
777
|
|
|
778
778
|
curpos = delta->delta_off;
|
|
779
779
|
error = git_packfile_unpack_header(&size, &type, &idx->pack->mwf, &w, &curpos);
|
|
780
|
-
git_mwindow_close(&w);
|
|
781
780
|
if (error < 0)
|
|
782
781
|
return error;
|
|
783
782
|
|
|
@@ -914,12 +913,17 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
|
|
|
914
913
|
git_filebuf index_file = {0};
|
|
915
914
|
void *packfile_trailer;
|
|
916
915
|
|
|
916
|
+
if (!idx->parsed_header) {
|
|
917
|
+
giterr_set(GITERR_INDEXER, "incomplete pack header");
|
|
918
|
+
return -1;
|
|
919
|
+
}
|
|
920
|
+
|
|
917
921
|
if (git_hash_ctx_init(&ctx) < 0)
|
|
918
922
|
return -1;
|
|
919
923
|
|
|
920
924
|
/* Test for this before resolve_deltas(), as it plays with idx->off */
|
|
921
|
-
if (idx->off < idx->pack->mwf.size
|
|
922
|
-
giterr_set(GITERR_INDEXER, "
|
|
925
|
+
if (idx->off + 20 < idx->pack->mwf.size) {
|
|
926
|
+
giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack");
|
|
923
927
|
return -1;
|
|
924
928
|
}
|
|
925
929
|
|
|
@@ -8,288 +8,372 @@
|
|
|
8
8
|
#include "iterator.h"
|
|
9
9
|
#include "tree.h"
|
|
10
10
|
#include "index.h"
|
|
11
|
-
#include "ignore.h"
|
|
12
|
-
#include "buffer.h"
|
|
13
|
-
#include "submodule.h"
|
|
14
|
-
#include <ctype.h>
|
|
15
|
-
|
|
16
|
-
#define ITERATOR_SET_CB(P,NAME_LC) do { \
|
|
17
|
-
(P)->cb.current = NAME_LC ## _iterator__current; \
|
|
18
|
-
(P)->cb.advance = NAME_LC ## _iterator__advance; \
|
|
19
|
-
(P)->cb.advance_into = NAME_LC ## _iterator__advance_into; \
|
|
20
|
-
(P)->cb.seek = NAME_LC ## _iterator__seek; \
|
|
21
|
-
(P)->cb.reset = NAME_LC ## _iterator__reset; \
|
|
22
|
-
(P)->cb.at_end = NAME_LC ## _iterator__at_end; \
|
|
23
|
-
(P)->cb.free = NAME_LC ## _iterator__free; \
|
|
24
|
-
} while (0)
|
|
25
|
-
|
|
26
|
-
#define ITERATOR_CASE_FLAGS \
|
|
27
|
-
(GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_IGNORE_CASE)
|
|
28
|
-
|
|
29
|
-
#define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC,REPO) do { \
|
|
30
|
-
(P)->base.type = GIT_ITERATOR_TYPE_ ## NAME_UC; \
|
|
31
|
-
(P)->base.cb = &(P)->cb; \
|
|
32
|
-
ITERATOR_SET_CB(P,NAME_LC); \
|
|
33
|
-
(P)->base.repo = (REPO); \
|
|
34
|
-
(P)->base.start = options && options->start ? \
|
|
35
|
-
git__strdup(options->start) : NULL; \
|
|
36
|
-
(P)->base.end = options && options->end ? \
|
|
37
|
-
git__strdup(options->end) : NULL; \
|
|
38
|
-
if ((options && options->start && !(P)->base.start) || \
|
|
39
|
-
(options && options->end && !(P)->base.end)) { \
|
|
40
|
-
git__free(P); return -1; } \
|
|
41
|
-
(P)->base.strcomp = git__strcmp; \
|
|
42
|
-
(P)->base.strncomp = git__strncmp; \
|
|
43
|
-
(P)->base.prefixcomp = git__prefixcmp; \
|
|
44
|
-
(P)->base.flags = options ? options->flags & ~ITERATOR_CASE_FLAGS : 0; \
|
|
45
|
-
if ((P)->base.flags & GIT_ITERATOR_DONT_AUTOEXPAND) \
|
|
46
|
-
(P)->base.flags |= GIT_ITERATOR_INCLUDE_TREES; \
|
|
47
|
-
if (options && options->pathlist.count && \
|
|
48
|
-
iterator_pathlist__init(&P->base, &options->pathlist) < 0) { \
|
|
49
|
-
git__free(P); return -1; } \
|
|
50
|
-
} while (0)
|
|
51
11
|
|
|
52
|
-
#define
|
|
53
|
-
#define
|
|
54
|
-
#define
|
|
55
|
-
#define iterator__dont_autoexpand(I) iterator__flag(I,DONT_AUTOEXPAND)
|
|
56
|
-
#define iterator__do_autoexpand(I) !iterator__flag(I,DONT_AUTOEXPAND)
|
|
57
|
-
#define iterator__include_conflicts(I) iterator__flag(I, INCLUDE_CONFLICTS)
|
|
12
|
+
#define GIT_ITERATOR_FIRST_ACCESS (1 << 15)
|
|
13
|
+
#define GIT_ITERATOR_HONOR_IGNORES (1 << 16)
|
|
14
|
+
#define GIT_ITERATOR_IGNORE_DOT_GIT (1 << 17)
|
|
58
15
|
|
|
59
|
-
#define
|
|
16
|
+
#define iterator__flag(I,F) ((((git_iterator *)(I))->flags & GIT_ITERATOR_ ## F) != 0)
|
|
17
|
+
#define iterator__ignore_case(I) iterator__flag(I,IGNORE_CASE)
|
|
18
|
+
#define iterator__include_trees(I) iterator__flag(I,INCLUDE_TREES)
|
|
19
|
+
#define iterator__dont_autoexpand(I) iterator__flag(I,DONT_AUTOEXPAND)
|
|
20
|
+
#define iterator__do_autoexpand(I) !iterator__flag(I,DONT_AUTOEXPAND)
|
|
21
|
+
#define iterator__include_conflicts(I) iterator__flag(I,INCLUDE_CONFLICTS)
|
|
60
22
|
#define iterator__has_been_accessed(I) iterator__flag(I,FIRST_ACCESS)
|
|
23
|
+
#define iterator__honor_ignores(I) iterator__flag(I,HONOR_IGNORES)
|
|
24
|
+
#define iterator__ignore_dot_git(I) iterator__flag(I,IGNORE_DOT_GIT)
|
|
61
25
|
|
|
62
|
-
#define iterator__end(I) ((git_iterator *)(I))->end
|
|
63
|
-
#define iterator__past_end(I,PATH) \
|
|
64
|
-
(iterator__end(I) && ((git_iterator *)(I))->prefixcomp((PATH),iterator__end(I)) > 0)
|
|
65
26
|
|
|
27
|
+
static void iterator_set_ignore_case(git_iterator *iter, bool ignore_case)
|
|
28
|
+
{
|
|
29
|
+
if (ignore_case)
|
|
30
|
+
iter->flags |= GIT_ITERATOR_IGNORE_CASE;
|
|
31
|
+
else
|
|
32
|
+
iter->flags &= ~GIT_ITERATOR_IGNORE_CASE;
|
|
33
|
+
|
|
34
|
+
iter->strcomp = ignore_case ? git__strcasecmp : git__strcmp;
|
|
35
|
+
iter->strncomp = ignore_case ? git__strncasecmp : git__strncmp;
|
|
36
|
+
iter->prefixcomp = ignore_case ? git__prefixcmp_icase : git__prefixcmp;
|
|
37
|
+
iter->entry_srch = ignore_case ? git_index_entry_isrch : git_index_entry_srch;
|
|
66
38
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
39
|
+
git_vector_set_cmp(&iter->pathlist, (git_vector_cmp)iter->strcomp);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static int iterator_range_init(
|
|
43
|
+
git_iterator *iter, const char *start, const char *end)
|
|
44
|
+
{
|
|
45
|
+
if (start && *start) {
|
|
46
|
+
iter->start = git__strdup(start);
|
|
47
|
+
GITERR_CHECK_ALLOC(iter->start);
|
|
48
|
+
|
|
49
|
+
iter->start_len = strlen(iter->start);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (end && *end) {
|
|
53
|
+
iter->end = git__strdup(end);
|
|
54
|
+
GITERR_CHECK_ALLOC(iter->end);
|
|
55
|
+
|
|
56
|
+
iter->end_len = strlen(iter->end);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
iter->started = (iter->start == NULL);
|
|
60
|
+
iter->ended = false;
|
|
61
|
+
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static void iterator_range_free(git_iterator *iter)
|
|
66
|
+
{
|
|
67
|
+
if (iter->start) {
|
|
68
|
+
git__free(iter->start);
|
|
69
|
+
iter->start = NULL;
|
|
70
|
+
iter->start_len = 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (iter->end) {
|
|
74
|
+
git__free(iter->end);
|
|
75
|
+
iter->end = NULL;
|
|
76
|
+
iter->end_len = 0;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static int iterator_reset_range(
|
|
81
|
+
git_iterator *iter, const char *start, const char *end)
|
|
82
|
+
{
|
|
83
|
+
iterator_range_free(iter);
|
|
84
|
+
return iterator_range_init(iter, start, end);
|
|
85
|
+
}
|
|
73
86
|
|
|
74
|
-
static int
|
|
87
|
+
static int iterator_pathlist_init(git_iterator *iter, git_strarray *pathlist)
|
|
75
88
|
{
|
|
76
89
|
size_t i;
|
|
77
90
|
|
|
78
|
-
if (git_vector_init(&iter->pathlist,
|
|
79
|
-
(git_vector_cmp)iter->strcomp) < 0)
|
|
91
|
+
if (git_vector_init(&iter->pathlist, pathlist->count, NULL) < 0)
|
|
80
92
|
return -1;
|
|
81
93
|
|
|
82
|
-
for (i = 0; i <
|
|
83
|
-
if (!
|
|
94
|
+
for (i = 0; i < pathlist->count; i++) {
|
|
95
|
+
if (!pathlist->strings[i])
|
|
84
96
|
continue;
|
|
85
97
|
|
|
86
|
-
if (git_vector_insert(&iter->pathlist,
|
|
98
|
+
if (git_vector_insert(&iter->pathlist, pathlist->strings[i]) < 0)
|
|
87
99
|
return -1;
|
|
88
100
|
}
|
|
89
101
|
|
|
90
|
-
git_vector_sort(&iter->pathlist);
|
|
91
|
-
|
|
92
102
|
return 0;
|
|
93
103
|
}
|
|
94
104
|
|
|
95
|
-
static
|
|
96
|
-
git_iterator *iter,
|
|
105
|
+
static int iterator_init_common(
|
|
106
|
+
git_iterator *iter,
|
|
107
|
+
git_repository *repo,
|
|
108
|
+
git_index *index,
|
|
109
|
+
git_iterator_options *given_opts)
|
|
97
110
|
{
|
|
98
|
-
|
|
99
|
-
|
|
111
|
+
static git_iterator_options default_opts = GIT_ITERATOR_OPTIONS_INIT;
|
|
112
|
+
git_iterator_options *options = given_opts ? given_opts : &default_opts;
|
|
113
|
+
bool ignore_case;
|
|
114
|
+
int precompose;
|
|
100
115
|
int error;
|
|
101
116
|
|
|
102
|
-
|
|
103
|
-
|
|
117
|
+
iter->repo = repo;
|
|
118
|
+
iter->index = index;
|
|
119
|
+
iter->flags = options->flags;
|
|
104
120
|
|
|
105
|
-
if (
|
|
106
|
-
|
|
121
|
+
if ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0) {
|
|
122
|
+
ignore_case = true;
|
|
123
|
+
} else if ((iter->flags & GIT_ITERATOR_DONT_IGNORE_CASE) != 0) {
|
|
124
|
+
ignore_case = false;
|
|
125
|
+
} else if (repo) {
|
|
126
|
+
git_index *index;
|
|
107
127
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
* so see if the pathlist contains a file beneath this directory.
|
|
111
|
-
*/
|
|
112
|
-
while ((p = git_vector_get(&iter->pathlist, idx)) != NULL) {
|
|
113
|
-
if (iter->prefixcomp(p, path) != 0)
|
|
114
|
-
break;
|
|
128
|
+
if ((error = git_repository_index__weakptr(&index, iter->repo)) < 0)
|
|
129
|
+
return error;
|
|
115
130
|
|
|
116
|
-
|
|
117
|
-
assert(p[path_len]);
|
|
131
|
+
ignore_case = !!index->ignore_case;
|
|
118
132
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
if (ignore_case == 1)
|
|
134
|
+
iter->flags |= GIT_ITERATOR_IGNORE_CASE;
|
|
135
|
+
else
|
|
136
|
+
iter->flags |= GIT_ITERATOR_DONT_IGNORE_CASE;
|
|
137
|
+
} else {
|
|
138
|
+
ignore_case = false;
|
|
139
|
+
}
|
|
125
140
|
|
|
126
|
-
|
|
127
|
-
|
|
141
|
+
/* try to look up precompose and set flag if appropriate */
|
|
142
|
+
if (repo &&
|
|
143
|
+
(iter->flags & GIT_ITERATOR_PRECOMPOSE_UNICODE) == 0 &&
|
|
144
|
+
(iter->flags & GIT_ITERATOR_DONT_PRECOMPOSE_UNICODE) == 0) {
|
|
128
145
|
|
|
129
|
-
|
|
146
|
+
if (git_repository__cvar(&precompose, repo, GIT_CVAR_PRECOMPOSE) < 0)
|
|
147
|
+
giterr_clear();
|
|
148
|
+
else if (precompose)
|
|
149
|
+
iter->flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
|
|
130
150
|
}
|
|
131
151
|
|
|
132
|
-
|
|
152
|
+
if ((iter->flags & GIT_ITERATOR_DONT_AUTOEXPAND))
|
|
153
|
+
iter->flags |= GIT_ITERATOR_INCLUDE_TREES;
|
|
154
|
+
|
|
155
|
+
if ((error = iterator_range_init(iter, options->start, options->end)) < 0 ||
|
|
156
|
+
(error = iterator_pathlist_init(iter, &options->pathlist)) < 0)
|
|
157
|
+
return error;
|
|
158
|
+
|
|
159
|
+
iterator_set_ignore_case(iter, ignore_case);
|
|
160
|
+
return 0;
|
|
133
161
|
}
|
|
134
162
|
|
|
135
|
-
static void
|
|
163
|
+
static void iterator_clear(git_iterator *iter)
|
|
136
164
|
{
|
|
165
|
+
iter->started = false;
|
|
166
|
+
iter->ended = false;
|
|
167
|
+
iter->stat_calls = 0;
|
|
137
168
|
iter->pathlist_walk_idx = 0;
|
|
169
|
+
iter->flags &= ~GIT_ITERATOR_FIRST_ACCESS;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
GIT_INLINE(bool) iterator_has_started(
|
|
173
|
+
git_iterator *iter, const char *path, bool is_submodule)
|
|
174
|
+
{
|
|
175
|
+
size_t path_len;
|
|
176
|
+
|
|
177
|
+
if (iter->start == NULL || iter->started == true)
|
|
178
|
+
return true;
|
|
179
|
+
|
|
180
|
+
/* the starting path is generally a prefix - we have started once we
|
|
181
|
+
* are prefixed by this path
|
|
182
|
+
*/
|
|
183
|
+
iter->started = (iter->prefixcomp(path, iter->start) >= 0);
|
|
184
|
+
|
|
185
|
+
if (iter->started)
|
|
186
|
+
return true;
|
|
187
|
+
|
|
188
|
+
path_len = strlen(path);
|
|
189
|
+
|
|
190
|
+
/* if, however, we are a submodule, then we support `start` being
|
|
191
|
+
* suffixed with a `/` for crazy legacy reasons. match `submod`
|
|
192
|
+
* with a start path of `submod/`.
|
|
193
|
+
*/
|
|
194
|
+
if (is_submodule && iter->start_len && path_len == iter->start_len - 1 &&
|
|
195
|
+
iter->start[iter->start_len-1] == '/')
|
|
196
|
+
return true;
|
|
197
|
+
|
|
198
|
+
/* if, however, our current path is a directory, and our starting path
|
|
199
|
+
* is _beneath_ that directory, then recurse into the directory (even
|
|
200
|
+
* though we have not yet "started")
|
|
201
|
+
*/
|
|
202
|
+
if (path_len > 0 && path[path_len-1] == '/' &&
|
|
203
|
+
iter->strncomp(path, iter->start, path_len) == 0)
|
|
204
|
+
return true;
|
|
205
|
+
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
GIT_INLINE(bool) iterator_has_ended(git_iterator *iter, const char *path)
|
|
210
|
+
{
|
|
211
|
+
if (iter->end == NULL)
|
|
212
|
+
return false;
|
|
213
|
+
else if (iter->ended)
|
|
214
|
+
return true;
|
|
215
|
+
|
|
216
|
+
iter->ended = (iter->prefixcomp(path, iter->end) > 0);
|
|
217
|
+
return iter->ended;
|
|
138
218
|
}
|
|
139
219
|
|
|
140
|
-
/* walker for the index iterator that allows it to walk the sorted
|
|
141
|
-
* entries alongside
|
|
142
|
-
* stores the starting position for subsequent calls, the position is advanced
|
|
143
|
-
* along with the index iterator, with a special case for handling directories
|
|
144
|
-
* in the pathlist that are specified without trailing '/'. (eg, `foo`).
|
|
145
|
-
* we do not advance over these entries until we're certain that the index
|
|
146
|
-
* iterator will not ask us for a file beneath that directory (eg, `foo/bar`).
|
|
220
|
+
/* walker for the index and tree iterator that allows it to walk the sorted
|
|
221
|
+
* pathlist entries alongside sorted iterator entries.
|
|
147
222
|
*/
|
|
148
|
-
static bool
|
|
223
|
+
static bool iterator_pathlist_next_is(git_iterator *iter, const char *path)
|
|
149
224
|
{
|
|
150
|
-
size_t i;
|
|
151
225
|
char *p;
|
|
152
|
-
size_t p_len;
|
|
226
|
+
size_t path_len, p_len, cmp_len, i;
|
|
153
227
|
int cmp;
|
|
154
228
|
|
|
229
|
+
if (iter->pathlist.length == 0)
|
|
230
|
+
return true;
|
|
231
|
+
|
|
232
|
+
git_vector_sort(&iter->pathlist);
|
|
233
|
+
|
|
234
|
+
path_len = strlen(path);
|
|
235
|
+
|
|
236
|
+
/* for comparison, drop the trailing slash on the current '/' */
|
|
237
|
+
if (path_len && path[path_len-1] == '/')
|
|
238
|
+
path_len--;
|
|
239
|
+
|
|
155
240
|
for (i = iter->pathlist_walk_idx; i < iter->pathlist.length; i++) {
|
|
156
241
|
p = iter->pathlist.contents[i];
|
|
157
242
|
p_len = strlen(p);
|
|
158
243
|
|
|
244
|
+
if (p_len && p[p_len-1] == '/')
|
|
245
|
+
p_len--;
|
|
246
|
+
|
|
247
|
+
cmp_len = min(path_len, p_len);
|
|
248
|
+
|
|
159
249
|
/* see if the pathlist entry is a prefix of this path */
|
|
160
|
-
cmp = iter->strncomp(p, path,
|
|
250
|
+
cmp = iter->strncomp(p, path, cmp_len);
|
|
251
|
+
|
|
252
|
+
/* prefix match - see if there's an exact match, or if we were
|
|
253
|
+
* given a path that matches the directory
|
|
254
|
+
*/
|
|
255
|
+
if (cmp == 0) {
|
|
256
|
+
/* if this pathlist entry is not suffixed with a '/' then
|
|
257
|
+
* it matches a path that is a file or a directory.
|
|
258
|
+
* (eg, pathlist = "foo" and path is "foo" or "foo/" or
|
|
259
|
+
* "foo/something")
|
|
260
|
+
*/
|
|
261
|
+
if (p[cmp_len] == '\0' &&
|
|
262
|
+
(path[cmp_len] == '\0' || path[cmp_len] == '/'))
|
|
263
|
+
return true;
|
|
264
|
+
|
|
265
|
+
/* if this pathlist entry _is_ suffixed with a '/' then
|
|
266
|
+
* it matches only paths that are directories.
|
|
267
|
+
* (eg, pathlist = "foo/" and path is "foo/" or "foo/something")
|
|
268
|
+
*/
|
|
269
|
+
if (p[cmp_len] == '/' && path[cmp_len] == '/')
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
161
272
|
|
|
162
273
|
/* this pathlist entry sorts before the given path, try the next */
|
|
163
|
-
if (
|
|
274
|
+
else if (cmp < 0) {
|
|
164
275
|
iter->pathlist_walk_idx++;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
165
278
|
|
|
166
279
|
/* this pathlist sorts after the given path, no match. */
|
|
167
|
-
else if (cmp > 0)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
/* match! an exact match (`foo` vs `foo`), the path is a child of an
|
|
171
|
-
* explicit directory in the pathlist (`foo/` vs `foo/bar`) or the path
|
|
172
|
-
* is a child of an entry in the pathlist (`foo` vs `foo/bar`)
|
|
173
|
-
*/
|
|
174
|
-
else if (path[p_len] == '\0' || p[p_len - 1] == '/' || path[p_len] == '/')
|
|
175
|
-
return true;
|
|
176
|
-
|
|
177
|
-
/* only advance the start index for future callers if we know that we
|
|
178
|
-
* will not see a child of this path. eg, a pathlist entry `foo` is
|
|
179
|
-
* a prefix for `foo.txt` and `foo/bar`. don't advance the start
|
|
180
|
-
* pathlist index when we see `foo.txt` or we would miss a subsequent
|
|
181
|
-
* inspection of `foo/bar`. only advance when there are no more
|
|
182
|
-
* potential children.
|
|
183
|
-
*/
|
|
184
|
-
else if (path[p_len] > '/')
|
|
185
|
-
iter->pathlist_walk_idx++;
|
|
280
|
+
else if (cmp > 0) {
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
186
283
|
}
|
|
187
284
|
|
|
188
285
|
return false;
|
|
189
286
|
}
|
|
190
287
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
288
|
+
typedef enum {
|
|
289
|
+
ITERATOR_PATHLIST_NONE = 0,
|
|
290
|
+
ITERATOR_PATHLIST_IS_FILE = 1,
|
|
291
|
+
ITERATOR_PATHLIST_IS_DIR = 2,
|
|
292
|
+
ITERATOR_PATHLIST_IS_PARENT = 3,
|
|
293
|
+
ITERATOR_PATHLIST_FULL = 4,
|
|
294
|
+
} iterator_pathlist_search_t;
|
|
199
295
|
|
|
200
|
-
static
|
|
201
|
-
git_iterator *iter, const char *
|
|
296
|
+
static iterator_pathlist_search_t iterator_pathlist_search(
|
|
297
|
+
git_iterator *iter, const char *path, size_t path_len)
|
|
202
298
|
{
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
iter->start = git__strdup(start);
|
|
207
|
-
GITERR_CHECK_ALLOC(iter->start);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (end) {
|
|
211
|
-
if (iter->end)
|
|
212
|
-
git__free(iter->end);
|
|
213
|
-
iter->end = git__strdup(end);
|
|
214
|
-
GITERR_CHECK_ALLOC(iter->end);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
iter->flags &= ~GIT_ITERATOR_FIRST_ACCESS;
|
|
299
|
+
const char *p;
|
|
300
|
+
size_t idx;
|
|
301
|
+
int error;
|
|
218
302
|
|
|
219
|
-
|
|
220
|
-
|
|
303
|
+
if (iter->pathlist.length == 0)
|
|
304
|
+
return ITERATOR_PATHLIST_FULL;
|
|
221
305
|
|
|
222
|
-
|
|
223
|
-
git_iterator *iter,
|
|
224
|
-
git_iterator_flag_t flags)
|
|
225
|
-
{
|
|
226
|
-
bool ignore_case;
|
|
227
|
-
int error;
|
|
306
|
+
git_vector_sort(&iter->pathlist);
|
|
228
307
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
else if ((flags & GIT_ITERATOR_DONT_IGNORE_CASE) != 0)
|
|
232
|
-
ignore_case = false;
|
|
233
|
-
else {
|
|
234
|
-
git_index *index;
|
|
308
|
+
error = git_vector_bsearch2(&idx, &iter->pathlist,
|
|
309
|
+
(git_vector_cmp)iter->strcomp, path);
|
|
235
310
|
|
|
236
|
-
|
|
237
|
-
|
|
311
|
+
/* the given path was found in the pathlist. since the pathlist only
|
|
312
|
+
* matches directories when they're suffixed with a '/', analyze the
|
|
313
|
+
* path string to determine whether it's a directory or not.
|
|
314
|
+
*/
|
|
315
|
+
if (error == 0) {
|
|
316
|
+
if (path_len && path[path_len-1] == '/')
|
|
317
|
+
return ITERATOR_PATHLIST_IS_DIR;
|
|
238
318
|
|
|
239
|
-
|
|
319
|
+
return ITERATOR_PATHLIST_IS_FILE;
|
|
240
320
|
}
|
|
241
321
|
|
|
242
|
-
|
|
243
|
-
|
|
322
|
+
/* at this point, the path we're examining may be a directory (though we
|
|
323
|
+
* don't know that yet, since we're avoiding a stat unless it's necessary)
|
|
324
|
+
* so walk the pathlist looking for the given path with a '/' after it,
|
|
325
|
+
*/
|
|
326
|
+
while ((p = git_vector_get(&iter->pathlist, idx)) != NULL) {
|
|
327
|
+
if (iter->prefixcomp(p, path) != 0)
|
|
328
|
+
break;
|
|
244
329
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
iter->prefixcomp = git__prefixcmp_icase;
|
|
248
|
-
} else {
|
|
249
|
-
iter->flags = (iter->flags & ~GIT_ITERATOR_IGNORE_CASE);
|
|
330
|
+
/* an exact match would have been matched by the bsearch above */
|
|
331
|
+
assert(p[path_len]);
|
|
250
332
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
333
|
+
/* is this a literal directory entry (eg `foo/`) or a file beneath */
|
|
334
|
+
if (p[path_len] == '/') {
|
|
335
|
+
return (p[path_len+1] == '\0') ?
|
|
336
|
+
ITERATOR_PATHLIST_IS_DIR :
|
|
337
|
+
ITERATOR_PATHLIST_IS_PARENT;
|
|
338
|
+
}
|
|
255
339
|
|
|
256
|
-
|
|
340
|
+
if (p[path_len] > '/')
|
|
341
|
+
break;
|
|
257
342
|
|
|
258
|
-
|
|
259
|
-
}
|
|
343
|
+
idx++;
|
|
344
|
+
}
|
|
260
345
|
|
|
261
|
-
|
|
262
|
-
{
|
|
263
|
-
if (entry) *entry = NULL;
|
|
346
|
+
return ITERATOR_PATHLIST_NONE;
|
|
264
347
|
}
|
|
265
348
|
|
|
349
|
+
/* Empty iterator */
|
|
266
350
|
|
|
267
|
-
static int
|
|
351
|
+
static int empty_iterator_noop(const git_index_entry **e, git_iterator *i)
|
|
268
352
|
{
|
|
269
353
|
GIT_UNUSED(i);
|
|
270
|
-
iterator__clear_entry(e);
|
|
271
|
-
return GIT_ITEROVER;
|
|
272
|
-
}
|
|
273
354
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
return
|
|
355
|
+
if (e)
|
|
356
|
+
*e = NULL;
|
|
357
|
+
|
|
358
|
+
return GIT_ITEROVER;
|
|
278
359
|
}
|
|
279
360
|
|
|
280
|
-
static int
|
|
361
|
+
static int empty_iterator_advance_over(
|
|
362
|
+
const git_index_entry **e,
|
|
363
|
+
git_iterator_status_t *s,
|
|
364
|
+
git_iterator *i)
|
|
281
365
|
{
|
|
282
|
-
|
|
283
|
-
return
|
|
366
|
+
*s = GIT_ITERATOR_STATUS_EMPTY;
|
|
367
|
+
return empty_iterator_noop(e, i);
|
|
284
368
|
}
|
|
285
369
|
|
|
286
|
-
static int
|
|
370
|
+
static int empty_iterator_reset(git_iterator *i)
|
|
287
371
|
{
|
|
288
372
|
GIT_UNUSED(i);
|
|
289
|
-
return
|
|
373
|
+
return 0;
|
|
290
374
|
}
|
|
291
375
|
|
|
292
|
-
static void
|
|
376
|
+
static void empty_iterator_free(git_iterator *i)
|
|
293
377
|
{
|
|
294
378
|
GIT_UNUSED(i);
|
|
295
379
|
}
|
|
@@ -300,1516 +384,1512 @@ typedef struct {
|
|
|
300
384
|
} empty_iterator;
|
|
301
385
|
|
|
302
386
|
int git_iterator_for_nothing(
|
|
303
|
-
git_iterator **
|
|
387
|
+
git_iterator **out,
|
|
304
388
|
git_iterator_options *options)
|
|
305
389
|
{
|
|
306
|
-
empty_iterator *
|
|
307
|
-
GITERR_CHECK_ALLOC(i);
|
|
390
|
+
empty_iterator *iter;
|
|
308
391
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
392
|
+
static git_iterator_callbacks callbacks = {
|
|
393
|
+
empty_iterator_noop,
|
|
394
|
+
empty_iterator_noop,
|
|
395
|
+
empty_iterator_noop,
|
|
396
|
+
empty_iterator_advance_over,
|
|
397
|
+
empty_iterator_reset,
|
|
398
|
+
empty_iterator_free
|
|
399
|
+
};
|
|
312
400
|
|
|
313
|
-
|
|
401
|
+
*out = NULL;
|
|
314
402
|
|
|
315
|
-
|
|
316
|
-
|
|
403
|
+
iter = git__calloc(1, sizeof(empty_iterator));
|
|
404
|
+
GITERR_CHECK_ALLOC(iter);
|
|
317
405
|
|
|
318
|
-
|
|
406
|
+
iter->base.type = GIT_ITERATOR_TYPE_EMPTY;
|
|
407
|
+
iter->base.cb = &callbacks;
|
|
408
|
+
iter->base.flags = options->flags;
|
|
409
|
+
|
|
410
|
+
*out = &iter->base;
|
|
319
411
|
return 0;
|
|
320
412
|
}
|
|
321
413
|
|
|
414
|
+
/* Tree iterator */
|
|
415
|
+
|
|
416
|
+
typedef struct {
|
|
417
|
+
git_tree_entry *tree_entry;
|
|
418
|
+
const char *parent_path;
|
|
419
|
+
} tree_iterator_entry;
|
|
322
420
|
|
|
323
|
-
typedef struct
|
|
324
|
-
struct tree_iterator_entry {
|
|
325
|
-
tree_iterator_entry *parent;
|
|
326
|
-
const git_tree_entry *te;
|
|
421
|
+
typedef struct {
|
|
327
422
|
git_tree *tree;
|
|
328
|
-
};
|
|
329
423
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
tree_iterator_frame *up, *down;
|
|
424
|
+
/* path to this particular frame (folder) */
|
|
425
|
+
git_buf path;
|
|
333
426
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
427
|
+
/* a sorted list of the entries for this frame (folder), these are
|
|
428
|
+
* actually pointers to the iterator's entry pool.
|
|
429
|
+
*/
|
|
430
|
+
git_vector entries;
|
|
431
|
+
tree_iterator_entry *current;
|
|
337
432
|
|
|
338
|
-
|
|
339
|
-
size_t startlen;
|
|
433
|
+
size_t next_idx;
|
|
340
434
|
|
|
341
|
-
|
|
342
|
-
|
|
435
|
+
/* on case insensitive iterations, we also have an array of other
|
|
436
|
+
* paths that were case insensitively equal to this one, and their
|
|
437
|
+
* tree objects. we have coalesced the tree entries into this frame.
|
|
438
|
+
* a child `tree_iterator_entry` will contain a pointer to its actual
|
|
439
|
+
* parent path.
|
|
440
|
+
*/
|
|
441
|
+
git_vector similar_trees;
|
|
442
|
+
git_array_t(git_buf) similar_paths;
|
|
443
|
+
} tree_iterator_frame;
|
|
343
444
|
|
|
344
445
|
typedef struct {
|
|
345
446
|
git_iterator base;
|
|
346
|
-
|
|
347
|
-
tree_iterator_frame
|
|
348
|
-
|
|
447
|
+
git_tree *root;
|
|
448
|
+
git_array_t(tree_iterator_frame) frames;
|
|
449
|
+
|
|
349
450
|
git_index_entry entry;
|
|
350
|
-
git_buf
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
451
|
+
git_buf entry_path;
|
|
452
|
+
|
|
453
|
+
/* a pool of entries to reduce the number of allocations */
|
|
454
|
+
git_pool entry_pool;
|
|
354
455
|
} tree_iterator;
|
|
355
456
|
|
|
356
|
-
|
|
357
|
-
tree_iterator *
|
|
457
|
+
GIT_INLINE(tree_iterator_frame *) tree_iterator_parent_frame(
|
|
458
|
+
tree_iterator *iter)
|
|
358
459
|
{
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return NULL;
|
|
362
|
-
|
|
363
|
-
if (git_tree_entry__is_tree(te) && git_buf_putc(&ti->path, '/') < 0)
|
|
364
|
-
return NULL;
|
|
365
|
-
|
|
366
|
-
ti->path_has_filename = true;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
return ti->path.ptr;
|
|
460
|
+
return iter->frames.size > 1 ?
|
|
461
|
+
&iter->frames.ptr[iter->frames.size-2] : NULL;
|
|
370
462
|
}
|
|
371
463
|
|
|
372
|
-
|
|
464
|
+
GIT_INLINE(tree_iterator_frame *) tree_iterator_current_frame(
|
|
465
|
+
tree_iterator *iter)
|
|
373
466
|
{
|
|
374
|
-
|
|
375
|
-
ssize_t strpos = ti->path.size;
|
|
376
|
-
const git_tree_entry *te;
|
|
377
|
-
|
|
378
|
-
if (strpos && ti->path.ptr[strpos - 1] == '/')
|
|
379
|
-
strpos--;
|
|
380
|
-
|
|
381
|
-
for (; scan && (te = scan->te); scan = scan->parent) {
|
|
382
|
-
strpos -= te->filename_len;
|
|
383
|
-
memcpy(&ti->path.ptr[strpos], te->filename, te->filename_len);
|
|
384
|
-
strpos -= 1; /* separator */
|
|
385
|
-
}
|
|
467
|
+
return iter->frames.size ? &iter->frames.ptr[iter->frames.size-1] : NULL;
|
|
386
468
|
}
|
|
387
469
|
|
|
388
|
-
|
|
389
|
-
const git_tree_entry *a,
|
|
390
|
-
const git_tree_entry *b,
|
|
391
|
-
int (*compare)(const char *, const char *, size_t))
|
|
470
|
+
GIT_INLINE(int) tree_entry_cmp(
|
|
471
|
+
const git_tree_entry *a, const git_tree_entry *b, bool icase)
|
|
392
472
|
{
|
|
393
473
|
return git_path_cmp(
|
|
394
474
|
a->filename, a->filename_len, a->attr == GIT_FILEMODE_TREE,
|
|
395
475
|
b->filename, b->filename_len, b->attr == GIT_FILEMODE_TREE,
|
|
396
|
-
|
|
476
|
+
icase ? git__strncasecmp : git__strncmp);
|
|
397
477
|
}
|
|
398
478
|
|
|
399
|
-
|
|
479
|
+
GIT_INLINE(int) tree_iterator_entry_cmp(const void *ptr_a, const void *ptr_b)
|
|
400
480
|
{
|
|
401
|
-
const tree_iterator_entry *
|
|
402
|
-
|
|
481
|
+
const tree_iterator_entry *a = (const tree_iterator_entry *)ptr_a;
|
|
482
|
+
const tree_iterator_entry *b = (const tree_iterator_entry *)ptr_b;
|
|
403
483
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if (!ae->parent->te || !be->parent->te)
|
|
407
|
-
cmp = tree_iterator__te_cmp(ae->te, be->te, git__strncmp);
|
|
408
|
-
else
|
|
409
|
-
cmp = tree_iterator__ci_cmp(ae->parent, be->parent, p);
|
|
410
|
-
}
|
|
484
|
+
return tree_entry_cmp(a->tree_entry, b->tree_entry, false);
|
|
485
|
+
}
|
|
411
486
|
|
|
412
|
-
|
|
487
|
+
GIT_INLINE(int) tree_iterator_entry_cmp_icase(
|
|
488
|
+
const void *ptr_a, const void *ptr_b)
|
|
489
|
+
{
|
|
490
|
+
const tree_iterator_entry *a = (const tree_iterator_entry *)ptr_a;
|
|
491
|
+
const tree_iterator_entry *b = (const tree_iterator_entry *)ptr_b;
|
|
492
|
+
|
|
493
|
+
return tree_entry_cmp(a->tree_entry, b->tree_entry, true);
|
|
413
494
|
}
|
|
414
495
|
|
|
415
|
-
static int
|
|
496
|
+
static int tree_iterator_entry_sort_icase(const void *ptr_a, const void *ptr_b)
|
|
416
497
|
{
|
|
417
|
-
const
|
|
418
|
-
const
|
|
498
|
+
const tree_iterator_entry *a = (const tree_iterator_entry *)ptr_a;
|
|
499
|
+
const tree_iterator_entry *b = (const tree_iterator_entry *)ptr_b;
|
|
419
500
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
501
|
+
int c = tree_entry_cmp(a->tree_entry, b->tree_entry, true);
|
|
502
|
+
|
|
503
|
+
/* stabilize the sort order for filenames that are (case insensitively)
|
|
504
|
+
* the same by examining the parent path (case sensitively) before
|
|
505
|
+
* falling back to a case sensitive sort of the filename.
|
|
506
|
+
*/
|
|
507
|
+
if (!c && a->parent_path != b->parent_path)
|
|
508
|
+
c = git__strcmp(a->parent_path, b->parent_path);
|
|
509
|
+
|
|
510
|
+
if (!c)
|
|
511
|
+
c = tree_entry_cmp(a->tree_entry, b->tree_entry, false);
|
|
512
|
+
|
|
513
|
+
return c;
|
|
424
514
|
}
|
|
425
515
|
|
|
426
|
-
static
|
|
427
|
-
|
|
516
|
+
static int tree_iterator_compute_path(
|
|
517
|
+
git_buf *out,
|
|
518
|
+
tree_iterator_entry *entry)
|
|
428
519
|
{
|
|
429
|
-
|
|
430
|
-
ti->path_ambiguities--;
|
|
520
|
+
git_buf_clear(out);
|
|
431
521
|
|
|
432
|
-
if (
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
522
|
+
if (entry->parent_path)
|
|
523
|
+
git_buf_joinpath(out, entry->parent_path, entry->tree_entry->filename);
|
|
524
|
+
else
|
|
525
|
+
git_buf_puts(out, entry->tree_entry->filename);
|
|
436
526
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
527
|
+
if (git_tree_entry__is_tree(entry->tree_entry))
|
|
528
|
+
git_buf_putc(out, '/');
|
|
529
|
+
|
|
530
|
+
if (git_buf_oom(out))
|
|
531
|
+
return -1;
|
|
441
532
|
|
|
442
|
-
return
|
|
533
|
+
return 0;
|
|
443
534
|
}
|
|
444
535
|
|
|
445
|
-
static int
|
|
536
|
+
static int tree_iterator_frame_init(
|
|
537
|
+
tree_iterator *iter,
|
|
538
|
+
git_tree *tree,
|
|
539
|
+
tree_iterator_entry *frame_entry)
|
|
446
540
|
{
|
|
541
|
+
tree_iterator_frame *new_frame = NULL;
|
|
542
|
+
tree_iterator_entry *new_entry;
|
|
543
|
+
git_tree *dup = NULL;
|
|
544
|
+
git_tree_entry *tree_entry;
|
|
545
|
+
git_vector_cmp cmp;
|
|
546
|
+
size_t i;
|
|
447
547
|
int error = 0;
|
|
448
|
-
const git_tree_entry *te, *last = NULL;
|
|
449
548
|
|
|
450
|
-
|
|
549
|
+
new_frame = git_array_alloc(iter->frames);
|
|
550
|
+
GITERR_CHECK_ALLOC(new_frame);
|
|
451
551
|
|
|
452
|
-
|
|
453
|
-
te = tf->entries[tf->next]->te;
|
|
552
|
+
memset(new_frame, 0, sizeof(tree_iterator_frame));
|
|
454
553
|
|
|
455
|
-
|
|
456
|
-
|
|
554
|
+
if ((error = git_tree_dup(&dup, tree)) < 0)
|
|
555
|
+
goto done;
|
|
556
|
+
|
|
557
|
+
memset(new_frame, 0x0, sizeof(tree_iterator_frame));
|
|
558
|
+
new_frame->tree = dup;
|
|
559
|
+
|
|
560
|
+
if (frame_entry &&
|
|
561
|
+
(error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0)
|
|
562
|
+
goto done;
|
|
563
|
+
|
|
564
|
+
cmp = iterator__ignore_case(&iter->base) ?
|
|
565
|
+
tree_iterator_entry_sort_icase : NULL;
|
|
566
|
+
|
|
567
|
+
if ((error = git_vector_init(
|
|
568
|
+
&new_frame->entries, dup->entries.size, cmp)) < 0)
|
|
569
|
+
goto done;
|
|
457
570
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
571
|
+
git_array_foreach(dup->entries, i, tree_entry) {
|
|
572
|
+
new_entry = git_pool_malloc(&iter->entry_pool, 1);
|
|
573
|
+
GITERR_CHECK_ALLOC(new_entry);
|
|
574
|
+
|
|
575
|
+
new_entry->tree_entry = tree_entry;
|
|
576
|
+
new_entry->parent_path = new_frame->path.ptr;
|
|
577
|
+
|
|
578
|
+
if ((error = git_vector_insert(&new_frame->entries, new_entry)) < 0)
|
|
579
|
+
goto done;
|
|
462
580
|
}
|
|
463
581
|
|
|
464
|
-
|
|
465
|
-
|
|
582
|
+
git_vector_set_sorted(&new_frame->entries,
|
|
583
|
+
!iterator__ignore_case(&iter->base));
|
|
466
584
|
|
|
467
|
-
|
|
585
|
+
done:
|
|
468
586
|
if (error < 0) {
|
|
469
|
-
|
|
470
|
-
|
|
587
|
+
git_tree_free(dup);
|
|
588
|
+
git_array_pop(iter->frames);
|
|
471
589
|
}
|
|
472
590
|
|
|
473
|
-
|
|
474
|
-
return -1; /* must have been allocation failure */
|
|
475
|
-
|
|
476
|
-
return 0;
|
|
591
|
+
return error;
|
|
477
592
|
}
|
|
478
593
|
|
|
479
|
-
GIT_INLINE(
|
|
594
|
+
GIT_INLINE(tree_iterator_entry *) tree_iterator_current_entry(
|
|
595
|
+
tree_iterator_frame *frame)
|
|
480
596
|
{
|
|
481
|
-
return
|
|
482
|
-
ti->head->entries[ti->head->current]->tree != NULL);
|
|
597
|
+
return frame->current;
|
|
483
598
|
}
|
|
484
599
|
|
|
485
|
-
|
|
600
|
+
GIT_INLINE(int) tree_iterator_frame_push_neighbors(
|
|
601
|
+
tree_iterator *iter,
|
|
602
|
+
tree_iterator_frame *parent_frame,
|
|
603
|
+
tree_iterator_frame *frame,
|
|
604
|
+
const char *filename)
|
|
486
605
|
{
|
|
606
|
+
tree_iterator_entry *entry, *new_entry;
|
|
607
|
+
git_tree *tree = NULL;
|
|
608
|
+
git_tree_entry *tree_entry;
|
|
609
|
+
git_buf *path;
|
|
610
|
+
size_t new_size, i;
|
|
487
611
|
int error = 0;
|
|
488
|
-
tree_iterator_frame *head = ti->head, *tf = NULL;
|
|
489
|
-
size_t i, n_entries = 0, alloclen;
|
|
490
612
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
for (i = head->current; i < head->next; ++i)
|
|
495
|
-
n_entries += git_tree_entrycount(head->entries[i]->tree);
|
|
613
|
+
while (parent_frame->next_idx < parent_frame->entries.length) {
|
|
614
|
+
entry = parent_frame->entries.contents[parent_frame->next_idx];
|
|
496
615
|
|
|
497
|
-
|
|
498
|
-
|
|
616
|
+
if (strcasecmp(filename, entry->tree_entry->filename) != 0)
|
|
617
|
+
break;
|
|
499
618
|
|
|
500
|
-
|
|
501
|
-
|
|
619
|
+
if ((error = git_tree_lookup(&tree,
|
|
620
|
+
iter->base.repo, entry->tree_entry->oid)) < 0)
|
|
621
|
+
break;
|
|
502
622
|
|
|
503
|
-
|
|
623
|
+
if (git_vector_insert(&parent_frame->similar_trees, tree) < 0)
|
|
624
|
+
break;
|
|
504
625
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
ti->head = tf;
|
|
626
|
+
path = git_array_alloc(parent_frame->similar_paths);
|
|
627
|
+
GITERR_CHECK_ALLOC(path);
|
|
508
628
|
|
|
509
|
-
|
|
510
|
-
git_tree *tree = head->entries[i]->tree;
|
|
511
|
-
size_t j, max_j = git_tree_entrycount(tree);
|
|
629
|
+
memset(path, 0, sizeof(git_buf));
|
|
512
630
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
GITERR_CHECK_ALLOC(entry);
|
|
631
|
+
if ((error = tree_iterator_compute_path(path, entry)) < 0)
|
|
632
|
+
break;
|
|
516
633
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
634
|
+
GITERR_CHECK_ALLOC_ADD(&new_size,
|
|
635
|
+
frame->entries.length, tree->entries.size);
|
|
636
|
+
git_vector_size_hint(&frame->entries, new_size);
|
|
520
637
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
638
|
+
git_array_foreach(tree->entries, i, tree_entry) {
|
|
639
|
+
new_entry = git_pool_malloc(&iter->entry_pool, 1);
|
|
640
|
+
GITERR_CHECK_ALLOC(new_entry);
|
|
524
641
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
git__tsort_r(
|
|
528
|
-
(void **)tf->entries, tf->n_entries, tree_iterator__ci_cmp, tf);
|
|
642
|
+
new_entry->tree_entry = tree_entry;
|
|
643
|
+
new_entry->parent_path = path->ptr;
|
|
529
644
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
tree_iterator__search_cmp, ti, &tf->current);
|
|
645
|
+
if ((error = git_vector_insert(&frame->entries, new_entry)) < 0)
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
534
648
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
tf->current--;
|
|
649
|
+
if (error)
|
|
650
|
+
break;
|
|
538
651
|
|
|
539
|
-
|
|
540
|
-
tf->start++;
|
|
541
|
-
tf->startlen = strlen(tf->start);
|
|
542
|
-
}
|
|
652
|
+
parent_frame->next_idx++;
|
|
543
653
|
}
|
|
544
654
|
|
|
545
|
-
|
|
655
|
+
return error;
|
|
656
|
+
}
|
|
546
657
|
|
|
547
|
-
|
|
548
|
-
|
|
658
|
+
GIT_INLINE(int) tree_iterator_frame_push(
|
|
659
|
+
tree_iterator *iter, tree_iterator_entry *entry)
|
|
660
|
+
{
|
|
661
|
+
tree_iterator_frame *parent_frame, *frame;
|
|
662
|
+
git_tree *tree = NULL;
|
|
663
|
+
int error;
|
|
549
664
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
665
|
+
if ((error = git_tree_lookup(&tree,
|
|
666
|
+
iter->base.repo, entry->tree_entry->oid)) < 0 ||
|
|
667
|
+
(error = tree_iterator_frame_init(iter, tree, entry)) < 0)
|
|
668
|
+
goto done;
|
|
553
669
|
|
|
554
|
-
|
|
555
|
-
|
|
670
|
+
parent_frame = tree_iterator_parent_frame(iter);
|
|
671
|
+
frame = tree_iterator_current_frame(iter);
|
|
556
672
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
673
|
+
/* if we're case insensitive, then we may have another directory that
|
|
674
|
+
* is (case insensitively) equal to this one. coalesce those children
|
|
675
|
+
* into this tree.
|
|
676
|
+
*/
|
|
677
|
+
if (iterator__ignore_case(&iter->base))
|
|
678
|
+
error = tree_iterator_frame_push_neighbors(iter,
|
|
679
|
+
parent_frame, frame, entry->tree_entry->filename);
|
|
560
680
|
|
|
561
|
-
|
|
681
|
+
done:
|
|
682
|
+
git_tree_free(tree);
|
|
683
|
+
return error;
|
|
684
|
+
}
|
|
562
685
|
|
|
563
|
-
|
|
564
|
-
|
|
686
|
+
static void tree_iterator_frame_pop(tree_iterator *iter)
|
|
687
|
+
{
|
|
688
|
+
tree_iterator_frame *frame;
|
|
689
|
+
git_buf *buf = NULL;
|
|
690
|
+
git_tree *tree;
|
|
691
|
+
size_t i;
|
|
565
692
|
|
|
566
|
-
|
|
567
|
-
ti->head->down = NULL;
|
|
693
|
+
assert(iter->frames.size);
|
|
568
694
|
|
|
569
|
-
|
|
695
|
+
frame = git_array_pop(iter->frames);
|
|
570
696
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
git_buf_rtruncate_at_char(&ti->path, '/');
|
|
574
|
-
}
|
|
697
|
+
git_vector_free(&frame->entries);
|
|
698
|
+
git_tree_free(frame->tree);
|
|
575
699
|
|
|
576
|
-
|
|
700
|
+
do {
|
|
701
|
+
buf = git_array_pop(frame->similar_paths);
|
|
702
|
+
git_buf_free(buf);
|
|
703
|
+
} while (buf != NULL);
|
|
577
704
|
|
|
578
|
-
|
|
579
|
-
}
|
|
705
|
+
git_array_clear(frame->similar_paths);
|
|
580
706
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
while (tree_iterator__pop_frame(ti, final)) /* pop to root */;
|
|
707
|
+
git_vector_foreach(&frame->similar_trees, i, tree)
|
|
708
|
+
git_tree_free(tree);
|
|
584
709
|
|
|
585
|
-
|
|
586
|
-
assert(ti->head);
|
|
710
|
+
git_vector_free(&frame->similar_trees);
|
|
587
711
|
|
|
588
|
-
|
|
589
|
-
ti->path_ambiguities = 0;
|
|
590
|
-
git_buf_clear(&ti->path);
|
|
591
|
-
}
|
|
712
|
+
git_buf_free(&frame->path);
|
|
592
713
|
}
|
|
593
714
|
|
|
594
|
-
static int
|
|
715
|
+
static int tree_iterator_current(
|
|
716
|
+
const git_index_entry **out, git_iterator *i)
|
|
595
717
|
{
|
|
596
|
-
|
|
597
|
-
const git_tree_entry *te;
|
|
598
|
-
|
|
599
|
-
if (ti->entry_is_current)
|
|
600
|
-
return 0;
|
|
601
|
-
|
|
602
|
-
tf = ti->head;
|
|
603
|
-
te = tf->entries[tf->current]->te;
|
|
718
|
+
tree_iterator *iter = (tree_iterator *)i;
|
|
604
719
|
|
|
605
|
-
|
|
606
|
-
|
|
720
|
+
if (!iterator__has_been_accessed(i))
|
|
721
|
+
return iter->base.cb->advance(out, i);
|
|
607
722
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
if (ti->path_ambiguities > 0)
|
|
612
|
-
tree_iterator__rewrite_filename(ti);
|
|
613
|
-
|
|
614
|
-
if (iterator__past_end(ti, ti->entry.path)) {
|
|
615
|
-
tree_iterator__pop_all(ti, true, false);
|
|
723
|
+
if (!iter->frames.size) {
|
|
724
|
+
*out = NULL;
|
|
616
725
|
return GIT_ITEROVER;
|
|
617
726
|
}
|
|
618
727
|
|
|
619
|
-
|
|
620
|
-
|
|
728
|
+
*out = &iter->entry;
|
|
621
729
|
return 0;
|
|
622
730
|
}
|
|
623
731
|
|
|
624
|
-
static
|
|
625
|
-
|
|
732
|
+
static void tree_iterator_set_current(
|
|
733
|
+
tree_iterator *iter,
|
|
734
|
+
tree_iterator_frame *frame,
|
|
735
|
+
tree_iterator_entry *entry)
|
|
626
736
|
{
|
|
627
|
-
|
|
628
|
-
tree_iterator *ti = (tree_iterator *)self;
|
|
629
|
-
tree_iterator_frame *tf = ti->head;
|
|
630
|
-
|
|
631
|
-
iterator__clear_entry(entry);
|
|
632
|
-
|
|
633
|
-
if (tf->current >= tf->n_entries)
|
|
634
|
-
return GIT_ITEROVER;
|
|
737
|
+
git_tree_entry *tree_entry = entry->tree_entry;
|
|
635
738
|
|
|
636
|
-
|
|
637
|
-
return error;
|
|
638
|
-
|
|
639
|
-
if (entry)
|
|
640
|
-
*entry = &ti->entry;
|
|
739
|
+
frame->current = entry;
|
|
641
740
|
|
|
642
|
-
|
|
741
|
+
memset(&iter->entry, 0x0, sizeof(git_index_entry));
|
|
643
742
|
|
|
644
|
-
|
|
743
|
+
iter->entry.mode = tree_entry->attr;
|
|
744
|
+
iter->entry.path = iter->entry_path.ptr;
|
|
745
|
+
git_oid_cpy(&iter->entry.id, tree_entry->oid);
|
|
645
746
|
}
|
|
646
747
|
|
|
647
|
-
static int
|
|
748
|
+
static int tree_iterator_advance(const git_index_entry **out, git_iterator *i)
|
|
648
749
|
{
|
|
750
|
+
tree_iterator *iter = (tree_iterator *)i;
|
|
649
751
|
int error = 0;
|
|
650
|
-
tree_iterator *ti = (tree_iterator *)self;
|
|
651
|
-
|
|
652
|
-
if (tree_iterator__at_tree(ti))
|
|
653
|
-
error = tree_iterator__push_frame(ti);
|
|
654
752
|
|
|
655
|
-
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
static int tree_iterator__advance_internal(git_iterator *self)
|
|
659
|
-
{
|
|
660
|
-
int error;
|
|
661
|
-
tree_iterator *ti = (tree_iterator *)self;
|
|
662
|
-
tree_iterator_frame *tf = ti->head;
|
|
753
|
+
iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS;
|
|
663
754
|
|
|
664
|
-
|
|
665
|
-
|
|
755
|
+
/* examine tree entries until we find the next one to return */
|
|
756
|
+
while (true) {
|
|
757
|
+
tree_iterator_entry *prev_entry, *entry;
|
|
758
|
+
tree_iterator_frame *frame;
|
|
759
|
+
bool is_tree;
|
|
666
760
|
|
|
667
|
-
|
|
668
|
-
|
|
761
|
+
if ((frame = tree_iterator_current_frame(iter)) == NULL) {
|
|
762
|
+
error = GIT_ITEROVER;
|
|
763
|
+
break;
|
|
764
|
+
}
|
|
669
765
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
766
|
+
/* no more entries in this frame. pop the frame out */
|
|
767
|
+
if (frame->next_idx == frame->entries.length) {
|
|
768
|
+
tree_iterator_frame_pop(iter);
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
673
771
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
772
|
+
/* we may have coalesced the contents of case-insensitively same-named
|
|
773
|
+
* directories, so do the sort now.
|
|
774
|
+
*/
|
|
775
|
+
if (frame->next_idx == 0 && !git_vector_is_sorted(&frame->entries))
|
|
776
|
+
git_vector_sort(&frame->entries);
|
|
678
777
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
778
|
+
/* we have more entries in the current frame, that's our next entry */
|
|
779
|
+
prev_entry = tree_iterator_current_entry(frame);
|
|
780
|
+
entry = frame->entries.contents[frame->next_idx];
|
|
781
|
+
frame->next_idx++;
|
|
683
782
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
783
|
+
/* we can have collisions when iterating case insensitively. (eg,
|
|
784
|
+
* 'A/a' and 'a/A'). squash this one if it's already been seen.
|
|
785
|
+
*/
|
|
786
|
+
if (iterator__ignore_case(&iter->base) &&
|
|
787
|
+
prev_entry &&
|
|
788
|
+
tree_iterator_entry_cmp_icase(prev_entry, entry) == 0)
|
|
789
|
+
continue;
|
|
687
790
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
return tree_iterator__advance_into_internal(self);
|
|
791
|
+
if ((error = tree_iterator_compute_path(&iter->entry_path, entry)) < 0)
|
|
792
|
+
break;
|
|
691
793
|
|
|
692
|
-
|
|
693
|
-
|
|
794
|
+
/* if this path is before our start, advance over this entry */
|
|
795
|
+
if (!iterator_has_started(&iter->base, iter->entry_path.ptr, false))
|
|
796
|
+
continue;
|
|
694
797
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
int error;
|
|
798
|
+
/* if this path is after our end, stop */
|
|
799
|
+
if (iterator_has_ended(&iter->base, iter->entry_path.ptr)) {
|
|
800
|
+
error = GIT_ITEROVER;
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
701
803
|
|
|
702
|
-
|
|
703
|
-
if ((
|
|
704
|
-
|
|
804
|
+
/* if we have a list of paths we're interested in, examine it */
|
|
805
|
+
if (!iterator_pathlist_next_is(&iter->base, iter->entry_path.ptr))
|
|
806
|
+
continue;
|
|
705
807
|
|
|
706
|
-
|
|
707
|
-
m = iterator_pathlist__match(
|
|
708
|
-
self, entry->path, strlen(entry->path));
|
|
808
|
+
is_tree = git_tree_entry__is_tree(entry->tree_entry);
|
|
709
809
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
return error;
|
|
810
|
+
/* if we are *not* including trees then advance over this entry */
|
|
811
|
+
if (is_tree && !iterator__include_trees(iter)) {
|
|
713
812
|
|
|
714
|
-
|
|
813
|
+
/* if we've found a tree (and are not returning it to the caller)
|
|
814
|
+
* and we are autoexpanding, then we want to return the first
|
|
815
|
+
* child. push the new directory and advance.
|
|
816
|
+
*/
|
|
817
|
+
if (iterator__do_autoexpand(iter)) {
|
|
818
|
+
if ((error = tree_iterator_frame_push(iter, entry)) < 0)
|
|
819
|
+
break;
|
|
715
820
|
}
|
|
821
|
+
|
|
822
|
+
continue;
|
|
716
823
|
}
|
|
717
|
-
|
|
824
|
+
|
|
825
|
+
tree_iterator_set_current(iter, frame, entry);
|
|
826
|
+
|
|
827
|
+
/* if we are autoexpanding, then push this as a new frame, so that
|
|
828
|
+
* the next call to `advance` will dive into this directory.
|
|
829
|
+
*/
|
|
830
|
+
if (is_tree && iterator__do_autoexpand(iter))
|
|
831
|
+
error = tree_iterator_frame_push(iter, entry);
|
|
832
|
+
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
718
835
|
|
|
719
836
|
if (out)
|
|
720
|
-
*out = entry;
|
|
837
|
+
*out = (error == 0) ? &iter->entry : NULL;
|
|
721
838
|
|
|
722
839
|
return error;
|
|
723
840
|
}
|
|
724
841
|
|
|
725
|
-
static int
|
|
726
|
-
const git_index_entry **
|
|
842
|
+
static int tree_iterator_advance_into(
|
|
843
|
+
const git_index_entry **out, git_iterator *i)
|
|
727
844
|
{
|
|
728
|
-
|
|
845
|
+
tree_iterator *iter = (tree_iterator *)i;
|
|
846
|
+
tree_iterator_frame *frame;
|
|
847
|
+
tree_iterator_entry *prev_entry;
|
|
848
|
+
int error;
|
|
729
849
|
|
|
730
|
-
|
|
850
|
+
if (out)
|
|
851
|
+
*out = NULL;
|
|
731
852
|
|
|
732
|
-
if (
|
|
733
|
-
return
|
|
853
|
+
if ((frame = tree_iterator_current_frame(iter)) == NULL)
|
|
854
|
+
return GIT_ITEROVER;
|
|
734
855
|
|
|
735
|
-
|
|
736
|
-
|
|
856
|
+
/* get the last seen entry */
|
|
857
|
+
prev_entry = tree_iterator_current_entry(frame);
|
|
737
858
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
859
|
+
/* it's legal to call advance_into when auto-expand is on. in this case,
|
|
860
|
+
* we will have pushed a new (empty) frame on to the stack for this
|
|
861
|
+
* new directory. since it's empty, its current_entry should be null.
|
|
862
|
+
*/
|
|
863
|
+
assert(iterator__do_autoexpand(i) ^ (prev_entry != NULL));
|
|
742
864
|
|
|
743
|
-
|
|
865
|
+
if (prev_entry) {
|
|
866
|
+
if (!git_tree_entry__is_tree(prev_entry->tree_entry))
|
|
867
|
+
return 0;
|
|
744
868
|
|
|
745
|
-
|
|
746
|
-
|
|
869
|
+
if ((error = tree_iterator_frame_push(iter, prev_entry)) < 0)
|
|
870
|
+
return error;
|
|
871
|
+
}
|
|
747
872
|
|
|
748
|
-
|
|
873
|
+
/* we've advanced into the directory in question, let advance
|
|
874
|
+
* find the first entry
|
|
875
|
+
*/
|
|
876
|
+
return tree_iterator_advance(out, i);
|
|
749
877
|
}
|
|
750
878
|
|
|
751
|
-
static int
|
|
879
|
+
static int tree_iterator_advance_over(
|
|
880
|
+
const git_index_entry **out,
|
|
881
|
+
git_iterator_status_t *status,
|
|
882
|
+
git_iterator *i)
|
|
752
883
|
{
|
|
753
|
-
|
|
754
|
-
return
|
|
884
|
+
*status = GIT_ITERATOR_STATUS_NORMAL;
|
|
885
|
+
return git_iterator_advance(out, i);
|
|
755
886
|
}
|
|
756
887
|
|
|
757
|
-
static
|
|
758
|
-
git_iterator *self, const char *start, const char *end)
|
|
888
|
+
static void tree_iterator_clear(tree_iterator *iter)
|
|
759
889
|
{
|
|
760
|
-
|
|
890
|
+
while (iter->frames.size)
|
|
891
|
+
tree_iterator_frame_pop(iter);
|
|
761
892
|
|
|
762
|
-
|
|
893
|
+
git_array_clear(iter->frames);
|
|
763
894
|
|
|
764
|
-
|
|
765
|
-
|
|
895
|
+
git_pool_clear(&iter->entry_pool);
|
|
896
|
+
git_buf_clear(&iter->entry_path);
|
|
766
897
|
|
|
767
|
-
|
|
898
|
+
iterator_clear(&iter->base);
|
|
768
899
|
}
|
|
769
900
|
|
|
770
|
-
static int
|
|
901
|
+
static int tree_iterator_init(tree_iterator *iter)
|
|
771
902
|
{
|
|
772
|
-
|
|
773
|
-
return (ti->head->current >= ti->head->n_entries);
|
|
774
|
-
}
|
|
903
|
+
int error;
|
|
775
904
|
|
|
776
|
-
|
|
777
|
-
{
|
|
778
|
-
tree_iterator *ti = (tree_iterator *)self;
|
|
905
|
+
git_pool_init(&iter->entry_pool, sizeof(tree_iterator_entry));
|
|
779
906
|
|
|
780
|
-
if (
|
|
781
|
-
|
|
782
|
-
git_tree_free(ti->head->entries[0]->tree);
|
|
783
|
-
git__free(ti->head);
|
|
784
|
-
}
|
|
907
|
+
if ((error = tree_iterator_frame_init(iter, iter->root, NULL)) < 0)
|
|
908
|
+
return error;
|
|
785
909
|
|
|
786
|
-
|
|
787
|
-
|
|
910
|
+
iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
|
|
911
|
+
|
|
912
|
+
return 0;
|
|
788
913
|
}
|
|
789
914
|
|
|
790
|
-
static int
|
|
915
|
+
static int tree_iterator_reset(git_iterator *i)
|
|
791
916
|
{
|
|
792
|
-
|
|
793
|
-
tree_iterator_frame *root = git__calloc(sz, sizeof(char));
|
|
794
|
-
GITERR_CHECK_ALLOC(root);
|
|
917
|
+
tree_iterator *iter = (tree_iterator *)i;
|
|
795
918
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
919
|
+
tree_iterator_clear(iter);
|
|
920
|
+
return tree_iterator_init(iter);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
static void tree_iterator_free(git_iterator *i)
|
|
924
|
+
{
|
|
925
|
+
tree_iterator *iter = (tree_iterator *)i;
|
|
803
926
|
|
|
804
|
-
|
|
927
|
+
tree_iterator_clear(iter);
|
|
805
928
|
|
|
806
|
-
|
|
929
|
+
git_tree_free(iter->root);
|
|
930
|
+
git_buf_free(&iter->entry_path);
|
|
807
931
|
}
|
|
808
932
|
|
|
809
933
|
int git_iterator_for_tree(
|
|
810
|
-
git_iterator **
|
|
934
|
+
git_iterator **out,
|
|
811
935
|
git_tree *tree,
|
|
812
936
|
git_iterator_options *options)
|
|
813
937
|
{
|
|
938
|
+
tree_iterator *iter;
|
|
814
939
|
int error;
|
|
815
|
-
tree_iterator *ti;
|
|
816
|
-
|
|
817
|
-
if (tree == NULL)
|
|
818
|
-
return git_iterator_for_nothing(iter, options);
|
|
819
940
|
|
|
820
|
-
|
|
821
|
-
|
|
941
|
+
static git_iterator_callbacks callbacks = {
|
|
942
|
+
tree_iterator_current,
|
|
943
|
+
tree_iterator_advance,
|
|
944
|
+
tree_iterator_advance_into,
|
|
945
|
+
tree_iterator_advance_over,
|
|
946
|
+
tree_iterator_reset,
|
|
947
|
+
tree_iterator_free
|
|
948
|
+
};
|
|
822
949
|
|
|
823
|
-
|
|
824
|
-
GITERR_CHECK_ALLOC(ti);
|
|
950
|
+
*out = NULL;
|
|
825
951
|
|
|
826
|
-
|
|
952
|
+
if (tree == NULL)
|
|
953
|
+
return git_iterator_for_nothing(out, options);
|
|
827
954
|
|
|
828
|
-
|
|
829
|
-
|
|
955
|
+
iter = git__calloc(1, sizeof(tree_iterator));
|
|
956
|
+
GITERR_CHECK_ALLOC(iter);
|
|
830
957
|
|
|
831
|
-
|
|
958
|
+
iter->base.type = GIT_ITERATOR_TYPE_TREE;
|
|
959
|
+
iter->base.cb = &callbacks;
|
|
832
960
|
|
|
833
|
-
if ((error =
|
|
834
|
-
|
|
835
|
-
|
|
961
|
+
if ((error = iterator_init_common(&iter->base,
|
|
962
|
+
git_tree_owner(tree), NULL, options)) < 0 ||
|
|
963
|
+
(error = git_tree_dup(&iter->root, tree)) < 0 ||
|
|
964
|
+
(error = tree_iterator_init(iter)) < 0)
|
|
965
|
+
goto on_error;
|
|
836
966
|
|
|
837
|
-
*
|
|
967
|
+
*out = &iter->base;
|
|
838
968
|
return 0;
|
|
839
969
|
|
|
840
|
-
|
|
841
|
-
git_iterator_free(
|
|
970
|
+
on_error:
|
|
971
|
+
git_iterator_free(&iter->base);
|
|
842
972
|
return error;
|
|
843
973
|
}
|
|
844
974
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
git_iterator base;
|
|
848
|
-
git_iterator_callbacks cb;
|
|
849
|
-
git_index *index;
|
|
850
|
-
git_vector entries;
|
|
851
|
-
git_vector_cmp entry_srch;
|
|
852
|
-
size_t current;
|
|
853
|
-
/* when limiting with a pathlist, this is the current index into it */
|
|
854
|
-
size_t pathlist_idx;
|
|
855
|
-
/* when not in autoexpand mode, use these to represent "tree" state */
|
|
856
|
-
git_buf partial;
|
|
857
|
-
size_t partial_pos;
|
|
858
|
-
char restore_terminator;
|
|
859
|
-
git_index_entry tree_entry;
|
|
860
|
-
} index_iterator;
|
|
861
|
-
|
|
862
|
-
static const git_index_entry *index_iterator__index_entry(index_iterator *ii)
|
|
863
|
-
{
|
|
864
|
-
const git_index_entry *ie = git_vector_get(&ii->entries, ii->current);
|
|
865
|
-
|
|
866
|
-
if (ie != NULL && iterator__past_end(ii, ie->path)) {
|
|
867
|
-
ii->current = git_vector_length(&ii->entries);
|
|
868
|
-
ie = NULL;
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
return ie;
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
static const git_index_entry *index_iterator__advance_over_unwanted(
|
|
875
|
-
index_iterator *ii)
|
|
975
|
+
int git_iterator_current_tree_entry(
|
|
976
|
+
const git_tree_entry **tree_entry, git_iterator *i)
|
|
876
977
|
{
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
while (ie) {
|
|
881
|
-
if (!iterator__include_conflicts(ii) &&
|
|
882
|
-
git_index_entry_is_conflict(ie)) {
|
|
883
|
-
ii->current++;
|
|
884
|
-
ie = index_iterator__index_entry(ii);
|
|
885
|
-
continue;
|
|
886
|
-
}
|
|
978
|
+
tree_iterator *iter;
|
|
979
|
+
tree_iterator_frame *frame;
|
|
980
|
+
tree_iterator_entry *entry;
|
|
887
981
|
|
|
888
|
-
|
|
889
|
-
* returned. walk the pathlist in unison with the index to
|
|
890
|
-
* compare paths.
|
|
891
|
-
*/
|
|
892
|
-
if (ii->base.pathlist.length) {
|
|
893
|
-
match = iterator_pathlist_walk__contains(&ii->base, ie->path);
|
|
982
|
+
assert(i->type == GIT_ITERATOR_TYPE_TREE);
|
|
894
983
|
|
|
895
|
-
|
|
896
|
-
ii->current++;
|
|
897
|
-
ie = index_iterator__index_entry(ii);
|
|
898
|
-
continue;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
984
|
+
iter = (tree_iterator *)i;
|
|
901
985
|
|
|
902
|
-
|
|
903
|
-
|
|
986
|
+
frame = tree_iterator_current_frame(iter);
|
|
987
|
+
entry = tree_iterator_current_entry(frame);
|
|
904
988
|
|
|
905
|
-
|
|
989
|
+
*tree_entry = entry->tree_entry;
|
|
990
|
+
return 0;
|
|
906
991
|
}
|
|
907
992
|
|
|
908
|
-
|
|
993
|
+
int git_iterator_current_parent_tree(
|
|
994
|
+
const git_tree **parent_tree, git_iterator *i, size_t depth)
|
|
909
995
|
{
|
|
910
|
-
|
|
996
|
+
tree_iterator *iter;
|
|
997
|
+
tree_iterator_frame *frame;
|
|
911
998
|
|
|
912
|
-
|
|
913
|
-
return;
|
|
999
|
+
assert(i->type == GIT_ITERATOR_TYPE_TREE);
|
|
914
1000
|
|
|
915
|
-
|
|
1001
|
+
iter = (tree_iterator *)i;
|
|
916
1002
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
ii->restore_terminator = ii->partial.ptr[ii->partial_pos];
|
|
920
|
-
ii->partial.ptr[ii->partial_pos] = '\0';
|
|
921
|
-
} else {
|
|
922
|
-
ii->partial_pos = ii->partial.size;
|
|
923
|
-
}
|
|
1003
|
+
assert(depth < iter->frames.size);
|
|
1004
|
+
frame = &iter->frames.ptr[iter->frames.size-depth-1];
|
|
924
1005
|
|
|
925
|
-
|
|
926
|
-
|
|
1006
|
+
*parent_tree = frame->tree;
|
|
1007
|
+
return 0;
|
|
927
1008
|
}
|
|
928
1009
|
|
|
929
|
-
|
|
930
|
-
{
|
|
931
|
-
const git_index_entry *ie = index_iterator__advance_over_unwanted(ii);
|
|
932
|
-
const char *scan, *prior, *slash;
|
|
1010
|
+
/* Filesystem iterator */
|
|
933
1011
|
|
|
934
|
-
|
|
935
|
-
|
|
1012
|
+
typedef struct {
|
|
1013
|
+
struct stat st;
|
|
1014
|
+
size_t path_len;
|
|
1015
|
+
iterator_pathlist_search_t match;
|
|
1016
|
+
char path[GIT_FLEX_ARRAY];
|
|
1017
|
+
} filesystem_iterator_entry;
|
|
936
1018
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
slash = scan;
|
|
1019
|
+
typedef struct {
|
|
1020
|
+
git_vector entries;
|
|
1021
|
+
git_pool entry_pool;
|
|
1022
|
+
size_t next_idx;
|
|
942
1023
|
|
|
943
|
-
|
|
944
|
-
|
|
1024
|
+
size_t path_len;
|
|
1025
|
+
int is_ignored;
|
|
1026
|
+
} filesystem_iterator_frame;
|
|
945
1027
|
|
|
946
|
-
|
|
947
|
-
|
|
1028
|
+
typedef struct {
|
|
1029
|
+
git_iterator base;
|
|
1030
|
+
char *root;
|
|
1031
|
+
size_t root_len;
|
|
948
1032
|
|
|
949
|
-
|
|
950
|
-
}
|
|
1033
|
+
unsigned int dirload_flags;
|
|
951
1034
|
|
|
952
|
-
|
|
953
|
-
|
|
1035
|
+
git_tree *tree;
|
|
1036
|
+
git_index *index;
|
|
1037
|
+
git_vector index_snapshot;
|
|
954
1038
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
{
|
|
958
|
-
index_iterator *ii = (index_iterator *)self;
|
|
959
|
-
const git_index_entry *ie = git_vector_get(&ii->entries, ii->current);
|
|
1039
|
+
git_array_t(filesystem_iterator_frame) frames;
|
|
1040
|
+
git_ignores ignores;
|
|
960
1041
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1042
|
+
/* info about the current entry */
|
|
1043
|
+
git_index_entry entry;
|
|
1044
|
+
git_buf current_path;
|
|
1045
|
+
int current_is_ignored;
|
|
965
1046
|
|
|
966
|
-
|
|
967
|
-
|
|
1047
|
+
/* temporary buffer for advance_over */
|
|
1048
|
+
git_buf tmp_buf;
|
|
1049
|
+
} filesystem_iterator;
|
|
968
1050
|
|
|
969
|
-
ii->base.flags |= GIT_ITERATOR_FIRST_ACCESS;
|
|
970
1051
|
|
|
971
|
-
|
|
1052
|
+
GIT_INLINE(filesystem_iterator_frame *) filesystem_iterator_parent_frame(
|
|
1053
|
+
filesystem_iterator *iter)
|
|
1054
|
+
{
|
|
1055
|
+
return iter->frames.size > 1 ?
|
|
1056
|
+
&iter->frames.ptr[iter->frames.size-2] : NULL;
|
|
972
1057
|
}
|
|
973
1058
|
|
|
974
|
-
|
|
1059
|
+
GIT_INLINE(filesystem_iterator_frame *) filesystem_iterator_current_frame(
|
|
1060
|
+
filesystem_iterator *iter)
|
|
975
1061
|
{
|
|
976
|
-
|
|
977
|
-
return (ii->current >= git_vector_length(&ii->entries));
|
|
1062
|
+
return iter->frames.size ? &iter->frames.ptr[iter->frames.size-1] : NULL;
|
|
978
1063
|
}
|
|
979
1064
|
|
|
980
|
-
|
|
981
|
-
|
|
1065
|
+
GIT_INLINE(filesystem_iterator_entry *) filesystem_iterator_current_entry(
|
|
1066
|
+
filesystem_iterator_frame *frame)
|
|
982
1067
|
{
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
const git_index_entry *ie;
|
|
986
|
-
|
|
987
|
-
if (!iterator__has_been_accessed(ii))
|
|
988
|
-
return index_iterator__current(entry, self);
|
|
989
|
-
|
|
990
|
-
if (index_iterator__at_tree(ii)) {
|
|
991
|
-
if (iterator__do_autoexpand(ii)) {
|
|
992
|
-
ii->partial.ptr[ii->partial_pos] = ii->restore_terminator;
|
|
993
|
-
index_iterator__next_prefix_tree(ii);
|
|
994
|
-
} else {
|
|
995
|
-
/* advance to sibling tree (i.e. find entry with new prefix) */
|
|
996
|
-
while (ii->current < entrycount) {
|
|
997
|
-
ii->current++;
|
|
998
|
-
|
|
999
|
-
if (!(ie = git_vector_get(&ii->entries, ii->current)) ||
|
|
1000
|
-
ii->base.prefixcomp(ie->path, ii->partial.ptr) != 0)
|
|
1001
|
-
break;
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
if (index_iterator__first_prefix_tree(ii) < 0)
|
|
1005
|
-
return -1;
|
|
1006
|
-
}
|
|
1007
|
-
} else {
|
|
1008
|
-
if (ii->current < entrycount)
|
|
1009
|
-
ii->current++;
|
|
1010
|
-
|
|
1011
|
-
if (index_iterator__first_prefix_tree(ii) < 0)
|
|
1012
|
-
return -1;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
return index_iterator__current(entry, self);
|
|
1068
|
+
return frame->next_idx == 0 ?
|
|
1069
|
+
NULL : frame->entries.contents[frame->next_idx-1];
|
|
1016
1070
|
}
|
|
1017
1071
|
|
|
1018
|
-
static int
|
|
1019
|
-
const git_index_entry **entry, git_iterator *self)
|
|
1072
|
+
static int filesystem_iterator_entry_cmp(const void *_a, const void *_b)
|
|
1020
1073
|
{
|
|
1021
|
-
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
if (ie != NULL && index_iterator__at_tree(ii)) {
|
|
1025
|
-
if (ii->restore_terminator)
|
|
1026
|
-
ii->partial.ptr[ii->partial_pos] = ii->restore_terminator;
|
|
1027
|
-
index_iterator__next_prefix_tree(ii);
|
|
1028
|
-
}
|
|
1074
|
+
const filesystem_iterator_entry *a = (const filesystem_iterator_entry *)_a;
|
|
1075
|
+
const filesystem_iterator_entry *b = (const filesystem_iterator_entry *)_b;
|
|
1029
1076
|
|
|
1030
|
-
return
|
|
1077
|
+
return git__strcmp(a->path, b->path);
|
|
1031
1078
|
}
|
|
1032
1079
|
|
|
1033
|
-
static int
|
|
1080
|
+
static int filesystem_iterator_entry_cmp_icase(const void *_a, const void *_b)
|
|
1034
1081
|
{
|
|
1035
|
-
|
|
1036
|
-
|
|
1082
|
+
const filesystem_iterator_entry *a = (const filesystem_iterator_entry *)_a;
|
|
1083
|
+
const filesystem_iterator_entry *b = (const filesystem_iterator_entry *)_b;
|
|
1084
|
+
|
|
1085
|
+
return git__strcasecmp(a->path, b->path);
|
|
1037
1086
|
}
|
|
1038
1087
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1088
|
+
#define FILESYSTEM_MAX_DEPTH 100
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Figure out if an entry is a submodule.
|
|
1092
|
+
*
|
|
1093
|
+
* We consider it a submodule if the path is listed as a submodule in
|
|
1094
|
+
* either the tree or the index.
|
|
1095
|
+
*/
|
|
1096
|
+
static int filesystem_iterator_is_submodule(
|
|
1097
|
+
bool *out, filesystem_iterator *iter, const char *path, size_t path_len)
|
|
1041
1098
|
{
|
|
1042
|
-
|
|
1043
|
-
|
|
1099
|
+
bool is_submodule = false;
|
|
1100
|
+
int error;
|
|
1044
1101
|
|
|
1045
|
-
|
|
1046
|
-
return -1;
|
|
1102
|
+
*out = false;
|
|
1047
1103
|
|
|
1048
|
-
|
|
1104
|
+
/* first see if this path is a submodule in HEAD */
|
|
1105
|
+
if (iter->tree) {
|
|
1106
|
+
git_tree_entry *entry;
|
|
1049
1107
|
|
|
1050
|
-
|
|
1108
|
+
error = git_tree_entry_bypath(&entry, iter->tree, path);
|
|
1051
1109
|
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
*/
|
|
1055
|
-
if (ii->base.start)
|
|
1056
|
-
git_index_snapshot_find(
|
|
1057
|
-
&ii->current, &ii->entries, ii->entry_srch, ii->base.start, 0, 0);
|
|
1110
|
+
if (error < 0 && error != GIT_ENOTFOUND)
|
|
1111
|
+
return error;
|
|
1058
1112
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1113
|
+
if (!error) {
|
|
1114
|
+
is_submodule = (entry->attr == GIT_FILEMODE_COMMIT);
|
|
1115
|
+
git_tree_entry_free(entry);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1061
1118
|
|
|
1062
|
-
if (
|
|
1063
|
-
|
|
1119
|
+
if (!is_submodule && iter->base.index) {
|
|
1120
|
+
size_t pos;
|
|
1064
1121
|
|
|
1065
|
-
|
|
1122
|
+
error = git_index_snapshot_find(&pos,
|
|
1123
|
+
&iter->index_snapshot, iter->base.entry_srch, path, path_len, 0);
|
|
1066
1124
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1125
|
+
if (error < 0 && error != GIT_ENOTFOUND)
|
|
1126
|
+
return error;
|
|
1069
1127
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1128
|
+
if (!error) {
|
|
1129
|
+
git_index_entry *e = git_vector_get(&iter->index_snapshot, pos);
|
|
1130
|
+
is_submodule = (e->mode == GIT_FILEMODE_COMMIT);
|
|
1131
|
+
}
|
|
1072
1132
|
}
|
|
1073
1133
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1134
|
+
*out = is_submodule;
|
|
1076
1135
|
return 0;
|
|
1077
1136
|
}
|
|
1078
1137
|
|
|
1079
|
-
static void
|
|
1138
|
+
static void filesystem_iterator_frame_push_ignores(
|
|
1139
|
+
filesystem_iterator *iter,
|
|
1140
|
+
filesystem_iterator_entry *frame_entry,
|
|
1141
|
+
filesystem_iterator_frame *new_frame)
|
|
1080
1142
|
{
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
ii->index = NULL;
|
|
1084
|
-
git_buf_free(&ii->partial);
|
|
1085
|
-
}
|
|
1143
|
+
filesystem_iterator_frame *previous_frame;
|
|
1144
|
+
const char *path = frame_entry ? frame_entry->path : "";
|
|
1086
1145
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
git_repository *repo,
|
|
1090
|
-
git_index *index,
|
|
1091
|
-
git_iterator_options *options)
|
|
1092
|
-
{
|
|
1093
|
-
int error = 0;
|
|
1094
|
-
index_iterator *ii = git__calloc(1, sizeof(index_iterator));
|
|
1095
|
-
GITERR_CHECK_ALLOC(ii);
|
|
1146
|
+
if (!iterator__honor_ignores(&iter->base))
|
|
1147
|
+
return;
|
|
1096
1148
|
|
|
1097
|
-
if ((
|
|
1098
|
-
|
|
1099
|
-
|
|
1149
|
+
if (git_ignore__lookup(&new_frame->is_ignored,
|
|
1150
|
+
&iter->ignores, path, GIT_DIR_FLAG_TRUE) < 0) {
|
|
1151
|
+
giterr_clear();
|
|
1152
|
+
new_frame->is_ignored = GIT_IGNORE_NOTFOUND;
|
|
1100
1153
|
}
|
|
1101
|
-
ii->index = index;
|
|
1102
1154
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
git_iterator_free((git_iterator *)ii);
|
|
1107
|
-
return error;
|
|
1108
|
-
}
|
|
1155
|
+
/* if this is not the top level directory... */
|
|
1156
|
+
if (frame_entry) {
|
|
1157
|
+
const char *relative_path;
|
|
1109
1158
|
|
|
1110
|
-
|
|
1111
|
-
git_index_entry_isrch : git_index_entry_srch;
|
|
1159
|
+
previous_frame = filesystem_iterator_parent_frame(iter);
|
|
1112
1160
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
git_vector_sort(&ii->entries);
|
|
1161
|
+
/* push new ignores for files in this directory */
|
|
1162
|
+
relative_path = frame_entry->path + previous_frame->path_len;
|
|
1116
1163
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1164
|
+
/* inherit ignored from parent if no rule specified */
|
|
1165
|
+
if (new_frame->is_ignored <= GIT_IGNORE_NOTFOUND)
|
|
1166
|
+
new_frame->is_ignored = previous_frame->is_ignored;
|
|
1119
1167
|
|
|
1120
|
-
|
|
1168
|
+
git_ignore__push_dir(&iter->ignores, relative_path);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1121
1171
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1172
|
+
static void filesystem_iterator_frame_pop_ignores(
|
|
1173
|
+
filesystem_iterator *iter)
|
|
1174
|
+
{
|
|
1175
|
+
if (iterator__honor_ignores(&iter->base))
|
|
1176
|
+
git_ignore__pop_dir(&iter->ignores);
|
|
1124
1177
|
}
|
|
1125
1178
|
|
|
1179
|
+
GIT_INLINE(bool) filesystem_iterator_examine_path(
|
|
1180
|
+
bool *is_dir_out,
|
|
1181
|
+
iterator_pathlist_search_t *match_out,
|
|
1182
|
+
filesystem_iterator *iter,
|
|
1183
|
+
filesystem_iterator_entry *frame_entry,
|
|
1184
|
+
const char *path,
|
|
1185
|
+
size_t path_len)
|
|
1186
|
+
{
|
|
1187
|
+
bool is_dir = 0;
|
|
1188
|
+
iterator_pathlist_search_t match = ITERATOR_PATHLIST_FULL;
|
|
1126
1189
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
fs_iterator_frame *next;
|
|
1130
|
-
git_vector entries;
|
|
1131
|
-
size_t index;
|
|
1132
|
-
int is_ignored;
|
|
1133
|
-
};
|
|
1190
|
+
*is_dir_out = false;
|
|
1191
|
+
*match_out = ITERATOR_PATHLIST_NONE;
|
|
1134
1192
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
git_iterator base;
|
|
1138
|
-
git_iterator_callbacks cb;
|
|
1139
|
-
fs_iterator_frame *stack;
|
|
1140
|
-
git_index_entry entry;
|
|
1141
|
-
git_buf path;
|
|
1142
|
-
size_t root_len;
|
|
1143
|
-
uint32_t dirload_flags;
|
|
1144
|
-
int depth;
|
|
1145
|
-
iterator_pathlist__match_t pathlist_match;
|
|
1193
|
+
if (iter->base.start_len) {
|
|
1194
|
+
int cmp = iter->base.strncomp(path, iter->base.start, path_len);
|
|
1146
1195
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1196
|
+
/* we haven't stat'ed `path` yet, so we don't yet know if it's a
|
|
1197
|
+
* directory or not. special case if the current path may be a
|
|
1198
|
+
* directory that matches the start prefix.
|
|
1199
|
+
*/
|
|
1200
|
+
if (cmp == 0) {
|
|
1201
|
+
if (iter->base.start[path_len] == '/')
|
|
1202
|
+
is_dir = true;
|
|
1151
1203
|
|
|
1152
|
-
|
|
1204
|
+
else if (iter->base.start[path_len] != '\0')
|
|
1205
|
+
cmp = -1;
|
|
1206
|
+
}
|
|
1153
1207
|
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
size_t path_len;
|
|
1158
|
-
char path[GIT_FLEX_ARRAY];
|
|
1159
|
-
} fs_iterator_path_with_stat;
|
|
1208
|
+
if (cmp < 0)
|
|
1209
|
+
return false;
|
|
1210
|
+
}
|
|
1160
1211
|
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const fs_iterator_path_with_stat *psa = a, *psb = b;
|
|
1164
|
-
return strcmp(psa->path, psb->path);
|
|
1165
|
-
}
|
|
1212
|
+
if (iter->base.end_len) {
|
|
1213
|
+
int cmp = iter->base.strncomp(path, iter->base.end, iter->base.end_len);
|
|
1166
1214
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
return strcasecmp(psa->path, psb->path);
|
|
1171
|
-
}
|
|
1215
|
+
if (cmp > 0)
|
|
1216
|
+
return false;
|
|
1217
|
+
}
|
|
1172
1218
|
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1219
|
+
/* if we have a pathlist that we're limiting to, examine this path now
|
|
1220
|
+
* to avoid a `stat` if we're not interested in the path.
|
|
1221
|
+
*/
|
|
1222
|
+
if (iter->base.pathlist.length) {
|
|
1223
|
+
/* if our parent was explicitly included, so too are we */
|
|
1224
|
+
if (frame_entry && frame_entry->match != ITERATOR_PATHLIST_IS_PARENT)
|
|
1225
|
+
match = ITERATOR_PATHLIST_FULL;
|
|
1226
|
+
else
|
|
1227
|
+
match = iterator_pathlist_search(&iter->base, path, path_len);
|
|
1180
1228
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
ff = NULL;
|
|
1184
|
-
}
|
|
1229
|
+
if (match == ITERATOR_PATHLIST_NONE)
|
|
1230
|
+
return false;
|
|
1185
1231
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1232
|
+
/* Ensure that the pathlist entry lines up with what we expected */
|
|
1233
|
+
if (match == ITERATOR_PATHLIST_IS_DIR ||
|
|
1234
|
+
match == ITERATOR_PATHLIST_IS_PARENT)
|
|
1235
|
+
is_dir = true;
|
|
1236
|
+
}
|
|
1188
1237
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
git__free(ff);
|
|
1238
|
+
*is_dir_out = is_dir;
|
|
1239
|
+
*match_out = match;
|
|
1240
|
+
return true;
|
|
1193
1241
|
}
|
|
1194
1242
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1243
|
+
GIT_INLINE(bool) filesystem_iterator_is_dot_git(
|
|
1244
|
+
filesystem_iterator *iter, const char *path, size_t path_len)
|
|
1197
1245
|
{
|
|
1198
|
-
|
|
1199
|
-
if (!ff->next && !pop_last) {
|
|
1200
|
-
memset(&fi->entry, 0, sizeof(fi->entry));
|
|
1201
|
-
return;
|
|
1202
|
-
}
|
|
1246
|
+
size_t len;
|
|
1203
1247
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1248
|
+
if (!iterator__ignore_dot_git(&iter->base))
|
|
1249
|
+
return false;
|
|
1206
1250
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
}
|
|
1251
|
+
if ((len = path_len) < 4)
|
|
1252
|
+
return false;
|
|
1210
1253
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1254
|
+
if (path[len - 1] == '/')
|
|
1255
|
+
len--;
|
|
1213
1256
|
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1257
|
+
if (git__tolower(path[len - 1]) != 't' ||
|
|
1258
|
+
git__tolower(path[len - 2]) != 'i' ||
|
|
1259
|
+
git__tolower(path[len - 3]) != 'g' ||
|
|
1260
|
+
git__tolower(path[len - 4]) != '.')
|
|
1261
|
+
return false;
|
|
1217
1262
|
|
|
1218
|
-
|
|
1219
|
-
{
|
|
1220
|
-
const fs_iterator *fi = (const fs_iterator *)i;
|
|
1221
|
-
const fs_iterator_path_with_stat *ps = item;
|
|
1222
|
-
return fi->base.prefixcomp(fi->base.start, ps->path);
|
|
1263
|
+
return (len == 4 || path[len - 5] == '/');
|
|
1223
1264
|
}
|
|
1224
1265
|
|
|
1225
|
-
static
|
|
1226
|
-
|
|
1266
|
+
static filesystem_iterator_entry *filesystem_iterator_entry_init(
|
|
1267
|
+
filesystem_iterator_frame *frame,
|
|
1268
|
+
const char *path,
|
|
1269
|
+
size_t path_len,
|
|
1270
|
+
struct stat *statbuf,
|
|
1271
|
+
iterator_pathlist_search_t pathlist_match)
|
|
1227
1272
|
{
|
|
1228
|
-
|
|
1229
|
-
|
|
1273
|
+
filesystem_iterator_entry *entry;
|
|
1274
|
+
size_t entry_size;
|
|
1230
1275
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1276
|
+
/* Make sure to append two bytes, one for the path's null
|
|
1277
|
+
* termination, one for a possible trailing '/' for folders.
|
|
1278
|
+
*/
|
|
1279
|
+
if (GIT_ADD_SIZET_OVERFLOW(&entry_size,
|
|
1280
|
+
sizeof(filesystem_iterator_entry), path_len) ||
|
|
1281
|
+
GIT_ADD_SIZET_OVERFLOW(&entry_size, entry_size, 2) ||
|
|
1282
|
+
(entry = git_pool_malloc(&frame->entry_pool, entry_size)) == NULL)
|
|
1283
|
+
return NULL;
|
|
1284
|
+
|
|
1285
|
+
entry->path_len = path_len;
|
|
1286
|
+
entry->match = pathlist_match;
|
|
1287
|
+
memcpy(entry->path, path, path_len);
|
|
1288
|
+
memcpy(&entry->st, statbuf, sizeof(struct stat));
|
|
1289
|
+
|
|
1290
|
+
/* Suffix directory paths with a '/' */
|
|
1291
|
+
if (S_ISDIR(entry->st.st_mode))
|
|
1292
|
+
entry->path[entry->path_len++] = '/';
|
|
1293
|
+
|
|
1294
|
+
entry->path[entry->path_len] = '\0';
|
|
1295
|
+
|
|
1296
|
+
return entry;
|
|
1236
1297
|
}
|
|
1237
1298
|
|
|
1238
|
-
static int
|
|
1299
|
+
static int filesystem_iterator_frame_push(
|
|
1300
|
+
filesystem_iterator *iter,
|
|
1301
|
+
filesystem_iterator_entry *frame_entry)
|
|
1239
1302
|
{
|
|
1303
|
+
filesystem_iterator_frame *new_frame = NULL;
|
|
1240
1304
|
git_path_diriter diriter = GIT_PATH_DIRITER_INIT;
|
|
1305
|
+
git_buf root = GIT_BUF_INIT;
|
|
1241
1306
|
const char *path;
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
size_t path_len, cmp_len, ps_size;
|
|
1246
|
-
iterator_pathlist__match_t pathlist_match = ITERATOR_PATHLIST_MATCH;
|
|
1307
|
+
filesystem_iterator_entry *entry;
|
|
1308
|
+
struct stat statbuf;
|
|
1309
|
+
size_t path_len;
|
|
1247
1310
|
int error;
|
|
1248
1311
|
|
|
1312
|
+
if (iter->frames.size == FILESYSTEM_MAX_DEPTH) {
|
|
1313
|
+
giterr_set(GITERR_REPOSITORY,
|
|
1314
|
+
"directory nesting too deep (%d)", iter->frames.size);
|
|
1315
|
+
return -1;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
new_frame = git_array_alloc(iter->frames);
|
|
1319
|
+
GITERR_CHECK_ALLOC(new_frame);
|
|
1320
|
+
|
|
1321
|
+
memset(new_frame, 0, sizeof(filesystem_iterator_frame));
|
|
1322
|
+
|
|
1323
|
+
if (frame_entry)
|
|
1324
|
+
git_buf_joinpath(&root, iter->root, frame_entry->path);
|
|
1325
|
+
else
|
|
1326
|
+
git_buf_puts(&root, iter->root);
|
|
1327
|
+
|
|
1328
|
+
if (git_buf_oom(&root)) {
|
|
1329
|
+
error = -1;
|
|
1330
|
+
goto done;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
new_frame->path_len = frame_entry ? frame_entry->path_len : 0;
|
|
1334
|
+
|
|
1249
1335
|
/* Any error here is equivalent to the dir not existing, skip over it */
|
|
1250
1336
|
if ((error = git_path_diriter_init(
|
|
1251
|
-
&diriter,
|
|
1337
|
+
&diriter, root.ptr, iter->dirload_flags)) < 0) {
|
|
1252
1338
|
error = GIT_ENOTFOUND;
|
|
1253
1339
|
goto done;
|
|
1254
1340
|
}
|
|
1255
1341
|
|
|
1342
|
+
if ((error = git_vector_init(&new_frame->entries, 64,
|
|
1343
|
+
iterator__ignore_case(&iter->base) ?
|
|
1344
|
+
filesystem_iterator_entry_cmp_icase :
|
|
1345
|
+
filesystem_iterator_entry_cmp)) < 0)
|
|
1346
|
+
goto done;
|
|
1347
|
+
|
|
1348
|
+
git_pool_init(&new_frame->entry_pool, 1);
|
|
1349
|
+
|
|
1350
|
+
/* check if this directory is ignored */
|
|
1351
|
+
filesystem_iterator_frame_push_ignores(iter, frame_entry, new_frame);
|
|
1352
|
+
|
|
1256
1353
|
while ((error = git_path_diriter_next(&diriter)) == 0) {
|
|
1354
|
+
iterator_pathlist_search_t pathlist_match = ITERATOR_PATHLIST_FULL;
|
|
1355
|
+
bool dir_expected = false;
|
|
1356
|
+
|
|
1257
1357
|
if ((error = git_path_diriter_fullpath(&path, &path_len, &diriter)) < 0)
|
|
1258
1358
|
goto done;
|
|
1259
1359
|
|
|
1260
|
-
assert(path_len >
|
|
1360
|
+
assert(path_len > iter->root_len);
|
|
1261
1361
|
|
|
1262
1362
|
/* remove the prefix if requested */
|
|
1263
|
-
path +=
|
|
1264
|
-
path_len -=
|
|
1265
|
-
|
|
1266
|
-
/* skip if before start_stat or after end_stat */
|
|
1267
|
-
cmp_len = min(start_len, path_len);
|
|
1268
|
-
if (cmp_len && fi->base.strncomp(path, fi->base.start, cmp_len) < 0)
|
|
1269
|
-
continue;
|
|
1270
|
-
/* skip if after end_stat */
|
|
1271
|
-
cmp_len = min(end_len, path_len);
|
|
1272
|
-
if (cmp_len && fi->base.strncomp(path, fi->base.end, cmp_len) > 0)
|
|
1273
|
-
continue;
|
|
1363
|
+
path += iter->root_len;
|
|
1364
|
+
path_len -= iter->root_len;
|
|
1274
1365
|
|
|
1275
|
-
/*
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
1278
|
-
*
|
|
1279
|
-
* this path or children of this path.
|
|
1366
|
+
/* examine start / end and the pathlist to see if this path is in it.
|
|
1367
|
+
* note that since we haven't yet stat'ed the path, we cannot know
|
|
1368
|
+
* whether it's a directory yet or not, so this can give us an
|
|
1369
|
+
* expected type (S_IFDIR or S_IFREG) that we should examine)
|
|
1280
1370
|
*/
|
|
1281
|
-
if (
|
|
1282
|
-
|
|
1283
|
-
fi->pathlist_match != ITERATOR_PATHLIST_MATCH_DIRECTORY &&
|
|
1284
|
-
!(pathlist_match = iterator_pathlist__match(&fi->base, path, path_len)))
|
|
1371
|
+
if (!filesystem_iterator_examine_path(&dir_expected, &pathlist_match,
|
|
1372
|
+
iter, frame_entry, path, path_len))
|
|
1285
1373
|
continue;
|
|
1286
1374
|
|
|
1287
|
-
/*
|
|
1288
|
-
*
|
|
1375
|
+
/* TODO: don't need to stat if assume unchanged for this path and
|
|
1376
|
+
* we have an index, we can just copy the data out of it.
|
|
1289
1377
|
*/
|
|
1290
|
-
GITERR_CHECK_ALLOC_ADD(&ps_size, sizeof(fs_iterator_path_with_stat), path_len);
|
|
1291
|
-
GITERR_CHECK_ALLOC_ADD(&ps_size, ps_size, 2);
|
|
1292
1378
|
|
|
1293
|
-
|
|
1294
|
-
|
|
1379
|
+
if ((error = git_path_diriter_stat(&statbuf, &diriter)) < 0) {
|
|
1380
|
+
/* file was removed between readdir and lstat */
|
|
1381
|
+
if (error == GIT_ENOTFOUND)
|
|
1382
|
+
continue;
|
|
1295
1383
|
|
|
1296
|
-
|
|
1384
|
+
/* treat the file as unreadable */
|
|
1385
|
+
memset(&statbuf, 0, sizeof(statbuf));
|
|
1386
|
+
statbuf.st_mode = GIT_FILEMODE_UNREADABLE;
|
|
1297
1387
|
|
|
1298
|
-
|
|
1388
|
+
error = 0;
|
|
1389
|
+
}
|
|
1299
1390
|
|
|
1300
|
-
|
|
1301
|
-
if (error == GIT_ENOTFOUND) {
|
|
1302
|
-
/* file was removed between readdir and lstat */
|
|
1303
|
-
git__free(ps);
|
|
1304
|
-
continue;
|
|
1305
|
-
}
|
|
1391
|
+
iter->base.stat_calls++;
|
|
1306
1392
|
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
/* Treat the file as unreadable if we get any other error */
|
|
1314
|
-
memset(&ps->st, 0, sizeof(ps->st));
|
|
1315
|
-
ps->st.st_mode = GIT_FILEMODE_UNREADABLE;
|
|
1393
|
+
/* Ignore wacky things in the filesystem */
|
|
1394
|
+
if (!S_ISDIR(statbuf.st_mode) &&
|
|
1395
|
+
!S_ISREG(statbuf.st_mode) &&
|
|
1396
|
+
!S_ISLNK(statbuf.st_mode) &&
|
|
1397
|
+
statbuf.st_mode != GIT_FILEMODE_UNREADABLE)
|
|
1398
|
+
continue;
|
|
1316
1399
|
|
|
1317
|
-
|
|
1318
|
-
error = 0;
|
|
1319
|
-
} else if (S_ISDIR(ps->st.st_mode)) {
|
|
1320
|
-
/* Suffix directory paths with a '/' */
|
|
1321
|
-
ps->path[ps->path_len++] = '/';
|
|
1322
|
-
ps->path[ps->path_len] = '\0';
|
|
1323
|
-
} else if(!S_ISREG(ps->st.st_mode) && !S_ISLNK(ps->st.st_mode)) {
|
|
1324
|
-
/* Ignore wacky things in the filesystem */
|
|
1325
|
-
git__free(ps);
|
|
1400
|
+
if (filesystem_iterator_is_dot_git(iter, path, path_len))
|
|
1326
1401
|
continue;
|
|
1402
|
+
|
|
1403
|
+
/* convert submodules to GITLINK and remove trailing slashes */
|
|
1404
|
+
if (S_ISDIR(statbuf.st_mode)) {
|
|
1405
|
+
bool submodule = false;
|
|
1406
|
+
|
|
1407
|
+
if ((error = filesystem_iterator_is_submodule(&submodule,
|
|
1408
|
+
iter, path, path_len)) < 0)
|
|
1409
|
+
goto done;
|
|
1410
|
+
|
|
1411
|
+
if (submodule)
|
|
1412
|
+
statbuf.st_mode = GIT_FILEMODE_COMMIT;
|
|
1327
1413
|
}
|
|
1328
1414
|
|
|
1329
|
-
/*
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1415
|
+
/* Ensure that the pathlist entry lines up with what we expected */
|
|
1416
|
+
else if (dir_expected)
|
|
1417
|
+
continue;
|
|
1418
|
+
|
|
1419
|
+
entry = filesystem_iterator_entry_init(new_frame,
|
|
1420
|
+
path, path_len, &statbuf, pathlist_match);
|
|
1421
|
+
GITERR_CHECK_ALLOC(entry);
|
|
1422
|
+
|
|
1423
|
+
git_vector_insert(&new_frame->entries, entry);
|
|
1335
1424
|
}
|
|
1336
1425
|
|
|
1337
1426
|
if (error == GIT_ITEROVER)
|
|
1338
1427
|
error = 0;
|
|
1339
1428
|
|
|
1340
1429
|
/* sort now that directory suffix is added */
|
|
1341
|
-
git_vector_sort(
|
|
1430
|
+
git_vector_sort(&new_frame->entries);
|
|
1342
1431
|
|
|
1343
1432
|
done:
|
|
1433
|
+
if (error < 0)
|
|
1434
|
+
git_array_pop(iter->frames);
|
|
1435
|
+
|
|
1436
|
+
git_buf_free(&root);
|
|
1344
1437
|
git_path_diriter_free(&diriter);
|
|
1345
1438
|
return error;
|
|
1346
1439
|
}
|
|
1347
1440
|
|
|
1348
|
-
|
|
1349
|
-
static int fs_iterator__expand_dir(fs_iterator *fi)
|
|
1441
|
+
GIT_INLINE(void) filesystem_iterator_frame_pop(filesystem_iterator *iter)
|
|
1350
1442
|
{
|
|
1351
|
-
|
|
1352
|
-
fs_iterator_frame *ff;
|
|
1353
|
-
|
|
1354
|
-
if (fi->depth > FS_MAX_DEPTH) {
|
|
1355
|
-
giterr_set(GITERR_REPOSITORY,
|
|
1356
|
-
"Directory nesting is too deep (%d)", fi->depth);
|
|
1357
|
-
return -1;
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
ff = fs_iterator__alloc_frame(fi);
|
|
1361
|
-
GITERR_CHECK_ALLOC(ff);
|
|
1443
|
+
filesystem_iterator_frame *frame;
|
|
1362
1444
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
if (error < 0) {
|
|
1366
|
-
git_error_state last_error = { 0 };
|
|
1367
|
-
giterr_state_capture(&last_error, error);
|
|
1445
|
+
assert(iter->frames.size);
|
|
1368
1446
|
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
fs_iterator__advance_over(NULL, (git_iterator *)fi);
|
|
1372
|
-
/* next time return value we skipped to */
|
|
1373
|
-
fi->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
|
|
1447
|
+
frame = git_array_pop(iter->frames);
|
|
1448
|
+
filesystem_iterator_frame_pop_ignores(iter);
|
|
1374
1449
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1450
|
+
git_pool_clear(&frame->entry_pool);
|
|
1451
|
+
git_vector_free(&frame->entries);
|
|
1452
|
+
}
|
|
1377
1453
|
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1454
|
+
static void filesystem_iterator_set_current(
|
|
1455
|
+
filesystem_iterator *iter,
|
|
1456
|
+
filesystem_iterator_entry *entry)
|
|
1457
|
+
{
|
|
1458
|
+
iter->entry.ctime.seconds = entry->st.st_ctime;
|
|
1459
|
+
iter->entry.ctime.nanoseconds = entry->st.st_ctime_nsec;
|
|
1383
1460
|
|
|
1384
|
-
|
|
1461
|
+
iter->entry.mtime.seconds = entry->st.st_mtime;
|
|
1462
|
+
iter->entry.mtime.nanoseconds = entry->st.st_mtime_nsec;
|
|
1385
1463
|
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1464
|
+
iter->entry.dev = entry->st.st_dev;
|
|
1465
|
+
iter->entry.ino = entry->st.st_ino;
|
|
1466
|
+
iter->entry.mode = git_futils_canonical_mode(entry->st.st_mode);
|
|
1467
|
+
iter->entry.uid = entry->st.st_uid;
|
|
1468
|
+
iter->entry.gid = entry->st.st_gid;
|
|
1469
|
+
iter->entry.file_size = entry->st.st_size;
|
|
1389
1470
|
|
|
1390
|
-
|
|
1391
|
-
return error;
|
|
1471
|
+
iter->entry.path = entry->path;
|
|
1392
1472
|
|
|
1393
|
-
|
|
1473
|
+
iter->current_is_ignored = GIT_IGNORE_UNCHECKED;
|
|
1394
1474
|
}
|
|
1395
1475
|
|
|
1396
|
-
static int
|
|
1397
|
-
const git_index_entry **
|
|
1476
|
+
static int filesystem_iterator_current(
|
|
1477
|
+
const git_index_entry **out, git_iterator *i)
|
|
1398
1478
|
{
|
|
1399
|
-
|
|
1400
|
-
const git_index_entry *fe = (fi->entry.path == NULL) ? NULL : &fi->entry;
|
|
1479
|
+
filesystem_iterator *iter = (filesystem_iterator *)i;
|
|
1401
1480
|
|
|
1402
|
-
if (
|
|
1403
|
-
|
|
1481
|
+
if (!iterator__has_been_accessed(i))
|
|
1482
|
+
return iter->base.cb->advance(out, i);
|
|
1404
1483
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
}
|
|
1484
|
+
if (!iter->frames.size) {
|
|
1485
|
+
*out = NULL;
|
|
1486
|
+
return GIT_ITEROVER;
|
|
1487
|
+
}
|
|
1409
1488
|
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
return (((fs_iterator *)self)->entry.path == NULL);
|
|
1489
|
+
*out = &iter->entry;
|
|
1490
|
+
return 0;
|
|
1413
1491
|
}
|
|
1414
1492
|
|
|
1415
|
-
static int
|
|
1416
|
-
const git_index_entry **
|
|
1493
|
+
static int filesystem_iterator_advance(
|
|
1494
|
+
const git_index_entry **out, git_iterator *i)
|
|
1417
1495
|
{
|
|
1496
|
+
filesystem_iterator *iter = (filesystem_iterator *)i;
|
|
1418
1497
|
int error = 0;
|
|
1419
|
-
fs_iterator *fi = (fs_iterator *)iter;
|
|
1420
1498
|
|
|
1421
|
-
|
|
1499
|
+
iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS;
|
|
1422
1500
|
|
|
1423
|
-
/*
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
*/
|
|
1428
|
-
if (fi->entry.path != NULL &&
|
|
1429
|
-
(fi->entry.mode == GIT_FILEMODE_TREE ||
|
|
1430
|
-
fi->entry.mode == GIT_FILEMODE_COMMIT))
|
|
1431
|
-
/* returns GIT_ENOTFOUND if the directory is empty */
|
|
1432
|
-
error = fs_iterator__expand_dir(fi);
|
|
1501
|
+
/* examine filesystem entries until we find the next one to return */
|
|
1502
|
+
while (true) {
|
|
1503
|
+
filesystem_iterator_frame *frame;
|
|
1504
|
+
filesystem_iterator_entry *entry;
|
|
1433
1505
|
|
|
1434
|
-
|
|
1435
|
-
|
|
1506
|
+
if ((frame = filesystem_iterator_current_frame(iter)) == NULL) {
|
|
1507
|
+
error = GIT_ITEROVER;
|
|
1508
|
+
break;
|
|
1509
|
+
}
|
|
1436
1510
|
|
|
1437
|
-
|
|
1438
|
-
|
|
1511
|
+
/* no more entries in this frame. pop the frame out */
|
|
1512
|
+
if (frame->next_idx == frame->entries.length) {
|
|
1513
|
+
filesystem_iterator_frame_pop(iter);
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1439
1516
|
|
|
1440
|
-
|
|
1441
|
-
|
|
1517
|
+
/* we have more entries in the current frame, that's our next entry */
|
|
1518
|
+
entry = frame->entries.contents[frame->next_idx];
|
|
1519
|
+
frame->next_idx++;
|
|
1442
1520
|
|
|
1443
|
-
|
|
1444
|
-
{
|
|
1445
|
-
|
|
1446
|
-
fs_iterator_frame *ff;
|
|
1447
|
-
fs_iterator_path_with_stat *next;
|
|
1521
|
+
if (S_ISDIR(entry->st.st_mode)) {
|
|
1522
|
+
if (iterator__do_autoexpand(iter)) {
|
|
1523
|
+
error = filesystem_iterator_frame_push(iter, entry);
|
|
1448
1524
|
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1525
|
+
/* may get GIT_ENOTFOUND due to races or permission problems
|
|
1526
|
+
* that we want to quietly swallow
|
|
1527
|
+
*/
|
|
1528
|
+
if (error == GIT_ENOTFOUND)
|
|
1529
|
+
continue;
|
|
1530
|
+
else if (error < 0)
|
|
1531
|
+
break;
|
|
1532
|
+
}
|
|
1452
1533
|
|
|
1453
|
-
|
|
1454
|
-
|
|
1534
|
+
if (!iterator__include_trees(iter))
|
|
1535
|
+
continue;
|
|
1536
|
+
}
|
|
1455
1537
|
|
|
1456
|
-
|
|
1538
|
+
filesystem_iterator_set_current(iter, entry);
|
|
1539
|
+
break;
|
|
1457
1540
|
}
|
|
1541
|
+
|
|
1542
|
+
if (out)
|
|
1543
|
+
*out = (error == 0) ? &iter->entry : NULL;
|
|
1544
|
+
|
|
1545
|
+
return error;
|
|
1458
1546
|
}
|
|
1459
1547
|
|
|
1460
|
-
static int
|
|
1461
|
-
const git_index_entry **
|
|
1548
|
+
static int filesystem_iterator_advance_into(
|
|
1549
|
+
const git_index_entry **out, git_iterator *i)
|
|
1462
1550
|
{
|
|
1551
|
+
filesystem_iterator *iter = (filesystem_iterator *)i;
|
|
1552
|
+
filesystem_iterator_frame *frame;
|
|
1553
|
+
filesystem_iterator_entry *prev_entry;
|
|
1463
1554
|
int error;
|
|
1464
1555
|
|
|
1465
|
-
if (
|
|
1466
|
-
*
|
|
1556
|
+
if (out)
|
|
1557
|
+
*out = NULL;
|
|
1558
|
+
|
|
1559
|
+
if ((frame = filesystem_iterator_current_frame(iter)) == NULL)
|
|
1560
|
+
return GIT_ITEROVER;
|
|
1561
|
+
|
|
1562
|
+
/* get the last seen entry */
|
|
1563
|
+
prev_entry = filesystem_iterator_current_entry(frame);
|
|
1467
1564
|
|
|
1468
|
-
|
|
1565
|
+
/* it's legal to call advance_into when auto-expand is on. in this case,
|
|
1566
|
+
* we will have pushed a new (empty) frame on to the stack for this
|
|
1567
|
+
* new directory. since it's empty, its current_entry should be null.
|
|
1568
|
+
*/
|
|
1569
|
+
assert(iterator__do_autoexpand(i) ^ (prev_entry != NULL));
|
|
1469
1570
|
|
|
1470
|
-
|
|
1571
|
+
if (prev_entry) {
|
|
1572
|
+
if (prev_entry->st.st_mode != GIT_FILEMODE_COMMIT &&
|
|
1573
|
+
!S_ISDIR(prev_entry->st.st_mode))
|
|
1574
|
+
return 0;
|
|
1471
1575
|
|
|
1472
|
-
|
|
1473
|
-
|
|
1576
|
+
if ((error = filesystem_iterator_frame_push(iter, prev_entry)) < 0)
|
|
1577
|
+
return error;
|
|
1578
|
+
}
|
|
1474
1579
|
|
|
1475
|
-
|
|
1580
|
+
/* we've advanced into the directory in question, let advance
|
|
1581
|
+
* find the first entry
|
|
1582
|
+
*/
|
|
1583
|
+
return filesystem_iterator_advance(out, i);
|
|
1476
1584
|
}
|
|
1477
1585
|
|
|
1478
|
-
|
|
1479
|
-
const git_index_entry **entry, git_iterator *self)
|
|
1586
|
+
int git_iterator_current_workdir_path(git_buf **out, git_iterator *i)
|
|
1480
1587
|
{
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
if (!iterator__has_been_accessed(fi))
|
|
1484
|
-
return fs_iterator__current(entry, self);
|
|
1588
|
+
filesystem_iterator *iter = (filesystem_iterator *)i;
|
|
1589
|
+
const git_index_entry *entry;
|
|
1485
1590
|
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
{
|
|
1491
|
-
int error = fs_iterator__advance_into(entry, self);
|
|
1492
|
-
if (error != GIT_ENOTFOUND)
|
|
1493
|
-
return error;
|
|
1494
|
-
/* continue silently past empty directories if autoexpanding */
|
|
1495
|
-
giterr_clear();
|
|
1591
|
+
if (i->type != GIT_ITERATOR_TYPE_FS &&
|
|
1592
|
+
i->type != GIT_ITERATOR_TYPE_WORKDIR) {
|
|
1593
|
+
*out = NULL;
|
|
1594
|
+
return 0;
|
|
1496
1595
|
}
|
|
1497
1596
|
|
|
1498
|
-
|
|
1597
|
+
git_buf_truncate(&iter->current_path, iter->root_len);
|
|
1598
|
+
|
|
1599
|
+
if (git_iterator_current(&entry, i) < 0 ||
|
|
1600
|
+
git_buf_puts(&iter->current_path, entry->path) < 0)
|
|
1601
|
+
return -1;
|
|
1602
|
+
|
|
1603
|
+
*out = &iter->current_path;
|
|
1604
|
+
return 0;
|
|
1499
1605
|
}
|
|
1500
1606
|
|
|
1501
|
-
|
|
1607
|
+
GIT_INLINE(git_dir_flag) entry_dir_flag(git_index_entry *entry)
|
|
1502
1608
|
{
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1609
|
+
#if defined(GIT_WIN32) && !defined(__MINGW32__)
|
|
1610
|
+
return (entry && entry->mode) ?
|
|
1611
|
+
(S_ISDIR(entry->mode) ? GIT_DIR_FLAG_TRUE : GIT_DIR_FLAG_FALSE) :
|
|
1612
|
+
GIT_DIR_FLAG_UNKNOWN;
|
|
1613
|
+
#else
|
|
1614
|
+
GIT_UNUSED(entry);
|
|
1615
|
+
return GIT_DIR_FLAG_UNKNOWN;
|
|
1616
|
+
#endif
|
|
1509
1617
|
}
|
|
1510
1618
|
|
|
1511
|
-
static
|
|
1512
|
-
git_iterator *self, const char *start, const char *end)
|
|
1619
|
+
static void filesystem_iterator_update_ignored(filesystem_iterator *iter)
|
|
1513
1620
|
{
|
|
1514
|
-
|
|
1515
|
-
|
|
1621
|
+
filesystem_iterator_frame *frame;
|
|
1622
|
+
git_dir_flag dir_flag = entry_dir_flag(&iter->entry);
|
|
1516
1623
|
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1624
|
+
if (git_ignore__lookup(&iter->current_is_ignored,
|
|
1625
|
+
&iter->ignores, iter->entry.path, dir_flag) < 0) {
|
|
1626
|
+
giterr_clear();
|
|
1627
|
+
iter->current_is_ignored = GIT_IGNORE_NOTFOUND;
|
|
1628
|
+
}
|
|
1520
1629
|
|
|
1521
|
-
|
|
1522
|
-
|
|
1630
|
+
/* use ignore from containing frame stack */
|
|
1631
|
+
if (iter->current_is_ignored <= GIT_IGNORE_NOTFOUND) {
|
|
1632
|
+
frame = filesystem_iterator_current_frame(iter);
|
|
1633
|
+
iter->current_is_ignored = frame->is_ignored;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1523
1636
|
|
|
1524
|
-
|
|
1637
|
+
GIT_INLINE(bool) filesystem_iterator_current_is_ignored(
|
|
1638
|
+
filesystem_iterator *iter)
|
|
1639
|
+
{
|
|
1640
|
+
if (iter->current_is_ignored == GIT_IGNORE_UNCHECKED)
|
|
1641
|
+
filesystem_iterator_update_ignored(iter);
|
|
1525
1642
|
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
error = 0;
|
|
1643
|
+
return (iter->current_is_ignored == GIT_IGNORE_TRUE);
|
|
1644
|
+
}
|
|
1529
1645
|
|
|
1530
|
-
|
|
1646
|
+
bool git_iterator_current_is_ignored(git_iterator *i)
|
|
1647
|
+
{
|
|
1648
|
+
if (i->type != GIT_ITERATOR_TYPE_WORKDIR)
|
|
1649
|
+
return false;
|
|
1650
|
+
|
|
1651
|
+
return filesystem_iterator_current_is_ignored((filesystem_iterator *)i);
|
|
1531
1652
|
}
|
|
1532
1653
|
|
|
1533
|
-
|
|
1654
|
+
bool git_iterator_current_tree_is_ignored(git_iterator *i)
|
|
1534
1655
|
{
|
|
1535
|
-
|
|
1656
|
+
filesystem_iterator *iter = (filesystem_iterator *)i;
|
|
1657
|
+
filesystem_iterator_frame *frame;
|
|
1536
1658
|
|
|
1537
|
-
|
|
1538
|
-
|
|
1659
|
+
if (i->type != GIT_ITERATOR_TYPE_WORKDIR)
|
|
1660
|
+
return false;
|
|
1539
1661
|
|
|
1540
|
-
|
|
1662
|
+
frame = filesystem_iterator_current_frame(iter);
|
|
1663
|
+
return (frame->is_ignored == GIT_IGNORE_TRUE);
|
|
1541
1664
|
}
|
|
1542
1665
|
|
|
1543
|
-
static int
|
|
1666
|
+
static int filesystem_iterator_advance_over(
|
|
1667
|
+
const git_index_entry **out,
|
|
1668
|
+
git_iterator_status_t *status,
|
|
1669
|
+
git_iterator *i)
|
|
1544
1670
|
{
|
|
1545
|
-
|
|
1671
|
+
filesystem_iterator *iter = (filesystem_iterator *)i;
|
|
1672
|
+
filesystem_iterator_frame *current_frame;
|
|
1673
|
+
filesystem_iterator_entry *current_entry;
|
|
1674
|
+
const git_index_entry *entry = NULL;
|
|
1675
|
+
const char *base;
|
|
1676
|
+
int error = 0;
|
|
1546
1677
|
|
|
1547
|
-
|
|
1548
|
-
|
|
1678
|
+
*out = NULL;
|
|
1679
|
+
*status = GIT_ITERATOR_STATUS_NORMAL;
|
|
1549
1680
|
|
|
1550
|
-
|
|
1551
|
-
return GIT_ITEROVER;
|
|
1681
|
+
assert(iterator__has_been_accessed(i));
|
|
1552
1682
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1683
|
+
current_frame = filesystem_iterator_current_frame(iter);
|
|
1684
|
+
assert(current_frame);
|
|
1685
|
+
current_entry = filesystem_iterator_current_entry(current_frame);
|
|
1686
|
+
assert(current_entry);
|
|
1556
1687
|
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
return -1;
|
|
1688
|
+
if ((error = git_iterator_current(&entry, i)) < 0)
|
|
1689
|
+
return error;
|
|
1560
1690
|
|
|
1561
|
-
|
|
1562
|
-
|
|
1691
|
+
if (!S_ISDIR(entry->mode)) {
|
|
1692
|
+
if (filesystem_iterator_current_is_ignored(iter))
|
|
1693
|
+
*status = GIT_ITERATOR_STATUS_IGNORED;
|
|
1563
1694
|
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
git_index_entry__init_from_stat(&fi->entry, &ps->st, true);
|
|
1695
|
+
return filesystem_iterator_advance(out, i);
|
|
1696
|
+
}
|
|
1567
1697
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1698
|
+
git_buf_clear(&iter->tmp_buf);
|
|
1699
|
+
if ((error = git_buf_puts(&iter->tmp_buf, entry->path)) < 0)
|
|
1700
|
+
return error;
|
|
1570
1701
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1702
|
+
base = iter->tmp_buf.ptr;
|
|
1703
|
+
|
|
1704
|
+
/* scan inside the directory looking for files. if we find nothing,
|
|
1705
|
+
* we will remain EMPTY. if we find any ignored item, upgrade EMPTY to
|
|
1706
|
+
* IGNORED. if we find a real actual item, upgrade all the way to NORMAL
|
|
1707
|
+
* and then stop.
|
|
1708
|
+
*
|
|
1709
|
+
* however, if we're here looking for a pathlist item (but are not
|
|
1710
|
+
* actually in the pathlist ourselves) then start at FILTERED instead of
|
|
1711
|
+
* EMPTY. callers then know that this path was not something they asked
|
|
1712
|
+
* about.
|
|
1713
|
+
*/
|
|
1714
|
+
*status = current_entry->match == ITERATOR_PATHLIST_IS_PARENT ?
|
|
1715
|
+
GIT_ITERATOR_STATUS_FILTERED : GIT_ITERATOR_STATUS_EMPTY;
|
|
1716
|
+
|
|
1717
|
+
while (entry && !iter->base.prefixcomp(entry->path, base)) {
|
|
1718
|
+
if (filesystem_iterator_current_is_ignored(iter)) {
|
|
1719
|
+
/* if we found an explicitly ignored item, then update from
|
|
1720
|
+
* EMPTY to IGNORED
|
|
1721
|
+
*/
|
|
1722
|
+
*status = GIT_ITERATOR_STATUS_IGNORED;
|
|
1723
|
+
} else if (S_ISDIR(entry->mode)) {
|
|
1724
|
+
error = filesystem_iterator_advance_into(&entry, i);
|
|
1577
1725
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
int error = fs_iterator__advance_into(NULL, &fi->base);
|
|
1726
|
+
if (!error)
|
|
1727
|
+
continue;
|
|
1581
1728
|
|
|
1582
|
-
|
|
1583
|
-
|
|
1729
|
+
/* this directory disappeared, ignore it */
|
|
1730
|
+
else if (error == GIT_ENOTFOUND)
|
|
1731
|
+
error = 0;
|
|
1584
1732
|
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1733
|
+
/* a real error occurred */
|
|
1734
|
+
else
|
|
1735
|
+
break;
|
|
1736
|
+
} else {
|
|
1737
|
+
/* we found a non-ignored item, treat parent as untracked */
|
|
1738
|
+
*status = GIT_ITERATOR_STATUS_NORMAL;
|
|
1739
|
+
break;
|
|
1588
1740
|
}
|
|
1589
1741
|
|
|
1590
|
-
|
|
1742
|
+
if ((error = git_iterator_advance(&entry, i)) < 0)
|
|
1743
|
+
break;
|
|
1591
1744
|
}
|
|
1592
1745
|
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
git_iterator **out, fs_iterator *fi, const char *root)
|
|
1598
|
-
{
|
|
1599
|
-
int error;
|
|
1600
|
-
|
|
1601
|
-
if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) {
|
|
1602
|
-
git__free(fi);
|
|
1603
|
-
return -1;
|
|
1746
|
+
/* wrap up scan back to base directory */
|
|
1747
|
+
while (entry && !iter->base.prefixcomp(entry->path, base)) {
|
|
1748
|
+
if ((error = git_iterator_advance(&entry, i)) < 0)
|
|
1749
|
+
break;
|
|
1604
1750
|
}
|
|
1605
|
-
fi->root_len = fi->path.size;
|
|
1606
|
-
fi->pathlist_match = ITERATOR_PATHLIST_MATCH_CHILD;
|
|
1607
|
-
|
|
1608
|
-
fi->dirload_flags =
|
|
1609
|
-
(iterator__ignore_case(fi) ? GIT_PATH_DIR_IGNORE_CASE : 0) |
|
|
1610
|
-
(iterator__flag(fi, PRECOMPOSE_UNICODE) ?
|
|
1611
|
-
GIT_PATH_DIR_PRECOMPOSE_UNICODE : 0);
|
|
1612
1751
|
|
|
1613
|
-
if (
|
|
1614
|
-
|
|
1615
|
-
giterr_clear();
|
|
1616
|
-
error = 0;
|
|
1617
|
-
} else {
|
|
1618
|
-
git_iterator_free((git_iterator *)fi);
|
|
1619
|
-
fi = NULL;
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1752
|
+
if (!error)
|
|
1753
|
+
*out = entry;
|
|
1622
1754
|
|
|
1623
|
-
*out = (git_iterator *)fi;
|
|
1624
1755
|
return error;
|
|
1625
1756
|
}
|
|
1626
1757
|
|
|
1627
|
-
|
|
1628
|
-
git_iterator **out,
|
|
1629
|
-
const char *root,
|
|
1630
|
-
git_iterator_options *options)
|
|
1758
|
+
static void filesystem_iterator_clear(filesystem_iterator *iter)
|
|
1631
1759
|
{
|
|
1632
|
-
|
|
1633
|
-
|
|
1760
|
+
while (iter->frames.size)
|
|
1761
|
+
filesystem_iterator_frame_pop(iter);
|
|
1634
1762
|
|
|
1635
|
-
|
|
1763
|
+
git_array_clear(iter->frames);
|
|
1764
|
+
git_ignore__free(&iter->ignores);
|
|
1636
1765
|
|
|
1637
|
-
|
|
1638
|
-
fi->base.flags |= GIT_ITERATOR_IGNORE_CASE;
|
|
1766
|
+
git_buf_free(&iter->tmp_buf);
|
|
1639
1767
|
|
|
1640
|
-
|
|
1768
|
+
iterator_clear(&iter->base);
|
|
1641
1769
|
}
|
|
1642
1770
|
|
|
1643
|
-
|
|
1644
|
-
typedef struct {
|
|
1645
|
-
fs_iterator fi;
|
|
1646
|
-
git_ignores ignores;
|
|
1647
|
-
int is_ignored;
|
|
1648
|
-
|
|
1649
|
-
/*
|
|
1650
|
-
* We may have a tree or the index+snapshot to compare against
|
|
1651
|
-
* when checking for submodules.
|
|
1652
|
-
*/
|
|
1653
|
-
git_tree *tree;
|
|
1654
|
-
git_index *index;
|
|
1655
|
-
git_vector index_snapshot;
|
|
1656
|
-
git_vector_cmp entry_srch;
|
|
1657
|
-
|
|
1658
|
-
} workdir_iterator;
|
|
1659
|
-
|
|
1660
|
-
GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path)
|
|
1771
|
+
static int filesystem_iterator_init(filesystem_iterator *iter)
|
|
1661
1772
|
{
|
|
1662
|
-
|
|
1773
|
+
int error;
|
|
1663
1774
|
|
|
1664
|
-
if (
|
|
1665
|
-
|
|
1775
|
+
if (iterator__honor_ignores(&iter->base) &&
|
|
1776
|
+
(error = git_ignore__for_path(iter->base.repo,
|
|
1777
|
+
".gitignore", &iter->ignores)) < 0)
|
|
1778
|
+
return error;
|
|
1666
1779
|
|
|
1667
|
-
if (
|
|
1668
|
-
|
|
1780
|
+
if ((error = filesystem_iterator_frame_push(iter, NULL)) < 0)
|
|
1781
|
+
return error;
|
|
1669
1782
|
|
|
1670
|
-
|
|
1671
|
-
git__tolower(path->ptr[len - 2]) != 'i' ||
|
|
1672
|
-
git__tolower(path->ptr[len - 3]) != 'g' ||
|
|
1673
|
-
git__tolower(path->ptr[len - 4]) != '.')
|
|
1674
|
-
return false;
|
|
1783
|
+
iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
|
|
1675
1784
|
|
|
1676
|
-
return
|
|
1785
|
+
return 0;
|
|
1677
1786
|
}
|
|
1678
1787
|
|
|
1679
|
-
|
|
1680
|
-
* Figure out if an entry is a submodule.
|
|
1681
|
-
*
|
|
1682
|
-
* We consider it a submodule if the path is listed as a submodule in
|
|
1683
|
-
* either the tree or the index.
|
|
1684
|
-
*/
|
|
1685
|
-
static int is_submodule(workdir_iterator *wi, fs_iterator_path_with_stat *ie)
|
|
1788
|
+
static int filesystem_iterator_reset(git_iterator *i)
|
|
1686
1789
|
{
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
if (wi->tree) {
|
|
1690
|
-
git_tree_entry *e;
|
|
1790
|
+
filesystem_iterator *iter = (filesystem_iterator *)i;
|
|
1691
1791
|
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
error = git_tree_entry_bypath(&e, wi->tree, ie->path);
|
|
1695
|
-
ie->path[ie->path_len-1] = '/';
|
|
1696
|
-
if (error < 0 && error != GIT_ENOTFOUND)
|
|
1697
|
-
return 0;
|
|
1698
|
-
if (!error) {
|
|
1699
|
-
is_submodule = e->attr == GIT_FILEMODE_COMMIT;
|
|
1700
|
-
git_tree_entry_free(e);
|
|
1701
|
-
}
|
|
1702
|
-
}
|
|
1703
|
-
|
|
1704
|
-
if (!is_submodule && wi->index) {
|
|
1705
|
-
git_index_entry *e;
|
|
1706
|
-
size_t pos;
|
|
1707
|
-
|
|
1708
|
-
error = git_index_snapshot_find(&pos, &wi->index_snapshot, wi->entry_srch, ie->path, ie->path_len-1, 0);
|
|
1709
|
-
if (error < 0 && error != GIT_ENOTFOUND)
|
|
1710
|
-
return 0;
|
|
1711
|
-
|
|
1712
|
-
if (!error) {
|
|
1713
|
-
e = git_vector_get(&wi->index_snapshot, pos);
|
|
1714
|
-
|
|
1715
|
-
is_submodule = e->mode == GIT_FILEMODE_COMMIT;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
|
-
return is_submodule;
|
|
1792
|
+
filesystem_iterator_clear(iter);
|
|
1793
|
+
return filesystem_iterator_init(iter);
|
|
1720
1794
|
}
|
|
1721
1795
|
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1796
|
+
static void filesystem_iterator_free(git_iterator *i)
|
|
1797
|
+
{
|
|
1798
|
+
filesystem_iterator *iter = (filesystem_iterator *)i;
|
|
1799
|
+
git__free(iter->root);
|
|
1800
|
+
git_buf_free(&iter->current_path);
|
|
1801
|
+
git_tree_free(iter->tree);
|
|
1802
|
+
if (iter->index)
|
|
1803
|
+
git_index_snapshot_release(&iter->index_snapshot, iter->index);
|
|
1804
|
+
filesystem_iterator_clear(iter);
|
|
1731
1805
|
}
|
|
1732
1806
|
|
|
1733
|
-
static int
|
|
1807
|
+
static int iterator_for_filesystem(
|
|
1808
|
+
git_iterator **out,
|
|
1809
|
+
git_repository *repo,
|
|
1810
|
+
const char *root,
|
|
1811
|
+
git_index *index,
|
|
1812
|
+
git_tree *tree,
|
|
1813
|
+
git_iterator_type_t type,
|
|
1814
|
+
git_iterator_options *options)
|
|
1734
1815
|
{
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
fs_iterator_path_with_stat *entry;
|
|
1739
|
-
bool found_submodules = false;
|
|
1816
|
+
filesystem_iterator *iter;
|
|
1817
|
+
size_t root_len;
|
|
1818
|
+
int error;
|
|
1740
1819
|
|
|
1741
|
-
|
|
1820
|
+
static git_iterator_callbacks callbacks = {
|
|
1821
|
+
filesystem_iterator_current,
|
|
1822
|
+
filesystem_iterator_advance,
|
|
1823
|
+
filesystem_iterator_advance_into,
|
|
1824
|
+
filesystem_iterator_advance_over,
|
|
1825
|
+
filesystem_iterator_reset,
|
|
1826
|
+
filesystem_iterator_free
|
|
1827
|
+
};
|
|
1742
1828
|
|
|
1743
|
-
|
|
1744
|
-
if (git_ignore__lookup(&ff->is_ignored, &wi->ignores, fi->path.ptr + fi->root_len, dir_flag) < 0) {
|
|
1745
|
-
giterr_clear();
|
|
1746
|
-
ff->is_ignored = GIT_IGNORE_NOTFOUND;
|
|
1747
|
-
}
|
|
1829
|
+
*out = NULL;
|
|
1748
1830
|
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/');
|
|
1831
|
+
if (root == NULL)
|
|
1832
|
+
return git_iterator_for_nothing(out, options);
|
|
1752
1833
|
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
ff->is_ignored = ff->next->is_ignored;
|
|
1834
|
+
iter = git__calloc(1, sizeof(filesystem_iterator));
|
|
1835
|
+
GITERR_CHECK_ALLOC(iter);
|
|
1756
1836
|
|
|
1757
|
-
|
|
1758
|
-
(void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]);
|
|
1759
|
-
}
|
|
1837
|
+
root_len = strlen(root);
|
|
1760
1838
|
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
if (!S_ISDIR(entry->st.st_mode) || !strcmp(GIT_DIR, entry->path))
|
|
1764
|
-
continue;
|
|
1839
|
+
iter->root = git__malloc(root_len+2);
|
|
1840
|
+
GITERR_CHECK_ALLOC(iter->root);
|
|
1765
1841
|
|
|
1766
|
-
|
|
1767
|
-
entry->st.st_mode = GIT_FILEMODE_COMMIT;
|
|
1768
|
-
entry->path_len--;
|
|
1769
|
-
entry->path[entry->path_len] = '\0';
|
|
1770
|
-
found_submodules = true;
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1842
|
+
memcpy(iter->root, root, root_len);
|
|
1773
1843
|
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
git_vector_sort(&ff->entries);
|
|
1778
|
-
fs_iterator__seek_frame_start(fi, ff);
|
|
1844
|
+
if (root_len == 0 || root[root_len-1] != '/') {
|
|
1845
|
+
iter->root[root_len] = '/';
|
|
1846
|
+
root_len++;
|
|
1779
1847
|
}
|
|
1848
|
+
iter->root[root_len] = '\0';
|
|
1849
|
+
iter->root_len = root_len;
|
|
1780
1850
|
|
|
1781
|
-
|
|
1782
|
-
|
|
1851
|
+
if ((error = git_buf_puts(&iter->current_path, iter->root)) < 0)
|
|
1852
|
+
goto on_error;
|
|
1783
1853
|
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
workdir_iterator *wi = (workdir_iterator *)fi;
|
|
1787
|
-
git_ignore__pop_dir(&wi->ignores);
|
|
1788
|
-
return 0;
|
|
1789
|
-
}
|
|
1854
|
+
iter->base.type = type;
|
|
1855
|
+
iter->base.cb = &callbacks;
|
|
1790
1856
|
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1857
|
+
if ((error = iterator_init_common(&iter->base, repo, index, options)) < 0)
|
|
1858
|
+
goto on_error;
|
|
1859
|
+
|
|
1860
|
+
if (tree && (error = git_tree_dup(&iter->tree, tree)) < 0)
|
|
1861
|
+
goto on_error;
|
|
1862
|
+
|
|
1863
|
+
if (index &&
|
|
1864
|
+
(error = git_index_snapshot_new(&iter->index_snapshot, index)) < 0)
|
|
1865
|
+
goto on_error;
|
|
1794
1866
|
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1867
|
+
iter->index = index;
|
|
1868
|
+
iter->dirload_flags =
|
|
1869
|
+
(iterator__ignore_case(&iter->base) ? GIT_PATH_DIR_IGNORE_CASE : 0) |
|
|
1870
|
+
(iterator__flag(&iter->base, PRECOMPOSE_UNICODE) ?
|
|
1871
|
+
GIT_PATH_DIR_PRECOMPOSE_UNICODE : 0);
|
|
1798
1872
|
|
|
1799
|
-
|
|
1800
|
-
|
|
1873
|
+
if ((error = filesystem_iterator_init(iter)) < 0)
|
|
1874
|
+
goto on_error;
|
|
1801
1875
|
|
|
1876
|
+
*out = &iter->base;
|
|
1802
1877
|
return 0;
|
|
1878
|
+
|
|
1879
|
+
on_error:
|
|
1880
|
+
git__free(iter->root);
|
|
1881
|
+
git_buf_free(&iter->current_path);
|
|
1882
|
+
git_iterator_free(&iter->base);
|
|
1883
|
+
return error;
|
|
1803
1884
|
}
|
|
1804
1885
|
|
|
1805
|
-
|
|
1886
|
+
int git_iterator_for_filesystem(
|
|
1887
|
+
git_iterator **out,
|
|
1888
|
+
const char *root,
|
|
1889
|
+
git_iterator_options *options)
|
|
1806
1890
|
{
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
git_index_snapshot_release(&wi->index_snapshot, wi->index);
|
|
1810
|
-
git_tree_free(wi->tree);
|
|
1811
|
-
fs_iterator__free(self);
|
|
1812
|
-
git_ignore__free(&wi->ignores);
|
|
1891
|
+
return iterator_for_filesystem(out,
|
|
1892
|
+
NULL, root, NULL, NULL, GIT_ITERATOR_TYPE_FS, options);
|
|
1813
1893
|
}
|
|
1814
1894
|
|
|
1815
1895
|
int git_iterator_for_workdir_ext(
|
|
@@ -1818,299 +1898,326 @@ int git_iterator_for_workdir_ext(
|
|
|
1818
1898
|
const char *repo_workdir,
|
|
1819
1899
|
git_index *index,
|
|
1820
1900
|
git_tree *tree,
|
|
1821
|
-
git_iterator_options *
|
|
1901
|
+
git_iterator_options *given_opts)
|
|
1822
1902
|
{
|
|
1823
|
-
|
|
1824
|
-
workdir_iterator *wi;
|
|
1903
|
+
git_iterator_options options = GIT_ITERATOR_OPTIONS_INIT;
|
|
1825
1904
|
|
|
1826
1905
|
if (!repo_workdir) {
|
|
1827
1906
|
if (git_repository__ensure_not_bare(repo, "scan working directory") < 0)
|
|
1828
1907
|
return GIT_EBAREREPO;
|
|
1829
|
-
repo_workdir = git_repository_workdir(repo);
|
|
1830
|
-
}
|
|
1831
1908
|
|
|
1832
|
-
|
|
1833
|
-
wi = git__calloc(1, sizeof(workdir_iterator));
|
|
1834
|
-
GITERR_CHECK_ALLOC(wi);
|
|
1835
|
-
ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo);
|
|
1836
|
-
|
|
1837
|
-
wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR;
|
|
1838
|
-
wi->fi.cb.free = workdir_iterator__free;
|
|
1839
|
-
wi->fi.enter_dir_cb = workdir_iterator__enter_dir;
|
|
1840
|
-
wi->fi.leave_dir_cb = workdir_iterator__leave_dir;
|
|
1841
|
-
wi->fi.update_entry_cb = workdir_iterator__update_entry;
|
|
1842
|
-
|
|
1843
|
-
if ((error = iterator__update_ignore_case((git_iterator *)wi, options ? options->flags : 0)) < 0 ||
|
|
1844
|
-
(error = git_ignore__for_path(repo, ".gitignore", &wi->ignores)) < 0)
|
|
1845
|
-
{
|
|
1846
|
-
git_iterator_free((git_iterator *)wi);
|
|
1847
|
-
return error;
|
|
1909
|
+
repo_workdir = git_repository_workdir(repo);
|
|
1848
1910
|
}
|
|
1849
1911
|
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
wi->index = index;
|
|
1854
|
-
if (index && (error = git_index_snapshot_new(&wi->index_snapshot, index)) < 0) {
|
|
1855
|
-
git_iterator_free((git_iterator *)wi);
|
|
1856
|
-
return error;
|
|
1857
|
-
}
|
|
1858
|
-
wi->entry_srch = iterator__ignore_case(wi) ?
|
|
1859
|
-
git_index_entry_isrch : git_index_entry_srch;
|
|
1912
|
+
/* upgrade to a workdir iterator, adding necessary internal flags */
|
|
1913
|
+
if (given_opts)
|
|
1914
|
+
memcpy(&options, given_opts, sizeof(git_iterator_options));
|
|
1860
1915
|
|
|
1916
|
+
options.flags |= GIT_ITERATOR_HONOR_IGNORES |
|
|
1917
|
+
GIT_ITERATOR_IGNORE_DOT_GIT;
|
|
1861
1918
|
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
giterr_clear();
|
|
1865
|
-
else if (precompose)
|
|
1866
|
-
wi->fi.base.flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
|
|
1867
|
-
|
|
1868
|
-
return fs_iterator__initialize(out, &wi->fi, repo_workdir);
|
|
1919
|
+
return iterator_for_filesystem(out,
|
|
1920
|
+
repo, repo_workdir, index, tree, GIT_ITERATOR_TYPE_WORKDIR, &options);
|
|
1869
1921
|
}
|
|
1870
1922
|
|
|
1871
|
-
void git_iterator_free(git_iterator *iter)
|
|
1872
|
-
{
|
|
1873
|
-
if (iter == NULL)
|
|
1874
|
-
return;
|
|
1875
1923
|
|
|
1876
|
-
|
|
1924
|
+
/* Index iterator */
|
|
1877
1925
|
|
|
1878
|
-
git_vector_free(&iter->pathlist);
|
|
1879
|
-
git__free(iter->start);
|
|
1880
|
-
git__free(iter->end);
|
|
1881
1926
|
|
|
1882
|
-
|
|
1927
|
+
typedef struct {
|
|
1928
|
+
git_iterator base;
|
|
1929
|
+
git_vector entries;
|
|
1930
|
+
size_t next_idx;
|
|
1883
1931
|
|
|
1884
|
-
|
|
1885
|
-
|
|
1932
|
+
/* the pseudotree entry */
|
|
1933
|
+
git_index_entry tree_entry;
|
|
1934
|
+
git_buf tree_buf;
|
|
1935
|
+
bool skip_tree;
|
|
1936
|
+
|
|
1937
|
+
const git_index_entry *entry;
|
|
1938
|
+
} index_iterator;
|
|
1886
1939
|
|
|
1887
|
-
int
|
|
1940
|
+
static int index_iterator_current(
|
|
1941
|
+
const git_index_entry **out, git_iterator *i)
|
|
1888
1942
|
{
|
|
1889
|
-
|
|
1943
|
+
index_iterator *iter = (index_iterator *)i;
|
|
1890
1944
|
|
|
1891
|
-
if (
|
|
1892
|
-
return
|
|
1945
|
+
if (!iterator__has_been_accessed(i))
|
|
1946
|
+
return iter->base.cb->advance(out, i);
|
|
1893
1947
|
|
|
1894
|
-
if (iter->
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
else
|
|
1898
|
-
iter->flags &= ~GIT_ITERATOR_IGNORE_CASE;
|
|
1899
|
-
} else {
|
|
1900
|
-
giterr_set(GITERR_INVALID,
|
|
1901
|
-
"Cannot currently set ignore case on non-empty iterators");
|
|
1902
|
-
return -1;
|
|
1948
|
+
if (iter->entry == NULL) {
|
|
1949
|
+
*out = NULL;
|
|
1950
|
+
return GIT_ITEROVER;
|
|
1903
1951
|
}
|
|
1904
1952
|
|
|
1953
|
+
*out = iter->entry;
|
|
1905
1954
|
return 0;
|
|
1906
1955
|
}
|
|
1907
1956
|
|
|
1908
|
-
|
|
1957
|
+
static bool index_iterator_create_pseudotree(
|
|
1958
|
+
const git_index_entry **out,
|
|
1959
|
+
index_iterator *iter,
|
|
1960
|
+
const char *path)
|
|
1909
1961
|
{
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
return NULL;
|
|
1913
|
-
}
|
|
1962
|
+
const char *prev_path, *relative_path, *dirsep;
|
|
1963
|
+
size_t common_len;
|
|
1914
1964
|
|
|
1915
|
-
|
|
1916
|
-
const git_tree_entry **tree_entry, git_iterator *iter)
|
|
1917
|
-
{
|
|
1918
|
-
if (iter->type != GIT_ITERATOR_TYPE_TREE)
|
|
1919
|
-
*tree_entry = NULL;
|
|
1920
|
-
else {
|
|
1921
|
-
tree_iterator_frame *tf = ((tree_iterator *)iter)->head;
|
|
1922
|
-
*tree_entry = (tf->current < tf->n_entries) ?
|
|
1923
|
-
tf->entries[tf->current]->te : NULL;
|
|
1924
|
-
}
|
|
1965
|
+
prev_path = iter->entry ? iter->entry->path : "";
|
|
1925
1966
|
|
|
1926
|
-
|
|
1967
|
+
/* determine if the new path is in a different directory from the old */
|
|
1968
|
+
common_len = git_path_common_dirlen(prev_path, path);
|
|
1969
|
+
relative_path = path + common_len;
|
|
1970
|
+
|
|
1971
|
+
if ((dirsep = strchr(relative_path, '/')) == NULL)
|
|
1972
|
+
return false;
|
|
1973
|
+
|
|
1974
|
+
git_buf_clear(&iter->tree_buf);
|
|
1975
|
+
git_buf_put(&iter->tree_buf, path, (dirsep - path) + 1);
|
|
1976
|
+
|
|
1977
|
+
iter->tree_entry.mode = GIT_FILEMODE_TREE;
|
|
1978
|
+
iter->tree_entry.path = iter->tree_buf.ptr;
|
|
1979
|
+
|
|
1980
|
+
*out = &iter->tree_entry;
|
|
1981
|
+
return true;
|
|
1927
1982
|
}
|
|
1928
1983
|
|
|
1929
|
-
int
|
|
1930
|
-
const git_tree **tree_ptr,
|
|
1931
|
-
git_iterator *iter,
|
|
1932
|
-
const char *parent_path)
|
|
1984
|
+
static int index_iterator_skip_pseudotree(index_iterator *iter)
|
|
1933
1985
|
{
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
const char *scan = parent_path;
|
|
1937
|
-
const git_tree_entry *te;
|
|
1986
|
+
assert(iterator__has_been_accessed(&iter->base));
|
|
1987
|
+
assert(S_ISDIR(iter->entry->mode));
|
|
1938
1988
|
|
|
1939
|
-
|
|
1989
|
+
while (true) {
|
|
1990
|
+
const git_index_entry *next_entry = NULL;
|
|
1940
1991
|
|
|
1941
|
-
|
|
1942
|
-
|
|
1992
|
+
if (++iter->next_idx >= iter->entries.length)
|
|
1993
|
+
return GIT_ITEROVER;
|
|
1943
1994
|
|
|
1944
|
-
|
|
1945
|
-
if (!(tf = tf->down) ||
|
|
1946
|
-
tf->current >= tf->n_entries ||
|
|
1947
|
-
!(te = tf->entries[tf->current]->te) ||
|
|
1948
|
-
ti->base.strncomp(scan, te->filename, te->filename_len) != 0)
|
|
1949
|
-
return 0;
|
|
1995
|
+
next_entry = iter->entries.contents[iter->next_idx];
|
|
1950
1996
|
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1997
|
+
if (iter->base.strncomp(iter->tree_buf.ptr, next_entry->path,
|
|
1998
|
+
iter->tree_buf.size) != 0)
|
|
1999
|
+
break;
|
|
1954
2000
|
}
|
|
1955
2001
|
|
|
1956
|
-
|
|
2002
|
+
iter->skip_tree = false;
|
|
1957
2003
|
return 0;
|
|
1958
2004
|
}
|
|
1959
2005
|
|
|
1960
|
-
static
|
|
2006
|
+
static int index_iterator_advance(
|
|
2007
|
+
const git_index_entry **out, git_iterator *i)
|
|
1961
2008
|
{
|
|
1962
|
-
|
|
2009
|
+
index_iterator *iter = (index_iterator *)i;
|
|
2010
|
+
const git_index_entry *entry = NULL;
|
|
2011
|
+
bool is_submodule;
|
|
2012
|
+
int error = 0;
|
|
1963
2013
|
|
|
1964
|
-
|
|
1965
|
-
giterr_clear();
|
|
1966
|
-
wi->is_ignored = GIT_IGNORE_NOTFOUND;
|
|
1967
|
-
}
|
|
2014
|
+
iter->base.flags |= GIT_ITERATOR_FIRST_ACCESS;
|
|
1968
2015
|
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
2016
|
+
while (true) {
|
|
2017
|
+
if (iter->next_idx >= iter->entries.length) {
|
|
2018
|
+
error = GIT_ITEROVER;
|
|
2019
|
+
break;
|
|
2020
|
+
}
|
|
1973
2021
|
|
|
1974
|
-
|
|
1975
|
-
{
|
|
1976
|
-
|
|
2022
|
+
/* we were not asked to expand this pseudotree. advance over it. */
|
|
2023
|
+
if (iter->skip_tree) {
|
|
2024
|
+
index_iterator_skip_pseudotree(iter);
|
|
2025
|
+
continue;
|
|
2026
|
+
}
|
|
1977
2027
|
|
|
1978
|
-
|
|
1979
|
-
|
|
2028
|
+
entry = iter->entries.contents[iter->next_idx];
|
|
2029
|
+
is_submodule = S_ISGITLINK(entry->mode);
|
|
1980
2030
|
|
|
1981
|
-
|
|
1982
|
-
|
|
2031
|
+
if (!iterator_has_started(&iter->base, entry->path, is_submodule)) {
|
|
2032
|
+
iter->next_idx++;
|
|
2033
|
+
continue;
|
|
2034
|
+
}
|
|
1983
2035
|
|
|
1984
|
-
|
|
2036
|
+
if (iterator_has_ended(&iter->base, entry->path)) {
|
|
2037
|
+
error = GIT_ITEROVER;
|
|
2038
|
+
break;
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
/* if we have a list of paths we're interested in, examine it */
|
|
2042
|
+
if (!iterator_pathlist_next_is(&iter->base, entry->path)) {
|
|
2043
|
+
iter->next_idx++;
|
|
2044
|
+
continue;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
/* if this is a conflict, skip it unless we're including conflicts */
|
|
2048
|
+
if (git_index_entry_is_conflict(entry) &&
|
|
2049
|
+
!iterator__include_conflicts(&iter->base)) {
|
|
2050
|
+
iter->next_idx++;
|
|
2051
|
+
continue;
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
/* we've found what will be our next _file_ entry. but if we are
|
|
2055
|
+
* returning trees entries, we may need to return a pseudotree
|
|
2056
|
+
* entry that will contain this. don't advance over this entry,
|
|
2057
|
+
* though, we still need to return it on the next `advance`.
|
|
2058
|
+
*/
|
|
2059
|
+
if (iterator__include_trees(&iter->base) &&
|
|
2060
|
+
index_iterator_create_pseudotree(&entry, iter, entry->path)) {
|
|
2061
|
+
|
|
2062
|
+
/* Note whether this pseudo tree should be expanded or not */
|
|
2063
|
+
iter->skip_tree = iterator__dont_autoexpand(&iter->base);
|
|
2064
|
+
break;
|
|
2065
|
+
}
|
|
1985
2066
|
|
|
1986
|
-
|
|
2067
|
+
iter->next_idx++;
|
|
2068
|
+
break;
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
iter->entry = (error == 0) ? entry : NULL;
|
|
2072
|
+
|
|
2073
|
+
if (out)
|
|
2074
|
+
*out = iter->entry;
|
|
2075
|
+
|
|
2076
|
+
return error;
|
|
1987
2077
|
}
|
|
1988
2078
|
|
|
1989
|
-
|
|
2079
|
+
static int index_iterator_advance_into(
|
|
2080
|
+
const git_index_entry **out, git_iterator *i)
|
|
1990
2081
|
{
|
|
1991
|
-
|
|
2082
|
+
index_iterator *iter = (index_iterator *)i;
|
|
1992
2083
|
|
|
1993
|
-
if (iter->
|
|
1994
|
-
|
|
2084
|
+
if (! S_ISDIR(iter->tree_entry.mode)) {
|
|
2085
|
+
if (out)
|
|
2086
|
+
*out = NULL;
|
|
2087
|
+
|
|
2088
|
+
return 0;
|
|
2089
|
+
}
|
|
1995
2090
|
|
|
1996
|
-
|
|
2091
|
+
iter->skip_tree = false;
|
|
2092
|
+
return index_iterator_advance(out, i);
|
|
1997
2093
|
}
|
|
1998
2094
|
|
|
1999
|
-
int
|
|
2095
|
+
static int index_iterator_advance_over(
|
|
2096
|
+
const git_index_entry **out,
|
|
2097
|
+
git_iterator_status_t *status,
|
|
2098
|
+
git_iterator *i)
|
|
2000
2099
|
{
|
|
2100
|
+
index_iterator *iter = (index_iterator *)i;
|
|
2001
2101
|
const git_index_entry *entry;
|
|
2102
|
+
int error;
|
|
2002
2103
|
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
return 1;
|
|
2104
|
+
if ((error = index_iterator_current(&entry, i)) < 0)
|
|
2105
|
+
return error;
|
|
2006
2106
|
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
return -1;
|
|
2107
|
+
if (S_ISDIR(entry->mode))
|
|
2108
|
+
index_iterator_skip_pseudotree(iter);
|
|
2010
2109
|
|
|
2011
|
-
|
|
2110
|
+
*status = GIT_ITERATOR_STATUS_NORMAL;
|
|
2111
|
+
return index_iterator_advance(out, i);
|
|
2012
2112
|
}
|
|
2013
2113
|
|
|
2014
|
-
|
|
2114
|
+
static void index_iterator_clear(index_iterator *iter)
|
|
2015
2115
|
{
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->fi.entry.path)
|
|
2019
|
-
*path = NULL;
|
|
2020
|
-
else
|
|
2021
|
-
*path = &wi->fi.path;
|
|
2116
|
+
iterator_clear(&iter->base);
|
|
2117
|
+
}
|
|
2022
2118
|
|
|
2119
|
+
static int index_iterator_init(index_iterator *iter)
|
|
2120
|
+
{
|
|
2121
|
+
iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
|
|
2122
|
+
iter->next_idx = 0;
|
|
2123
|
+
iter->skip_tree = false;
|
|
2023
2124
|
return 0;
|
|
2024
2125
|
}
|
|
2025
2126
|
|
|
2026
|
-
int
|
|
2127
|
+
static int index_iterator_reset(git_iterator *i)
|
|
2027
2128
|
{
|
|
2028
|
-
|
|
2129
|
+
index_iterator *iter = (index_iterator *)i;
|
|
2029
2130
|
|
|
2030
|
-
|
|
2031
|
-
|
|
2131
|
+
index_iterator_clear(iter);
|
|
2132
|
+
return index_iterator_init(iter);
|
|
2133
|
+
}
|
|
2032
2134
|
|
|
2033
|
-
|
|
2135
|
+
static void index_iterator_free(git_iterator *i)
|
|
2136
|
+
{
|
|
2137
|
+
index_iterator *iter = (index_iterator *)i;
|
|
2034
2138
|
|
|
2035
|
-
|
|
2139
|
+
git_index_snapshot_release(&iter->entries, iter->base.index);
|
|
2140
|
+
git_buf_free(&iter->tree_buf);
|
|
2036
2141
|
}
|
|
2037
2142
|
|
|
2038
|
-
int
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2143
|
+
int git_iterator_for_index(
|
|
2144
|
+
git_iterator **out,
|
|
2145
|
+
git_repository *repo,
|
|
2146
|
+
git_index *index,
|
|
2147
|
+
git_iterator_options *options)
|
|
2042
2148
|
{
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
char *base = NULL;
|
|
2046
|
-
const git_index_entry *entry;
|
|
2149
|
+
index_iterator *iter;
|
|
2150
|
+
int error;
|
|
2047
2151
|
|
|
2048
|
-
|
|
2152
|
+
static git_iterator_callbacks callbacks = {
|
|
2153
|
+
index_iterator_current,
|
|
2154
|
+
index_iterator_advance,
|
|
2155
|
+
index_iterator_advance_into,
|
|
2156
|
+
index_iterator_advance_over,
|
|
2157
|
+
index_iterator_reset,
|
|
2158
|
+
index_iterator_free
|
|
2159
|
+
};
|
|
2049
2160
|
|
|
2050
|
-
|
|
2051
|
-
return git_iterator_advance(entryptr, iter);
|
|
2052
|
-
if ((error = git_iterator_current(&entry, iter)) < 0)
|
|
2053
|
-
return error;
|
|
2161
|
+
*out = NULL;
|
|
2054
2162
|
|
|
2055
|
-
if (
|
|
2056
|
-
|
|
2057
|
-
if (wi->is_ignored == GIT_IGNORE_TRUE)
|
|
2058
|
-
*status = GIT_ITERATOR_STATUS_IGNORED;
|
|
2059
|
-
return git_iterator_advance(entryptr, iter);
|
|
2060
|
-
}
|
|
2163
|
+
if (index == NULL)
|
|
2164
|
+
return git_iterator_for_nothing(out, options);
|
|
2061
2165
|
|
|
2062
|
-
|
|
2166
|
+
iter = git__calloc(1, sizeof(index_iterator));
|
|
2167
|
+
GITERR_CHECK_ALLOC(iter);
|
|
2063
2168
|
|
|
2064
|
-
base =
|
|
2065
|
-
|
|
2169
|
+
iter->base.type = GIT_ITERATOR_TYPE_INDEX;
|
|
2170
|
+
iter->base.cb = &callbacks;
|
|
2066
2171
|
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2172
|
+
if ((error = iterator_init_common(&iter->base, repo, index, options)) < 0 ||
|
|
2173
|
+
(error = git_index_snapshot_new(&iter->entries, index)) < 0 ||
|
|
2174
|
+
(error = index_iterator_init(iter)) < 0)
|
|
2175
|
+
goto on_error;
|
|
2070
2176
|
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
if (wi->is_ignored == GIT_IGNORE_TRUE)
|
|
2075
|
-
*status = GIT_ITERATOR_STATUS_IGNORED;
|
|
2076
|
-
else if (S_ISDIR(entry->mode)) {
|
|
2077
|
-
error = git_iterator_advance_into(&entry, iter);
|
|
2177
|
+
git_vector_set_cmp(&iter->entries, iterator__ignore_case(&iter->base) ?
|
|
2178
|
+
git_index_entry_icmp : git_index_entry_cmp);
|
|
2179
|
+
git_vector_sort(&iter->entries);
|
|
2078
2180
|
|
|
2079
|
-
|
|
2080
|
-
|
|
2181
|
+
*out = &iter->base;
|
|
2182
|
+
return 0;
|
|
2081
2183
|
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
*/
|
|
2087
|
-
if (wi->fi.pathlist_match == ITERATOR_PATHLIST_MATCH_CHILD)
|
|
2088
|
-
*status = GIT_ITERATOR_STATUS_FILTERED;
|
|
2089
|
-
else
|
|
2090
|
-
wi->is_ignored = GIT_IGNORE_TRUE; /* mark empty dirs ignored */
|
|
2184
|
+
on_error:
|
|
2185
|
+
git_iterator_free(&iter->base);
|
|
2186
|
+
return error;
|
|
2187
|
+
}
|
|
2091
2188
|
|
|
2092
|
-
error = 0;
|
|
2093
|
-
} else
|
|
2094
|
-
break; /* real error, stop here */
|
|
2095
|
-
} else {
|
|
2096
|
-
/* we found a non-ignored item, treat parent as untracked */
|
|
2097
|
-
*status = GIT_ITERATOR_STATUS_NORMAL;
|
|
2098
|
-
break;
|
|
2099
|
-
}
|
|
2100
2189
|
|
|
2101
|
-
|
|
2102
|
-
break;
|
|
2103
|
-
}
|
|
2190
|
+
/* Iterator API */
|
|
2104
2191
|
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2192
|
+
int git_iterator_reset_range(
|
|
2193
|
+
git_iterator *i, const char *start, const char *end)
|
|
2194
|
+
{
|
|
2195
|
+
if (iterator_reset_range(i, start, end) < 0)
|
|
2196
|
+
return -1;
|
|
2109
2197
|
|
|
2110
|
-
|
|
2111
|
-
|
|
2198
|
+
return i->cb->reset(i);
|
|
2199
|
+
}
|
|
2112
2200
|
|
|
2113
|
-
|
|
2201
|
+
void git_iterator_set_ignore_case(git_iterator *i, bool ignore_case)
|
|
2202
|
+
{
|
|
2203
|
+
assert(!iterator__has_been_accessed(i));
|
|
2204
|
+
iterator_set_ignore_case(i, ignore_case);
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
void git_iterator_free(git_iterator *iter)
|
|
2208
|
+
{
|
|
2209
|
+
if (iter == NULL)
|
|
2210
|
+
return;
|
|
2211
|
+
|
|
2212
|
+
iter->cb->free(iter);
|
|
2213
|
+
|
|
2214
|
+
git_vector_free(&iter->pathlist);
|
|
2215
|
+
git__free(iter->start);
|
|
2216
|
+
git__free(iter->end);
|
|
2217
|
+
|
|
2218
|
+
memset(iter, 0, sizeof(*iter));
|
|
2219
|
+
|
|
2220
|
+
git__free(iter);
|
|
2114
2221
|
}
|
|
2115
2222
|
|
|
2116
2223
|
int git_iterator_walk(
|