mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 16:13:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			93 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package fsutil
 | |
| 
 | |
| import (
 | |
| 	"os"
 | |
| 	"path"
 | |
| 	"runtime"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/pkg/errors"
 | |
| )
 | |
| 
 | |
| type parent struct {
 | |
| 	dir  string
 | |
| 	last string
 | |
| }
 | |
| 
 | |
| type Validator struct {
 | |
| 	parentDirs []parent
 | |
| }
 | |
| 
 | |
| func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err error) (retErr error) {
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	// test that all paths are in order and all parent dirs were present
 | |
| 	if v.parentDirs == nil {
 | |
| 		v.parentDirs = make([]parent, 1, 10)
 | |
| 	}
 | |
| 	if runtime.GOOS == "windows" {
 | |
| 		p = strings.Replace(p, "\\", "", -1)
 | |
| 	}
 | |
| 	if p != path.Clean(p) {
 | |
| 		return errors.Errorf("invalid unclean path %s", p)
 | |
| 	}
 | |
| 	if path.IsAbs(p) {
 | |
| 		return errors.Errorf("abolute path %s not allowed", p)
 | |
| 	}
 | |
| 	dir := path.Dir(p)
 | |
| 	base := path.Base(p)
 | |
| 	if dir == "." {
 | |
| 		dir = ""
 | |
| 	}
 | |
| 	if dir == ".." || strings.HasPrefix(p, "../") {
 | |
| 		return errors.Errorf("invalid path: %s", p)
 | |
| 	}
 | |
| 
 | |
| 	// find a parent dir from saved records
 | |
| 	i := sort.Search(len(v.parentDirs), func(i int) bool {
 | |
| 		return ComparePath(v.parentDirs[len(v.parentDirs)-1-i].dir, dir) <= 0
 | |
| 	})
 | |
| 	i = len(v.parentDirs) - 1 - i
 | |
| 	if i != len(v.parentDirs)-1 { // skipping back to grandparent
 | |
| 		v.parentDirs = v.parentDirs[:i+1]
 | |
| 	}
 | |
| 
 | |
| 	if dir != v.parentDirs[len(v.parentDirs)-1].dir || v.parentDirs[i].last >= base {
 | |
| 		return errors.Errorf("changes out of order: %q %q", p, path.Join(v.parentDirs[i].dir, v.parentDirs[i].last))
 | |
| 	}
 | |
| 	v.parentDirs[i].last = base
 | |
| 	if kind != ChangeKindDelete && fi.IsDir() {
 | |
| 		v.parentDirs = append(v.parentDirs, parent{
 | |
| 			dir:  path.Join(dir, base),
 | |
| 			last: "",
 | |
| 		})
 | |
| 	}
 | |
| 	// todo: validate invalid mode combinations
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func ComparePath(p1, p2 string) int {
 | |
| 	// byte-by-byte comparison to be compatible with str<>str
 | |
| 	min := min(len(p1), len(p2))
 | |
| 	for i := 0; i < min; i++ {
 | |
| 		switch {
 | |
| 		case p1[i] == p2[i]:
 | |
| 			continue
 | |
| 		case p2[i] != '/' && p1[i] < p2[i] || p1[i] == '/':
 | |
| 			return -1
 | |
| 		default:
 | |
| 			return 1
 | |
| 		}
 | |
| 	}
 | |
| 	return len(p1) - len(p2)
 | |
| }
 | |
| 
 | |
| func min(x, y int) int {
 | |
| 	if x < y {
 | |
| 		return x
 | |
| 	}
 | |
| 	return y
 | |
| }
 | 
