diff options
| author | Philip Kelley <phkelley@hotmail.com> | 2012-10-16 08:34:28 -0700 |
|---|---|---|
| committer | Philip Kelley <phkelley@hotmail.com> | 2012-10-16 08:34:28 -0700 |
| commit | 9e37305aad734efb83f22b2e292a7591bbf49f15 (patch) | |
| tree | 91b7498ffd8f292bac418c9dc0067aead5a435fa /src | |
| parent | ebb867558e734d8c053dd1a292ff9861197bdc4d (diff) | |
| parent | 52032ae53689ac37350f6af3bf1834122e4b3cf0 (diff) | |
| download | libgit2-9e37305aad734efb83f22b2e292a7591bbf49f15.tar.gz | |
Merge pull request #984 from arrbee/fix-fnmatch-and-ignore
Fix single file ignores
Diffstat (limited to 'src')
| -rw-r--r-- | src/attr_file.h | 8 | ||||
| -rw-r--r-- | src/fnmatch.c (renamed from src/compat/fnmatch.c) | 20 | ||||
| -rw-r--r-- | src/fnmatch.h (renamed from src/compat/fnmatch.h) | 7 | ||||
| -rw-r--r-- | src/ignore.c | 69 | ||||
| -rw-r--r-- | src/posix.h | 1 | ||||
| -rw-r--r-- | src/status.c | 23 | ||||
| -rw-r--r-- | src/unix/posix.h | 7 | ||||
| -rw-r--r-- | src/win32/posix.h | 1 |
8 files changed, 110 insertions, 26 deletions
diff --git a/src/attr_file.h b/src/attr_file.h index b28d8a02b..877daf306 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -71,10 +71,10 @@ typedef struct { } git_attr_file; typedef struct { - git_buf full; - const char *path; - const char *basename; - int is_dir; + git_buf full; + char *path; + char *basename; + int is_dir; } git_attr_path; typedef enum { diff --git a/src/compat/fnmatch.c b/src/fnmatch.c index 835d811bc..f394274da 100644 --- a/src/compat/fnmatch.c +++ b/src/fnmatch.c @@ -24,13 +24,16 @@ static int rangematch(const char *, char, int, char **); -int -p_fnmatch(const char *pattern, const char *string, int flags) +static int +p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) { const char *stringstart; char *newp; char c, test; + if (recurs-- == 0) + return FNM_NORES; + for (stringstart = string;;) switch (c = *pattern++) { case EOS: @@ -75,8 +78,11 @@ p_fnmatch(const char *pattern, const char *string, int flags) /* General case, use recursion. */ while ((test = *string) != EOS) { - if (!p_fnmatch(pattern, string, flags & ~FNM_PERIOD)) - return (0); + int e; + + e = p_fnmatchx(pattern, string, flags & ~FNM_PERIOD, recurs); + if (e != FNM_NOMATCH) + return e; if (test == '/' && (flags & FNM_PATHNAME)) break; ++string; @@ -178,3 +184,9 @@ rangematch(const char *pattern, char test, int flags, char **newp) return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); } +int +p_fnmatch(const char *pattern, const char *string, int flags) +{ + return p_fnmatchx(pattern, string, flags, 64); +} + diff --git a/src/compat/fnmatch.h b/src/fnmatch.h index 7faef09b3..913efd1a0 100644 --- a/src/compat/fnmatch.h +++ b/src/fnmatch.h @@ -11,12 +11,13 @@ #define FNM_NOMATCH 1 /* Match failed. */ #define FNM_NOSYS 2 /* Function not supported (unused). */ +#define FNM_NORES 3 /* Out of resources */ -#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ -#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ +#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ +#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ #define FNM_PERIOD 0x04 /* Period must be matched by period. */ #define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */ -#define FNM_CASEFOLD 0x10 /* Case insensitive search. */ +#define FNM_CASEFOLD 0x10 /* Case insensitive search. */ #define FNM_IGNORECASE FNM_CASEFOLD #define FNM_FILE_NAME FNM_PATHNAME diff --git a/src/ignore.c b/src/ignore.c index e711be206..6a377e60d 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -277,15 +277,76 @@ int git_ignore_clear_internal_rules( int git_ignore_path_is_ignored( int *ignored, git_repository *repo, - const char *path) + const char *pathname) { int error; + const char *workdir; + git_attr_path path; + char *tail, *end; + bool full_is_dir; git_ignores ignores; + unsigned int i; + git_attr_file *file; - if (git_ignore__for_path(repo, path, &ignores) < 0) - return -1; + assert(ignored && pathname); + + workdir = repo ? git_repository_workdir(repo) : NULL; + + if ((error = git_attr_path__init(&path, pathname, workdir)) < 0) + return error; + + tail = path.path; + end = &path.full.ptr[path.full.size]; + full_is_dir = path.is_dir; - error = git_ignore__lookup(&ignores, path, ignored); + while (1) { + /* advance to next component of path */ + path.basename = tail; + + while (tail < end && *tail != '/') tail++; + *tail = '\0'; + + path.full.size = (tail - path.full.ptr); + path.is_dir = (tail == end) ? full_is_dir : true; + + /* update ignores for new path fragment */ + if (path.basename == path.path) + error = git_ignore__for_path(repo, path.path, &ignores); + else + error = git_ignore__push_dir(&ignores, path.basename); + if (error < 0) + break; + + /* first process builtins - success means path was found */ + if (ignore_lookup_in_rules( + &ignores.ign_internal->rules, &path, ignored)) + goto cleanup; + + /* next process files in the path */ + git_vector_foreach(&ignores.ign_path, i, file) { + if (ignore_lookup_in_rules(&file->rules, &path, ignored)) + goto cleanup; + } + + /* last process global ignores */ + git_vector_foreach(&ignores.ign_global, i, file) { + if (ignore_lookup_in_rules(&file->rules, &path, ignored)) + goto cleanup; + } + + /* if we found no rules before reaching the end, we're done */ + if (tail == end) + break; + + /* reinstate divider in path */ + *tail = '/'; + while (*tail == '/') tail++; + } + + *ignored = 0; + +cleanup: + git_attr_path__free(&path); git_ignore__free(&ignores); return error; } diff --git a/src/posix.h b/src/posix.h index 71bb82283..d565dc11f 100644 --- a/src/posix.h +++ b/src/posix.h @@ -10,6 +10,7 @@ #include "common.h" #include <fcntl.h> #include <time.h> +#include "fnmatch.h" #ifndef S_IFGITLINK #define S_IFGITLINK 0160000 diff --git a/src/status.c b/src/status.c index 3a0ed075f..a37653db4 100644 --- a/src/status.c +++ b/src/status.c @@ -86,6 +86,10 @@ int git_status_foreach_ext( assert(show <= GIT_STATUS_SHOW_INDEX_THEN_WORKDIR); + if (show != GIT_STATUS_SHOW_INDEX_ONLY && + (err = git_repository__ensure_not_bare(repo, "status")) < 0) + return err; + if ((err = git_repository_head_tree(&head, repo)) < 0) return err; @@ -245,9 +249,22 @@ int git_status_file( error = GIT_EAMBIGUOUS; if (!error && !sfi.count) { - giterr_set(GITERR_INVALID, - "Attempt to get status of nonexistent file '%s'", path); - error = GIT_ENOTFOUND; + git_buf full = GIT_BUF_INIT; + + /* if the file actually exists and we still did not get a callback + * for it, then it must be contained inside an ignored directory, so + * mark it as such instead of generating an error. + */ + if (!git_buf_joinpath(&full, git_repository_workdir(repo), path) && + git_path_exists(full.ptr)) + sfi.status = GIT_STATUS_IGNORED; + else { + giterr_set(GITERR_INVALID, + "Attempt to get status of nonexistent file '%s'", path); + error = GIT_ENOTFOUND; + } + + git_buf_free(&full); } *status_flags = sfi.status; diff --git a/src/unix/posix.h b/src/unix/posix.h index 25038c827..bcd800301 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -7,13 +7,6 @@ #ifndef INCLUDE_posix__w32_h__ #define INCLUDE_posix__w32_h__ -#if !defined(__sun) && !defined(__amigaos4__) -# include <fnmatch.h> -# define p_fnmatch(p, s, f) fnmatch(p, s, f) -#else -# include "compat/fnmatch.h" -#endif - #include <stdio.h> #define p_lstat(p,b) lstat(p,b) diff --git a/src/win32/posix.h b/src/win32/posix.h index da46cf514..80dcca5c1 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -8,7 +8,6 @@ #define INCLUDE_posix__w32_h__ #include "common.h" -#include "compat/fnmatch.h" #include "utf-conv.h" GIT_INLINE(int) p_link(const char *old, const char *new) |
