mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
46 lines
1.8 KiB
Go
46 lines
1.8 KiB
Go
package store
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// UnderRoot reports whether p resolves inside root ON DISK — following every
|
||
|
|
// symlink on the way, including one planted in a directory that already
|
||
|
|
// exists. p need not exist: the deepest existing ancestor is what gets
|
||
|
|
// resolved, so the answer is available before anything is created.
|
||
|
|
//
|
||
|
|
// A lexical check (filepath.Rel, path.Clean, HasPrefix) answers a question
|
||
|
|
// about the STRING. os.MkdirAll, os.CreateTemp, os.Rename and os.Open all
|
||
|
|
// answer the question about the FILESYSTEM, and that is the one that decides
|
||
|
|
// where the bytes land: "docs/x.md" is a clean relative path by every lexical
|
||
|
|
// test and lands outside the root the moment "docs" is a symlink. It lives in
|
||
|
|
// this package because the two callers that need it — the syncer materializing
|
||
|
|
// a peer's op into a mount, and the file:// backend resolving a key under the
|
||
|
|
// hub's storage root — are the same question about different roots.
|
||
|
|
func UnderRoot(root, p string) bool {
|
||
|
|
rootReal, err := filepath.EvalSymlinks(root)
|
||
|
|
if err != nil {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
for dir := p; ; {
|
||
|
|
if real, err := filepath.EvalSymlinks(dir); err == nil {
|
||
|
|
rel, err := filepath.Rel(rootReal, real)
|
||
|
|
return err == nil && rel != ".." && !strings.HasPrefix(rel, ".."+string(filepath.Separator))
|
||
|
|
}
|
||
|
|
// A component that EXISTS but does not resolve is a dangling symlink,
|
||
|
|
// and stepping past it answered "inside the root" for a path that
|
||
|
|
// lands wherever the link points the moment anything creates the
|
||
|
|
// target. The guard must answer about where the bytes would go.
|
||
|
|
if fi, err := os.Lstat(dir); err == nil && fi.Mode()&os.ModeSymlink != 0 {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
parent := filepath.Dir(dir)
|
||
|
|
if parent == dir {
|
||
|
|
return false // walked off the top without finding anything that exists
|
||
|
|
}
|
||
|
|
dir = parent
|
||
|
|
}
|
||
|
|
}
|