-
Notifications
You must be signed in to change notification settings - Fork 6
/
dirent.go
55 lines (51 loc) · 1.39 KB
/
dirent.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package fastwalk
import (
"io/fs"
"os"
"sync"
"sync/atomic"
"syscall"
"unsafe"
)
type fileInfo struct {
once sync.Once
fs.FileInfo
err error
}
func loadFileInfo(pinfo **fileInfo) *fileInfo {
ptr := (*unsafe.Pointer)(unsafe.Pointer(pinfo))
fi := (*fileInfo)(atomic.LoadPointer(ptr))
if fi == nil {
fi = &fileInfo{}
if !atomic.CompareAndSwapPointer(
(*unsafe.Pointer)(unsafe.Pointer(pinfo)), // adrr
nil, // old
unsafe.Pointer(fi), // new
) {
fi = (*fileInfo)(atomic.LoadPointer(ptr))
}
}
return fi
}
// StatDirEntry returns a [fs.FileInfo] describing the named file ([os.Stat]).
// If de is a [fastwalk.DirEntry] its Stat method is used and the returned
// FileInfo may be cached from a prior call to Stat. If a cached result is not
// desired, users should just call [os.Stat] directly.
//
// This is a helper function for calling Stat on the DirEntry passed to the
// walkFn argument to [Walk].
//
// The path argument is only used if de is not of type [fastwalk.DirEntry].
// Therefore, de should be the DirEntry describing path.
func StatDirEntry(path string, de fs.DirEntry) (fs.FileInfo, error) {
if de == nil {
return nil, &os.PathError{Op: "stat", Path: path, Err: syscall.EINVAL}
}
if de.Type()&os.ModeSymlink == 0 {
return de.Info()
}
if d, ok := de.(DirEntry); ok {
return d.Stat()
}
return os.Stat(path)
}