Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
4 - * This file is part of libgit2, distributed under the GNU GPL v2 with
5 - * a Linking Exception. For full terms see the included COPYING file.
6 - */
7 -
8 - #include "ignore.h"
9 -
10 - #include "git2/ignore.h"
11 - #include "common.h"
12 - #include "attrcache.h"
13 - #include "path.h"
14 - #include "config.h"
15 - #include "wildmatch.h"
16 -
17 - #define GIT_IGNORE_INTERNAL "[internal]exclude"
18 -
19 - #define GIT_IGNORE_DEFAULT_RULES ".\n..\n.git\n"
20 -
21 - /**
22 - * A negative ignore pattern can negate a positive one without
23 - * wildcards if it is a basename only and equals the basename of
24 - * the positive pattern. Thus
25 - *
26 - * foo/bar
27 - * !bar
28 - *
29 - * would result in foo/bar being unignored again while
30 - *
31 - * moo/foo/bar
32 - * !foo/bar
33 - *
34 - * would do nothing. The reverse also holds true: a positive
35 - * basename pattern can be negated by unignoring the basename in
36 - * subdirectories. Thus
37 - *
38 - * bar
39 - * !foo/bar
40 - *
41 - * would result in foo/bar being unignored again. As with the
42 - * first case,
43 - *
44 - * foo/bar
45 - * !moo/foo/bar
46 - *
47 - * would do nothing, again.
48 - */
49 71 2 static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
50 - {
51 - int (*cmp)(const char *, const char *, size_t);
52 - git_attr_fnmatch *longer, *shorter;
53 - char *p;
54 -
55 71 2 if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0
56 59 3 || (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0)
57 12 4 return false;
58 -
59 59 5 if (neg->flags & GIT_ATTR_FNMATCH_ICASE)
60 1 6 cmp = git__strncasecmp;
61 - else
62 58 7 cmp = git__strncmp;
63 -
64 - /* If lengths match we need to have an exact match */
65 59 8 if (rule->length == neg->length) {
66 18 9,10 return cmp(rule->pattern, neg->pattern, rule->length) == 0;
67 41 11 } else if (rule->length < neg->length) {
68 22 12 shorter = rule;
69 22 12 longer = neg;
70 - } else {
71 19 13 shorter = neg;
72 19 13 longer = rule;
73 - }
74 -
75 - /* Otherwise, we need to check if the shorter
76 - * rule is a basename only (that is, it contains
77 - * no path separator) and, if so, if it
78 - * matches the tail of the longer rule */
79 41 14 p = longer->pattern + longer->length - shorter->length;
80 -
81 41 14 if (p[-1] != '/')
82 24 15 return false;
83 17 16 if (memchr(shorter->pattern, '/', shorter->length) != NULL)
84 3 17 return false;
85 -
86 14 18 return cmp(p, shorter->pattern, shorter->length) == 0;
87 - }
88 -
89 - /**
90 - * A negative ignore can only unignore a file which is given explicitly before, thus
91 - *
92 - * foo
93 - * !foo/bar
94 - *
95 - * does not unignore 'foo/bar' as it's not in the list. However
96 - *
97 - * foo/<star>
98 - * !foo/bar
99 - *
100 - * does unignore 'foo/bar', as it is contained within the 'foo/<star>' rule.
101 - */
102 32 2 static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match)
103 - {
104 32 2 int error = 0, wildmatch_flags;
105 - size_t i;
106 - git_attr_fnmatch *rule;
107 - char *path;
108 32 2 git_buf buf = GIT_BUF_INIT;
109 -
110 32 2 *out = 0;
111 -
112 32 2 wildmatch_flags = WM_PATHNAME;
113 32 2 if (match->flags & GIT_ATTR_FNMATCH_ICASE)
114 1 3 wildmatch_flags |= WM_CASEFOLD;
115 -
116 - /* path of the file relative to the workdir, so we match the rules in subdirs */
117 32 4 if (match->containing_dir) {
118 5 5 git_buf_puts(&buf, match->containing_dir);
119 - }
120 32 6,7 if (git_buf_puts(&buf, match->pattern) < 0)
121 ##### 8 return -1;
122 -
123 32 9 path = git_buf_detach(&buf);
124 -
125 102 10,27-29 git_vector_foreach(rules, i, rule) {
126 93 11 if (!(rule->flags & GIT_ATTR_FNMATCH_HASWILD)) {
127 71 12,13 if (does_negate_pattern(rule, match)) {
128 7 14 error = 0;
129 7 14 *out = 1;
130 7 14 goto out;
131 - }
132 - else
133 64 15 continue;
134 - }
135 -
136 22 16 git_buf_clear(&buf);
137 22 17 if (rule->containing_dir)
138 5 18 git_buf_puts(&buf, rule->containing_dir);
139 22 19 git_buf_puts(&buf, rule->pattern);
140 -
141 22 20,21 if (git_buf_oom(&buf))
142 ##### 22 goto out;
143 -
144 - /* if we found a match, we want to keep this rule */
145 22 23-25 if ((wildmatch(git_buf_cstr(&buf), path, wildmatch_flags)) == WM_MATCH) {
146 16 26 *out = 1;
147 16 26 error = 0;
148 16 26 goto out;
149 - }
150 - }
151 -
152 9 30 error = 0;
153 -
154 - out:
155 32 31 git__free(path);
156 32 32 git_buf_dispose(&buf);
157 32 33 return error;
158 - }
159 -
160 6974 2 static int parse_ignore_file(
161 - git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros)
162 - {
163 6974 2 int error = 0;
164 6974 2 int ignore_case = false;
165 6974 2 const char *scan = data, *context = NULL;
166 6974 2 git_attr_fnmatch *match = NULL;
167 -
168 - GIT_UNUSED(allow_macros);
169 -
170 6974 2,3 if (git_repository__configmap_lookup(&ignore_case, repo, GIT_CONFIGMAP_IGNORECASE) < 0)
171 ##### 4 git_error_clear();
172 -
173 - /* if subdir file path, convert context for file paths */
174 6974 5,7 if (attrs->entry &&
175 6974 6,9 git_path_root(attrs->entry->path) < 0 &&
176 6813 8 !git__suffixcmp(attrs->entry->path, "/" GIT_IGNORE_FILE))
177 1930 10 context = attrs->entry->path;
178 -
179 6973 11,12 if (git_mutex_lock(&attrs->lock) < 0) {
180 ##### 13 git_error_set(GIT_ERROR_OS, "failed to lock ignore file");
181 ##### 14 return -1;
182 - }
183 -
184 14372 15,38,39 while (!error && *scan) {
185 7399 16 int valid_rule = 1;
186 -
187 7399 16-18 if (!match && !(match = git__calloc(1, sizeof(*match)))) {
188 ##### 19 error = -1;
189 ##### 19 break;
190 - }
191 -
192 7398 20 match->flags =
193 - GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG;
194 -
195 7398 20,21 if (!(error = git_attr_fnmatch__parse(
196 - match, &attrs->pool, context, &scan)))
197 - {
198 3503 22 match->flags |= GIT_ATTR_FNMATCH_IGNORE;
199 -
200 3503 22 if (ignore_case)
201 110 23 match->flags |= GIT_ATTR_FNMATCH_ICASE;
202 -
203 3503 24 scan = git__next_line(scan);
204 -
205 - /*
206 - * If a negative match doesn't actually do anything,
207 - * throw it away. As we cannot always verify whether a
208 - * rule containing wildcards negates another rule, we
209 - * do not optimize away these rules, though.
210 - * */
211 3504 25 if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE
212 42 26 && !(match->flags & GIT_ATTR_FNMATCH_HASWILD))
213 32 27 error = does_negate_rule(&valid_rule, &attrs->rules, match);
214 -
215 3504 28,29 if (!error && valid_rule)
216 3495 30 error = git_vector_insert(&attrs->rules, match);
217 - }
218 -
219 7399 31,32 if (error != 0 || !valid_rule) {
220 3903 33 match->pattern = NULL;
221 -
222 3903 33,35 if (error == GIT_ENOTFOUND)
223 3896 34 error = 0;
224 - } else {
225 7399 36,37 match = NULL; /* vector now "owns" the match */
226 - }
227 - }
228 -
229 6973 40 git_mutex_unlock(&attrs->lock);
230 6974 41 git__free(match);
231 -
232 6974 42 return error;
233 - }
234 -
235 7829 2 static int push_ignore_file(
236 - git_ignores *ignores,
237 - git_vector *which_list,
238 - const char *base,
239 - const char *filename)
240 - {
241 7829 2 int error = 0;
242 7829 2 git_attr_file *file = NULL;
243 -
244 7829 2 error = git_attr_cache__get(&file, ignores->repo, NULL, GIT_ATTR_FILE__FROM_FILE,
245 - base, filename, parse_ignore_file, false);
246 7828 3 if (error < 0)
247 ##### 4 return error;
248 -
249 7828 5 if (file != NULL) {
250 7828 6,7 if ((error = git_vector_insert(which_list, file)) < 0)
251 ##### 8 git_attr_file__free(file);
252 - }
253 -
254 7829 9 return error;
255 - }
256 -
257 3323 2 static int push_one_ignore(void *payload, const char *path)
258 - {
259 3323 2 git_ignores *ign = payload;
260 3323 2 ign->depth++;
261 3323 2 return push_ignore_file(ign, &ign->ign_path, path, GIT_IGNORE_FILE);
262 - }
263 -
264 2947 2 static int get_internal_ignores(git_attr_file **out, git_repository *repo)
265 - {
266 - int error;
267 -
268 2947 2,3 if ((error = git_attr_cache__init(repo)) < 0)
269 ##### 4 return error;
270 -
271 2947 5 error = git_attr_cache__get(out, repo, NULL, GIT_ATTR_FILE__IN_MEMORY, NULL,
272 - GIT_IGNORE_INTERNAL, NULL, false);
273 -
274 - /* if internal rules list is empty, insert default rules */
275 2947 6,7 if (!error && !(*out)->rules.length)
276 1012 8 error = parse_ignore_file(repo, *out, GIT_IGNORE_DEFAULT_RULES, false);
277 -
278 2947 9 return error;
279 - }
280 -
281 2932 2 int git_ignore__for_path(
282 - git_repository *repo,
283 - const char *path,
284 - git_ignores *ignores)
285 - {
286 2932 2 int error = 0;
287 2932 2 const char *workdir = git_repository_workdir(repo);
288 2932 3 git_buf infopath = GIT_BUF_INIT;
289 -
290 2932 3-6 assert(repo && ignores && path);
291 -
292 2932 7 memset(ignores, 0, sizeof(*ignores));
293 2932 7 ignores->repo = repo;
294 -
295 - /* Read the ignore_case flag */
296 2932 7,8 if ((error = git_repository__configmap_lookup(
297 - &ignores->ignore_case, repo, GIT_CONFIGMAP_IGNORECASE)) < 0)
298 ##### 9 goto cleanup;
299 -
300 2932 10,11 if ((error = git_attr_cache__init(repo)) < 0)
301 ##### 12 goto cleanup;
302 -
303 - /* given a unrooted path in a non-bare repo, resolve it */
304 2932 13-15,24 if (workdir && git_path_root(path) < 0) {
305 2930 16 git_buf local = GIT_BUF_INIT;
306 -
307 2930 16-19 if ((error = git_path_dirname_r(&local, path)) < 0 ||
308 2930 20,21 (error = git_path_resolve_relative(&local, 0)) < 0 ||
309 2930 22 (error = git_path_to_dir(&local)) < 0 ||
310 2930 22 (error = git_buf_joinpath(&ignores->dir, workdir, local.ptr)) < 0)
311 - {;} /* Nothing, we just want to stop on the first error */
312 2930 23 git_buf_dispose(&local);
313 - } else {
314 2 25 error = git_buf_joinpath(&ignores->dir, path, "");
315 - }
316 2932 26 if (error < 0)
317 ##### 27 goto cleanup;
318 -
319 2932 28-30 if (workdir && !git__prefixcmp(ignores->dir.ptr, workdir))
320 2930 31 ignores->dir_root = strlen(workdir);
321 -
322 - /* set up internals */
323 2932 32,33 if ((error = get_internal_ignores(&ignores->ign_internal, repo)) < 0)
324 ##### 34 goto cleanup;
325 -
326 - /* load .gitignore up the path */
327 2932 35 if (workdir != NULL) {
328 2930 36 error = git_path_walk_up(
329 - &ignores->dir, workdir, push_one_ignore, ignores);
330 2930 37 if (error < 0)
331 ##### 38 goto cleanup;
332 - }
333 -
334 - /* load .git/info/exclude if possible */
335 2932 39-42 if ((error = git_repository_item_path(&infopath, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
336 2932 41 (error = push_ignore_file(ignores, &ignores->ign_global, infopath.ptr, GIT_IGNORE_FILE_INREPO)) < 0) {
337 ##### 43 if (error != GIT_ENOTFOUND)
338 ##### 44 goto cleanup;
339 ##### 45 error = 0;
340 - }
341 -
342 - /* load core.excludesfile */
343 2932 46,47 if (git_repository_attr_cache(repo)->cfg_excl_file != NULL)
344 3 49 error = push_ignore_file(
345 - ignores, &ignores->ign_global, NULL,
346 3 48 git_repository_attr_cache(repo)->cfg_excl_file);
347 -
348 - cleanup:
349 2932 50 git_buf_dispose(&infopath);
350 2932 51 if (error < 0)
351 ##### 52 git_ignore__free(ignores);
352 -
353 2932 53 return error;
354 - }
355 -
356 1570 2 int git_ignore__push_dir(git_ignores *ign, const char *dir)
357 - {
358 1571 2,3 if (git_buf_joinpath(&ign->dir, ign->dir.ptr, dir) < 0)
359 ##### 4 return -1;
360 -
361 1571 5 ign->depth++;
362 -
363 1571 5 return push_ignore_file(
364 1571 5 ign, &ign->ign_path, ign->dir.ptr, GIT_IGNORE_FILE);
365 - }
366 -
367 4343 2 int git_ignore__pop_dir(git_ignores *ign)
368 - {
369 4343 2 if (ign->ign_path.length > 0) {
370 4340 3 git_attr_file *file = git_vector_last(&ign->ign_path);
371 4340 4 const char *start = file->entry->path, *end;
372 -
373 - /* - ign->dir looks something like "/home/user/a/b/" (or "a/b/c/d/")
374 - * - file->path looks something like "a/b/.gitignore
375 - *
376 - * We are popping the last directory off ign->dir. We also want
377 - * to remove the file from the vector if the popped directory
378 - * matches the ignore path. We need to test if the "a/b" part of
379 - * the file key matches the path we are about to pop.
380 - */
381 -
382 4340 4 if ((end = strrchr(start, '/')) != NULL) {
383 1571 5 size_t dirlen = (end - start) + 1;
384 1571 5 const char *relpath = ign->dir.ptr + ign->dir_root;
385 1571 5 size_t pathlen = ign->dir.size - ign->dir_root;
386 -
387 1571 5,6 if (pathlen == dirlen && !memcmp(relpath, start, dirlen)) {
388 1571 7 git_vector_pop(&ign->ign_path);
389 1571 8 git_attr_file__free(file);
390 - }
391 - }
392 - }
393 -
394 4343 9 if (--ign->depth > 0) {
395 1765 10 git_buf_rtruncate_at_char(&ign->dir, '/');
396 1765 11 git_path_to_dir(&ign->dir);
397 - }
398 -
399 4343 12 return 0;
400 - }
401 -
402 3435 2 void git_ignore__free(git_ignores *ignores)
403 - {
404 - unsigned int i;
405 - git_attr_file *file;
406 -
407 3435 2 git_attr_file__free(ignores->ign_internal);
408 -
409 6757 3,5-7 git_vector_foreach(&ignores->ign_path, i, file) {
410 3322 4 git_attr_file__free(file);
411 3322 5 ignores->ign_path.contents[i] = NULL;
412 - }
413 3435 8 git_vector_free(&ignores->ign_path);
414 -
415 6370 9,11-13 git_vector_foreach(&ignores->ign_global, i, file) {
416 2935 10 git_attr_file__free(file);
417 2935 11 ignores->ign_global.contents[i] = NULL;
418 - }
419 3435 14 git_vector_free(&ignores->ign_global);
420 -
421 3435 15 git_buf_dispose(&ignores->dir);
422 3435 16 }
423 -
424 25614 2 static bool ignore_lookup_in_rules(
425 - int *ignored, git_attr_file *file, git_attr_path *path)
426 - {
427 - size_t j;
428 - git_attr_fnmatch *match;
429 -
430 52712 2,9-11 git_vector_rforeach(&file->rules, j, match) {
431 27830 3,4 if (match->flags & GIT_ATTR_FNMATCH_DIRECTORY &&
432 452 4 path->is_dir == GIT_DIR_FLAG_FALSE)
433 204 5 continue;
434 27631 6,7 if (git_attr_fnmatch__match(match, path)) {
435 737 8,8 *ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0) ?
436 737 8 GIT_IGNORE_TRUE : GIT_IGNORE_FALSE;
437 737 8 return true;
438 - }
439 - }
440 -
441 24882 12 return false;
442 - }
443 -
444 7154 2 int git_ignore__lookup(
445 - int *out, git_ignores *ignores, const char *pathname, git_dir_flag dir_flag)
446 - {
447 - size_t i;
448 - git_attr_file *file;
449 - git_attr_path path;
450 -
451 7154 2 *out = GIT_IGNORE_NOTFOUND;
452 -
453 7159 2-4 if (git_attr_path__init(
454 7154 2 &path, pathname, git_repository_workdir(ignores->repo), dir_flag) < 0)
455 ##### 5 return -1;
456 -
457 - /* first process builtins - success means path was found */
458 7159 6,7 if (ignore_lookup_in_rules(out, ignores->ign_internal, &path))
459 13 8 goto cleanup;
460 -
461 - /* next process files in the path.
462 - * this process has to process ignores in reverse order
463 - * to ensure correct prioritization of rules
464 - */
465 16170 9,13-15 git_vector_rforeach(&ignores->ign_path, i, file) {
466 9286 10,11 if (ignore_lookup_in_rules(out, file, &path))
467 260 12 goto cleanup;
468 - }
469 -
470 - /* last process global ignores */
471 13551 16,20-22 git_vector_foreach(&ignores->ign_global, i, file) {
472 6906 17,18 if (ignore_lookup_in_rules(out, file, &path))
473 239 19 goto cleanup;
474 - }
475 -
476 - cleanup:
477 7157 23 git_attr_path__free(&path);
478 7159 24 return 0;
479 - }
480 -
481 13 2 int git_ignore_add_rule(git_repository *repo, const char *rules)
482 - {
483 - int error;
484 13 2 git_attr_file *ign_internal = NULL;
485 -
486 13 2,3 if ((error = get_internal_ignores(&ign_internal, repo)) < 0)
487 ##### 4 return error;
488 -
489 13 5 error = parse_ignore_file(repo, ign_internal, rules, false);
490 13 6 git_attr_file__free(ign_internal);
491 -
492 13 7 return error;
493 - }
494 -
495 2 2 int git_ignore_clear_internal_rules(git_repository *repo)
496 - {
497 - int error;
498 - git_attr_file *ign_internal;
499 -
500 2 2,3 if ((error = get_internal_ignores(&ign_internal, repo)) < 0)
501 ##### 4 return error;
502 -
503 2 5,6 if (!(error = git_attr_file__clear_rules(ign_internal, true)))
504 2 7 error = parse_ignore_file(
505 - repo, ign_internal, GIT_IGNORE_DEFAULT_RULES, false);
506 -
507 2 8 git_attr_file__free(ign_internal);
508 2 9 return error;
509 - }
510 -
511 357 2 int git_ignore_path_is_ignored(
512 - int *ignored,
513 - git_repository *repo,
514 - const char *pathname)
515 - {
516 - int error;
517 - const char *workdir;
518 - git_attr_path path;
519 - git_ignores ignores;
520 - unsigned int i;
521 - git_attr_file *file;
522 357 2 git_dir_flag dir_flag = GIT_DIR_FLAG_UNKNOWN;
523 -
524 357 2-5 assert(repo && ignored && pathname);
525 -
526 357 6 workdir = git_repository_workdir(repo);
527 -
528 357 7 memset(&path, 0, sizeof(path));
529 357 7 memset(&ignores, 0, sizeof(ignores));
530 -
531 357 7,8 if (!git__suffixcmp(pathname, "/"))
532 5 9 dir_flag = GIT_DIR_FLAG_TRUE;
533 352 10,11 else if (git_repository_is_bare(repo))
534 ##### 12 dir_flag = GIT_DIR_FLAG_FALSE;
535 -
536 357 13-16 if ((error = git_attr_path__init(&path, pathname, workdir, dir_flag)) < 0 ||
537 357 15 (error = git_ignore__for_path(repo, path.path, &ignores)) < 0)
538 - goto cleanup;
539 -
540 - while (1) {
541 - /* first process builtins - success means path was found */
542 554 17,18 if (ignore_lookup_in_rules(ignored, ignores.ign_internal, &path))
543 26 19 goto cleanup;
544 -
545 - /* next process files in the path */
546 1729 20,24-26 git_vector_foreach(&ignores.ign_path, i, file) {
547 1394 21,22 if (ignore_lookup_in_rules(ignored, file, &path))
548 193 23 goto cleanup;
549 - }
550 -
551 - /* last process global ignores */
552 666 27,31-33 git_vector_foreach(&ignores.ign_global, i, file) {
553 337 28,29 if (ignore_lookup_in_rules(ignored, file, &path))
554 6 30 goto cleanup;
555 - }
556 -
557 - /* move up one directory */
558 329 34 if (path.basename == path.path)
559 132 35 break;
560 197 36 path.basename[-1] = '\0';
561 1367 36,38,39 while (path.basename > path.path && *path.basename != '/')
562 1170 37 path.basename--;
563 197 40 if (path.basename > path.path)
564 124 41 path.basename++;
565 197 42 path.is_dir = 1;
566 -
567 197 42,43 if ((error = git_ignore__pop_dir(&ignores)) < 0)
568 ##### 44 break;
569 197 45 }
570 -
571 132 46 *ignored = 0;
572 -
573 - cleanup:
574 357 47 git_attr_path__free(&path);
575 357 48 git_ignore__free(&ignores);
576 357 49 return error;
577 - }
578 -
579 1 2 int git_ignore__check_pathspec_for_exact_ignores(
580 - git_repository *repo,
581 - git_vector *vspec,
582 - bool no_fnmatch)
583 - {
584 1 2 int error = 0;
585 - size_t i;
586 - git_attr_fnmatch *match;
587 - int ignored;
588 1 2 git_buf path = GIT_BUF_INIT;
589 - const char *wd, *filename;
590 - git_index *idx;
591 -
592 1 2,3 if ((error = git_repository__ensure_not_bare(
593 1 4,5 repo, "validate pathspec")) < 0 ||
594 - (error = git_repository_index(&idx, repo)) < 0)
595 ##### 6 return error;
596 -
597 1 7 wd = git_repository_workdir(repo);
598 -
599 1 8,27-29 git_vector_foreach(vspec, i, match) {
600 - /* skip wildcard matches (if they are being used) */
601 1 9,10 if ((match->flags & GIT_ATTR_FNMATCH_HASWILD) != 0 &&
602 ##### 10 !no_fnmatch)
603 ##### 11 continue;
604 -
605 1 12 filename = match->pattern;
606 -
607 - /* if file is already in the index, it's fine */
608 1 12,13 if (git_index_get_bypath(idx, filename, 0) != NULL)
609 ##### 14 continue;
610 -
611 1 15,16 if ((error = git_buf_joinpath(&path, wd, filename)) < 0)
612 ##### 17 break;
613 -
614 - /* is there a file on disk that matches this exactly? */
615 1 18,19 if (!git_path_isfile(path.ptr))
616 ##### 20 continue;
617 -
618 - /* is that file ignored? */
619 1 21,22 if ((error = git_ignore_path_is_ignored(&ignored, repo, filename)) < 0)
620 ##### 23 break;
621 -
622 1 24 if (ignored) {
623 1 25 git_error_set(GIT_ERROR_INVALID, "pathspec contains ignored file '%s'",
624 - filename);
625 1 26 error = GIT_EINVALIDSPEC;
626 1 26 break;
627 - }
628 - }
629 -
630 1 30 git_index_free(idx);
631 1 31 git_buf_dispose(&path);
632 -
633 1 32 return error;
634 - }
635 -