| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -10,7 +10,6 @@ import (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"github.com/docker/docker/pkg/fileutils"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"github.com/pkg/errors"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"github.com/tonistiigi/fsutil/prefix"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"github.com/tonistiigi/fsutil/types"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -36,20 +35,15 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return errors.WithStack(&os.PathError{Op: "walk", Path: root, Err: syscall.ENOTDIR})
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					var pm *fileutils.PatternMatcher
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if opt != nil && opt.ExcludePatterns != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pm, err = fileutils.NewPatternMatcher(opt.ExcludePatterns)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							return errors.Wrapf(err, "invalid excludepatterns: %s", opt.ExcludePatterns)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					var (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						includePatterns []string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						includeMatcher  *fileutils.PatternMatcher
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						excludeMatcher  *fileutils.PatternMatcher
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					var includePatterns []string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if opt != nil && opt.IncludePatterns != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						includePatterns = make([]string, len(opt.IncludePatterns))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						for k := range opt.IncludePatterns {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							includePatterns[k] = filepath.Clean(opt.IncludePatterns[k])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						copy(includePatterns, opt.IncludePatterns)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if opt != nil && opt.FollowPaths != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						targets, err := FollowLinks(p, opt.FollowPaths)
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -61,13 +55,32 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							includePatterns = dedupePaths(includePatterns)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if len(includePatterns) != 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						includeMatcher, err = fileutils.NewPatternMatcher(includePatterns)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							return errors.Wrapf(err, "invalid includepatterns: %s", opt.IncludePatterns)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					var (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						lastIncludedDir string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if opt != nil && opt.ExcludePatterns != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						excludeMatcher, err = fileutils.NewPatternMatcher(opt.ExcludePatterns)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							return errors.Wrapf(err, "invalid excludepatterns: %s", opt.ExcludePatterns)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						parentDirs           []string // used only for exclude handling
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						parentMatchedExclude []bool
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					type visitedDir struct {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						fi               os.FileInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						path             string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						origpath         string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						pathWithSep      string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						includeMatchInfo fileutils.MatchInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						excludeMatchInfo fileutils.MatchInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						calledFn         bool
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// used only for include/exclude handling
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					var parentDirs []visitedDir
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					seenFiles := make(map[uint64]string)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return filepath.Walk(root, func(path string, fi os.FileInfo, err error) (retErr error) {
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -90,87 +103,84 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							return nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if opt != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if includePatterns != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								skip := false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if lastIncludedDir != "" {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if strings.HasPrefix(path, lastIncludedDir+string(filepath.Separator)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										skip = true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						var dir visitedDir
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if !skip {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									matched := false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									partial := true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									for _, pattern := range includePatterns {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										if ok, p := prefix.Match(pattern, path, false); ok {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											matched = true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											if !p {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												partial = false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												break
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if !matched {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										if fi.IsDir() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											return filepath.SkipDir
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										return nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if !partial && fi.IsDir() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										lastIncludedDir = path
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if includeMatcher != nil || excludeMatcher != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							for len(parentDirs) != 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								lastParentDir := parentDirs[len(parentDirs)-1].pathWithSep
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if strings.HasPrefix(path, lastParentDir) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									break
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								parentDirs = parentDirs[:len(parentDirs)-1]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if pm != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								for len(parentMatchedExclude) != 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									lastParentDir := parentDirs[len(parentDirs)-1]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if strings.HasPrefix(path, lastParentDir) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										break
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									parentDirs = parentDirs[:len(parentDirs)-1]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									parentMatchedExclude = parentMatchedExclude[:len(parentMatchedExclude)-1]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								var m bool
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if len(parentMatchedExclude) != 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									m, err = pm.MatchesUsingParentResult(path, parentMatchedExclude[len(parentMatchedExclude)-1])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								} else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									m, err = pm.MatchesOrParentMatches(path)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if fi.IsDir() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								dir = visitedDir{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									fi:          fi,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									path:        path,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									origpath:    origpath,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									pathWithSep: path + string(filepath.Separator),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									return errors.Wrap(err, "failed to match excludepatterns")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						skip := false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if includeMatcher != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							var parentIncludeMatchInfo fileutils.MatchInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if len(parentDirs) != 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								parentIncludeMatchInfo = parentDirs[len(parentDirs)-1].includeMatchInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							m, matchInfo, err := includeMatcher.MatchesUsingParentResults(path, parentIncludeMatchInfo)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								return errors.Wrap(err, "failed to match includepatterns")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if fi.IsDir() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								dir.includeMatchInfo = matchInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if !m {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								skip = true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if excludeMatcher != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							var parentExcludeMatchInfo fileutils.MatchInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if len(parentDirs) != 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								parentExcludeMatchInfo = parentDirs[len(parentDirs)-1].excludeMatchInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							m, matchInfo, err := excludeMatcher.MatchesUsingParentResults(path, parentExcludeMatchInfo)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								return errors.Wrap(err, "failed to match excludepatterns")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if fi.IsDir() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								dir.excludeMatchInfo = matchInfo
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if m {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if fi.IsDir() && !excludeMatcher.Exclusions() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									return filepath.SkipDir
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								skip = true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								var dirSlash string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if includeMatcher != nil || excludeMatcher != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							defer func() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if fi.IsDir() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									dirSlash = path + string(filepath.Separator)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									parentDirs = append(parentDirs, dirSlash)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									parentMatchedExclude = append(parentMatchedExclude, m)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									parentDirs = append(parentDirs, dir)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if m {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if fi.IsDir() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										if !pm.Exclusions() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											return filepath.SkipDir
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										for _, pat := range pm.Patterns() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											if !pat.Exclusion() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												continue
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											patStr := pat.String() + string(filepath.Separator)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											if strings.HasPrefix(patStr, dirSlash) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												goto passedFilter
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										return filepath.SkipDir
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									return nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if skip {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							return nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					passedFilter:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						dir.calledFn = true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						stat, err := mkstat(origpath, path, fi, seenFiles)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							return err
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -185,6 +195,31 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									return nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							for i, parentDir := range parentDirs {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if parentDir.calledFn {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									continue
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								parentStat, err := mkstat(parentDir.origpath, parentDir.path, parentDir.fi, seenFiles)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									return err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								select {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								case <-ctx.Done():
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									return ctx.Err()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								default:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if opt != nil && opt.Map != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if allowed := opt.Map(parentStat.Path, parentStat); !allowed {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										continue
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if err := fn(parentStat.Path, &StatInfo{parentStat}, nil); err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									return err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								parentDirs[i].calledFn = true
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if err := fn(stat.Path, &StatInfo{stat}, nil); err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								return err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |