path and path/filepath Deep Dive
path and path/filepath Deep Dive
Overview
path is slash-separated (URLs, import paths). path/filepath is OS paths. Mixing them is a common bug.
Quick rules
| Package | Use |
|---|---|
path/filepath |
Files on disk |
path |
URL paths, logical slash paths |
filepath.Join("a", "b") // a/b or a\b
path.Join("a", "b") // always a/b
filepath.Base("/tmp/x.go")
filepath.Ext("x.go") // .go
filepath.Clean("../etc/passwd")
filepath.Abs(".")Safe join (jail)
func safeJoin(root, unsafe string) (string, error) {
c := filepath.Clean("/" + unsafe) // force abs clean form
rel := strings.TrimPrefix(c, string(filepath.Separator))
full := filepath.Join(root, rel)
absRoot, _ := filepath.Abs(root)
absFull, _ := filepath.Abs(full)
if !strings.HasPrefix(absFull, absRoot+string(filepath.Separator)) && absFull != absRoot {
return "", fmt.Errorf("escape")
}
return absFull, nil
}Walk
filepath.WalkDir(root, func(p string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() && d.Name() == ".git" {
return fs.SkipDir
}
return nil
})Match / Glob
filepath.Glob("*.go")
filepath.Match("a/*.txt", name)Rules
| Do | Don’t |
|---|---|
filepath for files |
path.Join for disk on Windows |
| Clean + jail user paths | Concatenate root + "/" + user |
Try next
- Prove
path.Joinvsfilepath.Joindocs on Windows GOOS.
- WalkDir skip
node_modules.
- SafeJoin reject
../../etc/passwd.