// The filepath package uses either forward slashes or backslashes,
// depending on the operating system. To process paths such as URLs
// that always use forward slashes regardless of the operating
-// system, see the path package.
+// system, see the [path] package.
package filepath
import (
"errors"
"io/fs"
"os"
+ "slices"
"sort"
"strings"
)
b.w++
}
+func (b *lazybuf) prepend(prefix ...byte) {
+ b.buf = slices.Insert(b.buf, 0, prefix...)
+ b.w += len(prefix)
+}
+
func (b *lazybuf) string() string {
if b.buf == nil {
return b.volAndPath[:b.volLen+b.w]
// If the result of this process is an empty string, Clean
// returns the string ".".
//
+// On Windows, Clean does not modify the volume name other than to replace
+// occurrences of "/" with `\`.
+// For example, Clean("//host/share/../x") returns `\\host\share\x`.
+//
// See also Rob Pike, “Lexical File Names in Plan 9 or
// Getting Dot-Dot Right,”
// https://9p.io/sys/doc/lexnames.html
case os.IsPathSeparator(path[r]):
// empty path element
r++
- case path[r] == '.' && r+1 == n:
+ case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
// . element
r++
- case path[r] == '.' && os.IsPathSeparator(path[r+1]):
- // ./ element
- r++
-
- for r < len(path) && os.IsPathSeparator(path[r]) {
- r++
- }
- if out.w == 0 && volumeNameLen(path[r:]) > 0 {
- // When joining prefix "." and an absolute path on Windows,
- // the prefix should not be removed.
- out.append('.')
- }
case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
// .. element: remove to last separator
r += 2
out.append('.')
}
+ postClean(&out) // avoid creating absolute paths on Windows
return FromSlash(out.string())
}
return err
}
- dirs, err := readDir(path)
+ dirs, err := os.ReadDir(path)
if err != nil {
// Second call, to report ReadDir error.
err = walkDirFn(path, d, err)
if err != nil {
err = fn(root, nil, err)
} else {
- err = walkDir(root, &statDirEntry{info}, fn)
+ err = walkDir(root, fs.FileInfoToDirEntry(info), fn)
}
if err == SkipDir || err == SkipAll {
return nil
return err
}
-type statDirEntry struct {
- info fs.FileInfo
-}
-
-func (d *statDirEntry) Name() string { return d.info.Name() }
-func (d *statDirEntry) IsDir() bool { return d.info.IsDir() }
-func (d *statDirEntry) Type() fs.FileMode { return d.info.Mode().Type() }
-func (d *statDirEntry) Info() (fs.FileInfo, error) { return d.info, nil }
-
// Walk walks the file tree rooted at root, calling fn for each file or
// directory in the tree, including root.
//
return err
}
-// readDir reads the directory named by dirname and returns
-// a sorted list of directory entries.
-func readDir(dirname string) ([]fs.DirEntry, error) {
- f, err := os.Open(dirname)
- if err != nil {
- return nil, err
- }
- dirs, err := f.ReadDir(-1)
- f.Close()
- if err != nil {
- return nil, err
- }
- sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
- return dirs, nil
-}
-
// readDirNames reads the directory named by dirname and returns
// a sorted list of directory entry names.
func readDirNames(dirname string) ([]string, error) {