Merge pull request #149 from cyphar/casync-mtree-compare

entry: rework e.Path() handling for casync-mtree
This commit is contained in:
Vincent Batts 2018-11-15 15:04:02 -05:00 committed by GitHub
commit 367008df78
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 4 deletions

View file

@ -350,7 +350,6 @@ func Compare(oldDh, newDh *DirectoryHierarchy, keys []Keyword) ([]InodeDelta, er
if err != nil { if err != nil {
return nil, err return nil, err
} }
//fmt.Printf("new: %q\n", path)
// Cannot take &kv because it's the iterator. // Cannot take &kv because it's the iterator.
cEntry := new(Entry) cEntry := new(Entry)
@ -373,7 +372,6 @@ func Compare(oldDh, newDh *DirectoryHierarchy, keys []Keyword) ([]InodeDelta, er
if err != nil { if err != nil {
return nil, err return nil, err
} }
//fmt.Printf("old: %q\n", path)
// Cannot take &kv because it's the iterator. // Cannot take &kv because it's the iterator.
cEntry := new(Entry) cEntry := new(Entry)

View file

@ -2,6 +2,7 @@ package mtree
import ( import (
"fmt" "fmt"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -67,6 +68,39 @@ func (e Entry) Ascend() *Entry {
return e.Parent return e.Parent
} }
// CleanPath makes a path safe for use with filepath.Join. This is done by not
// only cleaning the path, but also (if the path is relative) adding a leading
// '/' and cleaning it (then removing the leading '/'). This ensures that a
// path resulting from prepending another path will always resolve to lexically
// be a subdirectory of the prefixed path. This is all done lexically, so paths
// that include symlinks won't be safe as a result of using CleanPath.
//
// This code was copied from runc/libcontainer/utils/utils.go. It was
// originally written by myself, so I am dual-licensing it for the purpose of
// this project.
func CleanPath(path string) string {
// Deal with empty strings nicely.
if path == "" {
return ""
}
// Ensure that all paths are cleaned (especially problematic ones like
// "/../../../../../" which can cause lots of issues).
path = filepath.Clean(path)
// If the path isn't absolute, we need to do more processing to fix paths
// such as "../../../../<etc>/some/path". We also shouldn't convert absolute
// paths to relative ones.
if !filepath.IsAbs(path) {
path = filepath.Clean(string(os.PathSeparator) + path)
// This can't fail, as (by definition) all paths are relative to root.
path, _ = filepath.Rel(string(os.PathSeparator), path)
}
// Clean the path again for good measure.
return filepath.Clean(path)
}
// Path provides the full path of the file, despite RelativeType or FullType. It // Path provides the full path of the file, despite RelativeType or FullType. It
// will be in Unvis'd form. // will be in Unvis'd form.
func (e Entry) Path() (string, error) { func (e Entry) Path() (string, error) {
@ -74,14 +108,15 @@ func (e Entry) Path() (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
decodedName = CleanPath(decodedName)
if e.Parent == nil || e.Type == FullType { if e.Parent == nil || e.Type == FullType {
return filepath.Clean(decodedName), nil return decodedName, nil
} }
parentName, err := e.Parent.Path() parentName, err := e.Parent.Path()
if err != nil { if err != nil {
return "", err return "", err
} }
return filepath.Clean(filepath.Join(parentName, decodedName)), nil return CleanPath(filepath.Join(parentName, decodedName)), nil
} }
// String joins a file with its associated keywords. The file name will be the // String joins a file with its associated keywords. The file name will be the