-
-
Notifications
You must be signed in to change notification settings - Fork 296
/
feature.go
120 lines (98 loc) · 2.56 KB
/
feature.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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package lscolors
import (
"os"
)
//go:generate stringer -type=feature -output=feature_string.go
type feature int
const (
featureInvalid feature = iota
featureOrphanedSymlink
featureSymlink
featureMultiHardLink
featureNamedPipe
featureSocket
featureDoor
featureBlockDevice
featureCharDevice
featureWorldWritableStickyDirectory
featureWorldWritableDirectory
featureStickyDirectory
featureDirectory
featureCapability
featureSetuid
featureSetgid
featureExecutable
featureRegular
)
// Weirdly, permission masks for group and other are missing on platforms other
// than linux, darwin and netbsd. So we replicate some of them here.
const (
worldWritable = 02 // Writable by other
executable = 0111 // Executable
)
func determineFeature(fname string, mh bool) (feature, error) {
stat, err := os.Lstat(fname)
if err != nil {
return featureInvalid, err
}
m := stat.Mode()
// Symlink and OrphanedSymlink has highest precedence
if is(m, os.ModeSymlink) {
_, err := os.Stat(fname)
if err != nil {
return featureOrphanedSymlink, nil
}
return featureSymlink, nil
}
// featureMultiHardLink
if mh && isMultiHardlink(stat) {
return featureMultiHardLink, nil
}
// type bits features
switch {
case is(m, os.ModeNamedPipe):
return featureNamedPipe, nil
case is(m, os.ModeSocket): // Never on Windows
return featureSocket, nil
case isDoor(stat):
return featureDoor, nil
case is(m, os.ModeCharDevice):
return featureCharDevice, nil
case is(m, os.ModeDevice):
// There is no dedicated os.Mode* flag for block device. On all
// supported Unix platforms, when os.ModeDevice is set but
// os.ModeCharDevice is not, the file is a block device (i.e.
// syscall.S_IFBLK is set). On Windows, this branch is unreachable.
//
// On Plan9, this in inaccurate.
return featureBlockDevice, nil
case is(m, os.ModeDir):
// Perm bits features for directory
perm := m.Perm()
switch {
case is(m, os.ModeSticky) && is(perm, worldWritable):
return featureWorldWritableStickyDirectory, nil
case is(perm, worldWritable):
return featureWorldWritableDirectory, nil
case is(m, os.ModeSticky):
return featureStickyDirectory, nil
default:
return featureDirectory, nil
}
}
// TODO(xiaq): Support featureCapacity
// Perm bits features for regular files
switch {
case is(m, os.ModeSetuid):
return featureSetuid, nil
case is(m, os.ModeSetgid):
return featureSetgid, nil
case m&executable != 0:
return featureExecutable, nil
}
// Check extension
return featureRegular, nil
}
func is(m, p os.FileMode) bool {
return m&p == p
}