1// +build darwin dragonfly freebsd linux netbsd openbsd
2
3package godirwalk
4
5import (
6	"os"
7	"path/filepath"
8	"syscall"
9)
10
11// modeType converts a syscall defined constant, which is in purview of OS, to a
12// constant defined by Go, assumed by this project to be stable.
13//
14// When the syscall constant is not recognized, this function falls back to a
15// Stat on the file system.
16func modeType(de *syscall.Dirent, osDirname, osChildname string) (os.FileMode, error) {
17	switch de.Type {
18	case syscall.DT_REG:
19		return 0, nil
20	case syscall.DT_DIR:
21		return os.ModeDir, nil
22	case syscall.DT_LNK:
23		return os.ModeSymlink, nil
24	case syscall.DT_CHR:
25		return os.ModeDevice | os.ModeCharDevice, nil
26	case syscall.DT_BLK:
27		return os.ModeDevice, nil
28	case syscall.DT_FIFO:
29		return os.ModeNamedPipe, nil
30	case syscall.DT_SOCK:
31		return os.ModeSocket, nil
32	default:
33		// If syscall returned unknown type (e.g., DT_UNKNOWN, DT_WHT),
34		// then resolve actual mode by getting stat.
35		fi, err := os.Lstat(filepath.Join(osDirname, osChildname))
36		if err != nil {
37			return 0, err
38		}
39		// Even though the stat provided all file mode bits, we want to
40		// ensure same values returned to caller regardless of whether
41		// we obtained file mode bits from syscall or stat call.
42		// Therefore mask out the additional file mode bits that are
43		// provided by stat but not by the syscall, so users can rely on
44		// their values.
45		return fi.Mode() & os.ModeType, nil
46	}
47}
48