Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions pkg/extractor/dirwalk/globExpand.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"sync/atomic"
)

Expand Down Expand Up @@ -49,13 +48,13 @@ func (s *Walker) Walk(paths ...string) <-chan string {

func (s *Walker) walk(c chan<- string, p string) {
if s.Recursive && isFollowableDir(p) {
s.recurseWalk(c, p)
s.recurseWalk(c, p, map[string]string{p: p})
} else {
s.globExpand(c, p)
}
}

func (s *Walker) recurseWalk(c chan<- string, p string) {
func (s *Walker) recurseWalk(c chan<- string, p string, visited map[string]string) {
var rootDevId DeviceId
if s.NoMountTraverse {
// getDeviceId (stat) is expensive
Expand Down Expand Up @@ -88,10 +87,13 @@ func (s *Walker) recurseWalk(c chan<- string, p string) {
real, err := filepath.EvalSymlinks(walkPath)
if err != nil {
s.onError(err)
} else if strings.HasPrefix(real, filepath.Clean(p)) {
s.onError(fmt.Errorf("already traversed symlink %s in %s", walkPath, p))
} else if s.NoMountTraverse && getDeviceId(real) != rootDevId {
// skip
} else if with, ok := visited[real]; ok {
s.onError(fmt.Errorf("already traversed symlink %s in %s", walkPath, with))
} else {
s.recurseWalk(c, walkPath+string(filepath.Separator))
visited[real] = walkPath
s.recurseWalk(c, walkPath+string(filepath.Separator), visited)
}

case info.Type()&os.ModeSymlink != 0: // sym link file
Expand Down
111 changes: 106 additions & 5 deletions pkg/extractor/dirwalk/globExpand_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package dirwalk

import (
"fmt"
"os"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -163,9 +165,19 @@ func TestRecurseWithSymFile(t *testing.T) {
assert.NotContains(t, files, "docs/license.md")
}

func TestRecurseWithSymDir(t *testing.T) {
t.Skip("Known bug, will fix later")
func TestRecursiveWithSymFileIgnore(t *testing.T) {
walk := Walker{
Recursive: true,
ListSymLinks: true,
Exclude: []string{"license*"},
}

files := collectChan(walk.Walk("docs/"))
assert.NotContains(t, files, "docs/license.md")
assert.Equal(t, uint64(1), walk.ExcludedCount())
}

func TestRecurseWithSymDir(t *testing.T) {
p := setupTestDir(t)

walk := Walker{
Expand All @@ -177,7 +189,7 @@ func TestRecurseWithSymDir(t *testing.T) {

walk.FollowSymLinks = true
files = collectChan(walk.Walk(p))
assert.Contains(t, files, p+"/syminner/b")
assert.Contains(t, files, p+"/other/syminner/b")
}

func TestRecurseDoesntIdentifyDirAsFile(t *testing.T) {
Expand All @@ -194,13 +206,104 @@ func TestRecurseDoesntIdentifyDirAsFile(t *testing.T) {
assertNoneContains(t, files, "syminner")
}

func TestNoInfiniteRecursion(t *testing.T) {
p := setupTestDir(t)
os.Symlink("./", p+"/recursive")
os.Symlink(p, p+"/recursive2")

hadError := false
walker := Walker{
Recursive: true,
FollowSymLinks: true,
OnTraverseError: captureError(&hadError),
}

files := collectChan(walker.Walk(p))
assert.True(t, hadError)
assertNoneContains(t, files, "recursive")
assertNoneContains(t, files, "recursive2")
assert.Equal(t, uint64(0), walker.ExcludedCount())
}

func TestNoMountTraverseWithSymlink(t *testing.T) {
p := setupTestDir(t)
os.Symlink("/dev", p+"/dev")

hadError := false
walker := Walker{
Recursive: true,
FollowSymLinks: true,
NoMountTraverse: true,
OnTraverseError: captureError(&hadError),
}

files := collectChan(walker.Walk(p))
assertNoneContains(t, files, "dev")
assert.False(t, hadError)
}

func TestExcludeSymDir(t *testing.T) {
p := setupTestDir(t)

hadError := false
walker := Walker{
Recursive: true,
FollowSymLinks: true,
ExcludeDir: []string{"syminner"},
OnTraverseError: captureError(&hadError),
}

files := collectChan(walker.Walk(p))
assert.False(t, hadError)
assertNoneContains(t, files, "syminner")
assert.Equal(t, uint64(1), walker.ExcludedCount())
}

func TestNoDoubleTraverseSymlink(t *testing.T) {
p := setupTestDir(t)
op := t.TempDir()
os.WriteFile(op+"/opfile", []byte("hello"), 0644)
os.Symlink(op, p+"/op1")
os.Symlink(op, p+"/op2")

hadError := false
walker := Walker{
Recursive: true,
FollowSymLinks: true,
OnTraverseError: captureError(&hadError),
}

files := collectChan(walker.Walk(p))
assert.Equal(t, 1, countContains(files, "op1"))
assert.Equal(t, 0, countContains(files, "op2"))
assert.True(t, hadError)
assert.Equal(t, uint64(0), walker.ExcludedCount())
}

func assertNoneContains(t *testing.T, set []string, contains string) {
t.Helper()
for _, item := range set {
assert.NotContains(t, item, contains)
}
}

func countContains(set []string, contains string) int {
count := 0
for _, item := range set {
if strings.Contains(item, contains) {
count++
}
}
return count
}

func captureError(target *bool) func(err error) {
return func(err error) {
fmt.Println(err)
*target = true
}
}

/*
Sets up the following files in a temp dir to test more complex scenarios
/a - "hello"
Expand All @@ -222,7 +325,5 @@ func setupTestDir(t *testing.T) string {
os.Symlink(p+"/inner", p+"/other/syminner")
os.Symlink(p+"/inner/b", p+"/other/symfile")

// os.Symlink("/proc", p+"/proc")

return p
}
Loading