benchmarkReaddir(".", b)
}
+func benchmarkStat(b *testing.B, path string) {
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := Stat(path)
+ if err != nil {
+ b.Fatalf("Stat(%q) failed: %v", path, err)
+ }
+ }
+}
+
+func benchmarkLstat(b *testing.B, path string) {
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := Lstat(path)
+ if err != nil {
+ b.Fatalf("Lstat(%q) failed: %v", path, err)
+ }
+ }
+}
+
+func BenchmarkStatDot(b *testing.B) {
+ benchmarkStat(b, ".")
+}
+
+func BenchmarkStatFile(b *testing.B) {
+ benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
+}
+
+func BenchmarkStatDir(b *testing.B) {
+ benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os"))
+}
+
+func BenchmarkLstatDot(b *testing.B) {
+ benchmarkLstat(b, ".")
+}
+
+func BenchmarkLstatFile(b *testing.B) {
+ benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
+}
+
+func BenchmarkLstatDir(b *testing.B) {
+ benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os"))
+}
+
// Read the directory one entry at a time.
func smallReaddirnames(file *File, length int, t *testing.T) []string {
names := make([]string, length)
if err != nil {
return nil, &PathError{"Stat", name, err}
}
-
+ // Apparently (see https://github.com/golang/go/issues/19922#issuecomment-300031421)
+ // GetFileAttributesEx is fastest approach to get file info.
+ // It does not work for symlinks. But symlinks are rare,
+ // so try GetFileAttributesEx first.
+ var fs fileStat
+ err = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fs.sys)))
+ if err == nil && fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
+ fs.path = name
+ if !isAbs(fs.path) {
+ fs.path, err = syscall.FullPath(fs.path)
+ if err != nil {
+ return nil, &PathError{"FullPath", name, err}
+ }
+ }
+ fs.name = basename(name)
+ return &fs, nil
+ }
// Use Windows I/O manager to dereference the symbolic link, as per
// https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
h, err := syscall.CreateFile(namep, 0, 0, nil,
if !isAbs(fs.path) {
fs.path, e = syscall.FullPath(fs.path)
if e != nil {
- return nil, e
+ return nil, &PathError{"FullPath", name, e}
}
}
return fs, nil