diff --git a/go-gitignore/gitignore.go b/go-gitignore/gitignore.go index e0b5df2..cce429b 100644 --- a/go-gitignore/gitignore.go +++ b/go-gitignore/gitignore.go @@ -268,18 +268,24 @@ func (i *ignore) MatchIsDir(path string, _isdir bool) Match { // the path is not located under the base directory of this GitIgnore, or // is not matched by this GitIgnore, nil is returned. func (i *ignore) Absolute(path string, isdir bool) Match { - // does the file share the same directory as this ignore file? - if !strings.HasPrefix(path, i._base) { + _rel, ok := relativeToBase(i._base, path) + if !ok { return nil } - - // extract the relative path of this file - _prefix := len(i._base) + 1 // BOYTERWASHERE - //_prefix := len(i._base) - _rel := string(path[_prefix:]) return i.Relative(_rel, isdir) } // Absolute() +func relativeToBase(base, path string) (string, bool) { + _rel, _err := filepath.Rel(base, path) + if _err != nil { + return "", false + } + if _rel == ".." || strings.HasPrefix(_rel, ".."+string(filepath.Separator)) { + return "", false + } + return _rel, true +} + // Relative attempts to match a path relative to the GitIgnore base // directory. isdir is used to indicate whether the path represents a file // or a directory. If the path is not matched by the GitIgnore, nil is diff --git a/go-gitignore/match_test.go b/go-gitignore/match_test.go index 3ae24e0..2289c60 100644 --- a/go-gitignore/match_test.go +++ b/go-gitignore/match_test.go @@ -276,6 +276,24 @@ func TestMatchAbsolute(t *testing.T) { } } // TestMatchAbsolute() +func TestMatchAbsoluteRejectsPathWithBasePrefixOnly(t *testing.T) { + _buffer, _err := buffer("file.txt\n") + if _err != nil { + t.Fatalf("unable to create temporary .gitignore: %s", _err.Error()) + } + + _ignore := gitignore.New(_buffer, _GITBASE, nil) + if _ignore == nil { + t.Fatal("expected non-nil GitIgnore instance; nil found") + } + + _path := _GITBASE + "xfile.txt" + _match := _ignore.Absolute(_path, false) + if _match != nil { + t.Fatalf("unexpected match for path outside base directory; expected nil, got %v", _match) + } +} + func TestMatchRelative(t *testing.T) { // create a temporary .gitignore _buffer, _err := buffer(_GITMATCH) diff --git a/go-gitignore/repository.go b/go-gitignore/repository.go index 1a69cdf..df56f74 100644 --- a/go-gitignore/repository.go +++ b/go-gitignore/repository.go @@ -5,7 +5,6 @@ package gitignore import ( "os" "path/filepath" - "strings" ) const File = ".gitignore" @@ -197,14 +196,10 @@ func (r *repository) Match(path string) Match { // path is not located under the base directory of this repository, or is not // matched by this repository, nil is returned. func (r *repository) Absolute(path string, isdir bool) Match { - // does the file share the same directory as this ignore file? - if !strings.HasPrefix(path, r.Base()) { + _rel, ok := relativeToBase(r.Base(), path) + if !ok { return nil } - - // extract the relative path of this file - _prefix := len(r.Base()) + 1 - _rel := string(path[_prefix:]) return r.Relative(_rel, isdir) } // Absolute()