]>
Commit | Line | Data |
---|---|---|
205166d2 | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
205166d2 | 3 | * |
bb742ede VM |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
205166d2 JP |
6 | */ |
7 | ||
8 | #include "common.h" | |
9 | #include "git2.h" | |
10 | #include "fileops.h" | |
11 | #include "hash.h" | |
3af6b34a JP |
12 | #include "vector.h" |
13 | #include "tree.h" | |
1ee2ef87 | 14 | #include "status.h" |
3af6b34a | 15 | #include "git2/status.h" |
56453d34 | 16 | #include "repository.h" |
df743c7d | 17 | #include "ignore.h" |
114f5a6c | 18 | #include "index.h" |
205166d2 | 19 | |
a48ea31d RB |
20 | #include "git2/diff.h" |
21 | #include "diff.h" | |
22 | ||
a1683f28 | 23 | static unsigned int index_delta2status(const git_diff_delta *head2idx) |
a48ea31d | 24 | { |
a1683f28 | 25 | git_status_t st = GIT_STATUS_CURRENT; |
a48ea31d | 26 | |
a1683f28 | 27 | switch (head2idx->status) { |
a48ea31d RB |
28 | case GIT_DELTA_ADDED: |
29 | case GIT_DELTA_COPIED: | |
a48ea31d RB |
30 | st = GIT_STATUS_INDEX_NEW; |
31 | break; | |
32 | case GIT_DELTA_DELETED: | |
33 | st = GIT_STATUS_INDEX_DELETED; | |
34 | break; | |
35 | case GIT_DELTA_MODIFIED: | |
36 | st = GIT_STATUS_INDEX_MODIFIED; | |
37 | break; | |
bc16fd3e RB |
38 | case GIT_DELTA_RENAMED: |
39 | st = GIT_STATUS_INDEX_RENAMED; | |
a1683f28 RB |
40 | |
41 | if (!git_oid_equal(&head2idx->old_file.oid, &head2idx->new_file.oid)) | |
42 | st |= GIT_STATUS_INDEX_MODIFIED; | |
bc16fd3e RB |
43 | break; |
44 | case GIT_DELTA_TYPECHANGE: | |
45 | st = GIT_STATUS_INDEX_TYPECHANGE; | |
46 | break; | |
a48ea31d RB |
47 | default: |
48 | break; | |
49 | } | |
50 | ||
51 | return st; | |
52 | } | |
53 | ||
a1683f28 | 54 | static unsigned int workdir_delta2status( |
3ff1d123 | 55 | git_diff *diff, git_diff_delta *idx2wd) |
a48ea31d | 56 | { |
a1683f28 | 57 | git_status_t st = GIT_STATUS_CURRENT; |
a48ea31d | 58 | |
a1683f28 | 59 | switch (idx2wd->status) { |
a48ea31d | 60 | case GIT_DELTA_ADDED: |
bc16fd3e | 61 | case GIT_DELTA_COPIED: |
a48ea31d RB |
62 | case GIT_DELTA_UNTRACKED: |
63 | st = GIT_STATUS_WT_NEW; | |
64 | break; | |
65 | case GIT_DELTA_DELETED: | |
66 | st = GIT_STATUS_WT_DELETED; | |
67 | break; | |
68 | case GIT_DELTA_MODIFIED: | |
69 | st = GIT_STATUS_WT_MODIFIED; | |
70 | break; | |
71 | case GIT_DELTA_IGNORED: | |
72 | st = GIT_STATUS_IGNORED; | |
73 | break; | |
dfe8c8df ET |
74 | case GIT_DELTA_RENAMED: |
75 | st = GIT_STATUS_WT_RENAMED; | |
a1683f28 RB |
76 | |
77 | if (!git_oid_equal(&idx2wd->old_file.oid, &idx2wd->new_file.oid)) { | |
78 | /* if OIDs don't match, we might need to calculate them now to | |
79 | * discern between RENAMED vs RENAMED+MODIFED | |
80 | */ | |
81 | if (git_oid_iszero(&idx2wd->old_file.oid) && | |
82 | diff->old_src == GIT_ITERATOR_TYPE_WORKDIR && | |
83 | !git_diff__oid_for_file( | |
84 | diff->repo, idx2wd->old_file.path, idx2wd->old_file.mode, | |
85 | idx2wd->old_file.size, &idx2wd->old_file.oid)) | |
86 | idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_OID; | |
87 | ||
88 | if (git_oid_iszero(&idx2wd->new_file.oid) && | |
89 | diff->new_src == GIT_ITERATOR_TYPE_WORKDIR && | |
90 | !git_diff__oid_for_file( | |
91 | diff->repo, idx2wd->new_file.path, idx2wd->new_file.mode, | |
92 | idx2wd->new_file.size, &idx2wd->new_file.oid)) | |
93 | idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_OID; | |
94 | ||
95 | if (!git_oid_equal(&idx2wd->old_file.oid, &idx2wd->new_file.oid)) | |
96 | st |= GIT_STATUS_WT_MODIFIED; | |
97 | } | |
dfe8c8df | 98 | break; |
bc16fd3e RB |
99 | case GIT_DELTA_TYPECHANGE: |
100 | st = GIT_STATUS_WT_TYPECHANGE; | |
101 | break; | |
a48ea31d RB |
102 | default: |
103 | break; | |
104 | } | |
105 | ||
106 | return st; | |
107 | } | |
108 | ||
1ee2ef87 | 109 | static bool status_is_included( |
3a68d7f0 | 110 | git_status_list *status, |
1ee2ef87 ET |
111 | git_diff_delta *head2idx, |
112 | git_diff_delta *idx2wd) | |
55cbd05b | 113 | { |
3a68d7f0 RB |
114 | if (!(status->opts.flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES)) |
115 | return 1; | |
116 | ||
37ee70fa | 117 | /* if excluding submodules and this is a submodule everywhere */ |
3a68d7f0 RB |
118 | if (head2idx) { |
119 | if (head2idx->status != GIT_DELTA_ADDED && | |
120 | head2idx->old_file.mode != GIT_FILEMODE_COMMIT) | |
121 | return 1; | |
122 | if (head2idx->status != GIT_DELTA_DELETED && | |
123 | head2idx->new_file.mode != GIT_FILEMODE_COMMIT) | |
124 | return 1; | |
125 | } | |
126 | if (idx2wd) { | |
127 | if (idx2wd->status != GIT_DELTA_ADDED && | |
128 | idx2wd->old_file.mode != GIT_FILEMODE_COMMIT) | |
129 | return 1; | |
130 | if (idx2wd->status != GIT_DELTA_DELETED && | |
131 | idx2wd->new_file.mode != GIT_FILEMODE_COMMIT) | |
132 | return 1; | |
55cbd05b RB |
133 | } |
134 | ||
3a68d7f0 RB |
135 | /* only get here if every valid mode is GIT_FILEMODE_COMMIT */ |
136 | return 0; | |
55cbd05b RB |
137 | } |
138 | ||
1ee2ef87 | 139 | static git_status_t status_compute( |
a1683f28 | 140 | git_status_list *status, |
1ee2ef87 ET |
141 | git_diff_delta *head2idx, |
142 | git_diff_delta *idx2wd) | |
143 | { | |
a1683f28 | 144 | git_status_t st = GIT_STATUS_CURRENT; |
1ee2ef87 ET |
145 | |
146 | if (head2idx) | |
a1683f28 | 147 | st |= index_delta2status(head2idx); |
1ee2ef87 ET |
148 | |
149 | if (idx2wd) | |
a1683f28 | 150 | st |= workdir_delta2status(status->idx2wd, idx2wd); |
1ee2ef87 | 151 | |
a1683f28 | 152 | return st; |
1ee2ef87 ET |
153 | } |
154 | ||
155 | static int status_collect( | |
156 | git_diff_delta *head2idx, | |
157 | git_diff_delta *idx2wd, | |
793c4385 | 158 | void *payload) |
a48ea31d | 159 | { |
25e0b157 | 160 | git_status_list *status = payload; |
1ee2ef87 | 161 | git_status_entry *status_entry; |
351888cf | 162 | |
25e0b157 | 163 | if (!status_is_included(status, head2idx, idx2wd)) |
1ee2ef87 | 164 | return 0; |
351888cf | 165 | |
1ee2ef87 | 166 | status_entry = git__malloc(sizeof(git_status_entry)); |
25e0b157 | 167 | GITERR_CHECK_ALLOC(status_entry); |
1ee2ef87 | 168 | |
25e0b157 | 169 | status_entry->status = status_compute(status, head2idx, idx2wd); |
1ee2ef87 ET |
170 | status_entry->head_to_index = head2idx; |
171 | status_entry->index_to_workdir = idx2wd; | |
172 | ||
25e0b157 | 173 | return git_vector_insert(&status->paired, status_entry); |
1ee2ef87 ET |
174 | } |
175 | ||
dfe8c8df ET |
176 | GIT_INLINE(int) status_entry_cmp_base( |
177 | const void *a, | |
178 | const void *b, | |
179 | int (*strcomp)(const char *a, const char *b)) | |
180 | { | |
181 | const git_status_entry *entry_a = a; | |
182 | const git_status_entry *entry_b = b; | |
183 | const git_diff_delta *delta_a, *delta_b; | |
184 | ||
185 | delta_a = entry_a->index_to_workdir ? entry_a->index_to_workdir : | |
186 | entry_a->head_to_index; | |
187 | delta_b = entry_b->index_to_workdir ? entry_b->index_to_workdir : | |
188 | entry_b->head_to_index; | |
189 | ||
190 | if (!delta_a && delta_b) | |
191 | return -1; | |
192 | if (delta_a && !delta_b) | |
193 | return 1; | |
194 | if (!delta_a && !delta_b) | |
195 | return 0; | |
196 | ||
197 | return strcomp(delta_a->new_file.path, delta_b->new_file.path); | |
198 | } | |
199 | ||
200 | static int status_entry_icmp(const void *a, const void *b) | |
201 | { | |
202 | return status_entry_cmp_base(a, b, git__strcasecmp); | |
203 | } | |
204 | ||
205 | static int status_entry_cmp(const void *a, const void *b) | |
206 | { | |
207 | return status_entry_cmp_base(a, b, git__strcmp); | |
208 | } | |
209 | ||
210 | static git_status_list *git_status_list_alloc(git_index *index) | |
1ee2ef87 | 211 | { |
351888cf | 212 | git_status_list *status = NULL; |
dfe8c8df ET |
213 | int (*entrycmp)(const void *a, const void *b); |
214 | ||
351888cf RB |
215 | if (!(status = git__calloc(1, sizeof(git_status_list)))) |
216 | return NULL; | |
217 | ||
dfe8c8df | 218 | entrycmp = index->ignore_case ? status_entry_icmp : status_entry_cmp; |
1ee2ef87 | 219 | |
351888cf RB |
220 | if (git_vector_init(&status->paired, 0, entrycmp) < 0) { |
221 | git__free(status); | |
1ee2ef87 | 222 | return NULL; |
351888cf | 223 | } |
1ee2ef87 | 224 | |
351888cf | 225 | return status; |
1ee2ef87 ET |
226 | } |
227 | ||
228 | int git_status_list_new( | |
229 | git_status_list **out, | |
230 | git_repository *repo, | |
231 | const git_status_options *opts) | |
232 | { | |
dfe8c8df | 233 | git_index *index = NULL; |
351888cf | 234 | git_status_list *status = NULL; |
2f8d30be | 235 | git_diff_options diffopt = GIT_DIFF_OPTIONS_INIT; |
e38f0d69 | 236 | git_diff_find_options findopt = GIT_DIFF_FIND_OPTIONS_INIT; |
a48ea31d RB |
237 | git_tree *head = NULL; |
238 | git_status_show_t show = | |
239 | opts ? opts->show : GIT_STATUS_SHOW_INDEX_AND_WORKDIR; | |
1ee2ef87 | 240 | int error = 0; |
351888cf | 241 | unsigned int flags = opts ? opts->flags : GIT_STATUS_OPT_DEFAULTS; |
a48ea31d | 242 | |
2a16914c | 243 | assert(show <= GIT_STATUS_SHOW_WORKDIR_ONLY); |
a48ea31d | 244 | |
1ee2ef87 ET |
245 | *out = NULL; |
246 | ||
c7231c45 | 247 | GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options"); |
79cfa20d | 248 | |
dfe8c8df ET |
249 | if ((error = git_repository__ensure_not_bare(repo, "status")) < 0 || |
250 | (error = git_repository_index(&index, repo)) < 0) | |
1ee2ef87 | 251 | return error; |
52032ae5 | 252 | |
5cec896a | 253 | /* if there is no HEAD, that's okay - we'll make an empty iterator */ |
4bf630b6 RB |
254 | if ((error = git_repository_head_tree(&head, repo)) < 0) { |
255 | if (error != GIT_ENOTFOUND && error != GIT_EUNBORNBRANCH) | |
256 | goto done; | |
257 | giterr_clear(); | |
351888cf | 258 | } |
1ee2ef87 | 259 | |
4bf630b6 RB |
260 | /* refresh index from disk unless prevented */ |
261 | if ((flags & GIT_STATUS_OPT_NO_REFRESH) == 0 && | |
8e5a8ef8 | 262 | git_index_read(index, false) < 0) |
4bf630b6 RB |
263 | giterr_clear(); |
264 | ||
351888cf RB |
265 | status = git_status_list_alloc(index); |
266 | GITERR_CHECK_ALLOC(status); | |
a48ea31d | 267 | |
351888cf RB |
268 | if (opts) { |
269 | memcpy(&status->opts, opts, sizeof(git_status_options)); | |
270 | memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec)); | |
271 | } | |
4b136a94 | 272 | |
0d64bef9 | 273 | diffopt.flags = GIT_DIFF_INCLUDE_TYPECHANGE; |
e38f0d69 | 274 | findopt.flags = GIT_DIFF_FIND_FOR_UNTRACKED; |
bc16fd3e | 275 | |
351888cf | 276 | if ((flags & GIT_STATUS_OPT_INCLUDE_UNTRACKED) != 0) |
66142ae0 | 277 | diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNTRACKED; |
351888cf | 278 | if ((flags & GIT_STATUS_OPT_INCLUDE_IGNORED) != 0) |
66142ae0 | 279 | diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_IGNORED; |
351888cf | 280 | if ((flags & GIT_STATUS_OPT_INCLUDE_UNMODIFIED) != 0) |
66142ae0 | 281 | diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNMODIFIED; |
351888cf | 282 | if ((flags & GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) != 0) |
4b136a94 | 283 | diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; |
351888cf | 284 | if ((flags & GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH) != 0) |
a1773f9d | 285 | diffopt.flags = diffopt.flags | GIT_DIFF_DISABLE_PATHSPEC_MATCH; |
351888cf | 286 | if ((flags & GIT_STATUS_OPT_RECURSE_IGNORED_DIRS) != 0) |
0c289dd7 | 287 | diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_IGNORED_DIRS; |
351888cf | 288 | if ((flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES) != 0) |
37ee70fa | 289 | diffopt.flags = diffopt.flags | GIT_DIFF_IGNORE_SUBMODULES; |
a48ea31d | 290 | |
e38f0d69 | 291 | if ((flags & GIT_STATUS_OPT_RENAMES_FROM_REWRITES) != 0) |
17c7fbf6 ET |
292 | findopt.flags = findopt.flags | |
293 | GIT_DIFF_FIND_AND_BREAK_REWRITES | | |
294 | GIT_DIFF_FIND_RENAMES_FROM_REWRITES | | |
295 | GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY; | |
dfe8c8df | 296 | |
37ee70fa | 297 | if (show != GIT_STATUS_SHOW_WORKDIR_ONLY) { |
351888cf | 298 | if ((error = git_diff_tree_to_index( |
4bf630b6 | 299 | &status->head2idx, repo, head, index, &diffopt)) < 0) |
351888cf | 300 | goto done; |
1ee2ef87 | 301 | |
351888cf | 302 | if ((flags & GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX) != 0 && |
e38f0d69 | 303 | (error = git_diff_find_similar(status->head2idx, &findopt)) < 0) |
351888cf | 304 | goto done; |
37ee70fa | 305 | } |
a48ea31d | 306 | |
37ee70fa | 307 | if (show != GIT_STATUS_SHOW_INDEX_ONLY) { |
351888cf | 308 | if ((error = git_diff_index_to_workdir( |
4bf630b6 | 309 | &status->idx2wd, repo, index, &diffopt)) < 0) |
351888cf | 310 | goto done; |
a48ea31d | 311 | |
351888cf | 312 | if ((flags & GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR) != 0 && |
e38f0d69 | 313 | (error = git_diff_find_similar(status->idx2wd, &findopt)) < 0) |
351888cf | 314 | goto done; |
1ee2ef87 | 315 | } |
55cbd05b | 316 | |
25e0b157 RB |
317 | error = git_diff__paired_foreach( |
318 | status->head2idx, status->idx2wd, status_collect, status); | |
319 | if (error < 0) | |
320 | goto done; | |
dfe8c8df | 321 | |
22b6b82f RB |
322 | if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY) |
323 | git_vector_set_cmp(&status->paired, status_entry_cmp); | |
324 | if (flags & GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY) | |
325 | git_vector_set_cmp(&status->paired, status_entry_icmp); | |
326 | ||
327 | if ((flags & | |
328 | (GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX | | |
329 | GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR | | |
330 | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY | | |
331 | GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)) != 0) | |
351888cf | 332 | git_vector_sort(&status->paired); |
dfe8c8df | 333 | |
351888cf RB |
334 | done: |
335 | if (error < 0) { | |
336 | git_status_list_free(status); | |
337 | status = NULL; | |
338 | } | |
a48ea31d | 339 | |
351888cf | 340 | *out = status; |
1ee2ef87 | 341 | |
a48ea31d | 342 | git_tree_free(head); |
dfe8c8df | 343 | git_index_free(index); |
5dca2010 | 344 | |
1ee2ef87 ET |
345 | return error; |
346 | } | |
347 | ||
351888cf | 348 | size_t git_status_list_entrycount(git_status_list *status) |
1ee2ef87 | 349 | { |
351888cf | 350 | assert(status); |
1ee2ef87 | 351 | |
351888cf | 352 | return status->paired.length; |
1ee2ef87 ET |
353 | } |
354 | ||
351888cf | 355 | const git_status_entry *git_status_byindex(git_status_list *status, size_t i) |
1ee2ef87 | 356 | { |
351888cf | 357 | assert(status); |
1ee2ef87 | 358 | |
351888cf | 359 | return git_vector_get(&status->paired, i); |
1ee2ef87 ET |
360 | } |
361 | ||
351888cf | 362 | void git_status_list_free(git_status_list *status) |
1ee2ef87 | 363 | { |
351888cf | 364 | if (status == NULL) |
1ee2ef87 ET |
365 | return; |
366 | ||
3ff1d123 RB |
367 | git_diff_free(status->head2idx); |
368 | git_diff_free(status->idx2wd); | |
1ee2ef87 | 369 | |
fcd324c6 | 370 | git_vector_free_all(&status->paired); |
1ee2ef87 | 371 | |
351888cf RB |
372 | git__memzero(status, sizeof(*status)); |
373 | git__free(status); | |
1ee2ef87 ET |
374 | } |
375 | ||
376 | int git_status_foreach_ext( | |
377 | git_repository *repo, | |
378 | const git_status_options *opts, | |
379 | git_status_cb cb, | |
380 | void *payload) | |
381 | { | |
351888cf | 382 | git_status_list *status; |
1ee2ef87 ET |
383 | const git_status_entry *status_entry; |
384 | size_t i; | |
385 | int error = 0; | |
386 | ||
351888cf | 387 | if ((error = git_status_list_new(&status, repo, opts)) < 0) |
1ee2ef87 ET |
388 | return error; |
389 | ||
351888cf | 390 | git_vector_foreach(&status->paired, i, status_entry) { |
1ee2ef87 ET |
391 | const char *path = status_entry->head_to_index ? |
392 | status_entry->head_to_index->old_file.path : | |
393 | status_entry->index_to_workdir->old_file.path; | |
394 | ||
c7b3e1b3 | 395 | if ((error = cb(path, status_entry->status, payload)) != 0) { |
26c1cb91 | 396 | giterr_set_after_callback(error); |
1ee2ef87 | 397 | break; |
c7b3e1b3 | 398 | } |
1ee2ef87 ET |
399 | } |
400 | ||
351888cf | 401 | git_status_list_free(status); |
f335ecd6 | 402 | |
1ee2ef87 | 403 | return error; |
a48ea31d RB |
404 | } |
405 | ||
351888cf | 406 | int git_status_foreach(git_repository *repo, git_status_cb cb, void *payload) |
a48ea31d | 407 | { |
351888cf | 408 | return git_status_foreach_ext(repo, NULL, cb, payload); |
a48ea31d RB |
409 | } |
410 | ||
41a82592 | 411 | struct status_file_info { |
5dca2010 | 412 | char *expected; |
41a82592 RB |
413 | unsigned int count; |
414 | unsigned int status; | |
25423d03 | 415 | int fnm_flags; |
5dca2010 | 416 | int ambiguous; |
3af6b34a JP |
417 | }; |
418 | ||
41a82592 | 419 | static int get_one_status(const char *path, unsigned int status, void *data) |
df743c7d | 420 | { |
41a82592 | 421 | struct status_file_info *sfi = data; |
25423d03 | 422 | int (*strcomp)(const char *a, const char *b); |
df743c7d | 423 | |
41a82592 RB |
424 | sfi->count++; |
425 | sfi->status = status; | |
df743c7d | 426 | |
25423d03 RB |
427 | strcomp = (sfi->fnm_flags & FNM_CASEFOLD) ? git__strcasecmp : git__strcmp; |
428 | ||
b90500f0 | 429 | if (sfi->count > 1 || |
25423d03 RB |
430 | (strcomp(sfi->expected, path) != 0 && |
431 | p_fnmatch(sfi->expected, path, sfi->fnm_flags) != 0)) | |
5c8bb98c | 432 | { |
5dca2010 | 433 | sfi->ambiguous = true; |
2f28219c | 434 | return GIT_EAMBIGUOUS; /* giterr_set will be done by caller */ |
0d0fa7c3 | 435 | } |
d8b903da | 436 | |
41a82592 | 437 | return 0; |
d8b903da | 438 | } |
439 | ||
0d0fa7c3 | 440 | int git_status_file( |
41a82592 RB |
441 | unsigned int *status_flags, |
442 | git_repository *repo, | |
443 | const char *path) | |
20361b2f | 444 | { |
41a82592 | 445 | int error; |
79cfa20d BS |
446 | git_status_options opts = GIT_STATUS_OPTIONS_INIT; |
447 | struct status_file_info sfi = {0}; | |
25423d03 | 448 | git_index *index; |
20361b2f | 449 | |
56453d34 | 450 | assert(status_flags && repo && path); |
451 | ||
25423d03 RB |
452 | if ((error = git_repository_index__weakptr(&index, repo)) < 0) |
453 | return error; | |
454 | ||
41a82592 | 455 | if ((sfi.expected = git__strdup(path)) == NULL) |
722c08af | 456 | return -1; |
25423d03 RB |
457 | if (index->ignore_case) |
458 | sfi.fnm_flags = FNM_CASEFOLD; | |
20361b2f | 459 | |
dfe8c8df | 460 | opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; |
41a82592 | 461 | opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED | |
1f9e41ee | 462 | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS | |
41a82592 RB |
463 | GIT_STATUS_OPT_INCLUDE_UNTRACKED | |
464 | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS | | |
465 | GIT_STATUS_OPT_INCLUDE_UNMODIFIED; | |
466 | opts.pathspec.count = 1; | |
467 | opts.pathspec.strings = &sfi.expected; | |
df743c7d | 468 | |
41a82592 | 469 | error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi); |
df743c7d | 470 | |
5c8bb98c RB |
471 | if (error < 0 && sfi.ambiguous) { |
472 | giterr_set(GITERR_INVALID, | |
473 | "Ambiguous path '%s' given to git_status_file", sfi.expected); | |
5dca2010 | 474 | error = GIT_EAMBIGUOUS; |
5c8bb98c | 475 | } |
5dca2010 | 476 | |
41a82592 | 477 | if (!error && !sfi.count) { |
1f9e41ee RB |
478 | giterr_set(GITERR_INVALID, |
479 | "Attempt to get status of nonexistent file '%s'", path); | |
480 | error = GIT_ENOTFOUND; | |
df743c7d RB |
481 | } |
482 | ||
41a82592 | 483 | *status_flags = sfi.status; |
20361b2f | 484 | |
41a82592 | 485 | git__free(sfi.expected); |
0d0fa7c3 | 486 | |
56453d34 | 487 | return error; |
20361b2f | 488 | } |
d8b903da | 489 | |
dc13f1f7 | 490 | int git_status_should_ignore( |
41a82592 RB |
491 | int *ignored, |
492 | git_repository *repo, | |
493 | const char *path) | |
cfbc880d | 494 | { |
2fb4e9b3 | 495 | return git_ignore_path_is_ignored(ignored, repo, path); |
cfbc880d RB |
496 | } |
497 |