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