-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.go
112 lines (98 loc) · 2.17 KB
/
parse.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
package permbits
import (
"errors"
"fmt"
"os"
)
type parseMode int
const (
parseOther = 0
parseGroup = 3
parseUser = 6
)
type parseApply int
const (
parseApplyNone parseApply = iota
parseApplyAdd
parseApplySet
parseApplySub
)
// ErrModeStringSyntax is returned when there is a syntax error in the mode string.
var ErrModeStringSyntax = errors.New("syntax error in mode string")
// MustString is a wrapper around FromString that will panic on invalid syntax.
func MustString(perms string) os.FileMode {
mode, err := FromString(perms)
if err != nil {
panic(err)
}
return mode
}
// FromString takes a subset of the available symbolic modes and returns a os.FileMode
// that is comprised of them or 0 and an error if the input is invalid.
//
// Supported Modes
//
// References: ugoa
// Operators: +-=
// Modes: rwx
//
// Special modes are not supported.
//
// Because the mode starts at 0 the `-` operator does not remove permissions unless they
// were added earlier in the mode string.
//
//nolint:gocognit // it's a long function.
func FromString(perms string) (os.FileMode, error) {
out := 0
mode := []parseMode{}
apply := parseApplyNone
for idx := range len(perms) {
switch perms[idx] {
case 'u':
mode = append(mode, parseUser)
case 'g':
mode = append(mode, parseGroup)
case 'o':
mode = append(mode, parseOther)
case 'a':
mode = append(mode, parseOther, parseGroup, parseUser)
case ',':
mode = []parseMode{}
apply = parseApplyNone
case '+':
apply = parseApplyAdd
case '-':
apply = parseApplySub
case '=':
apply = parseApplySet
case 'r', 'w', 'x':
val := 0
switch perms[idx] {
case 'r':
val = 4
case 'w':
val = 2
case 'x':
val = 1
}
for _, pv := range mode {
icv := val << pv
switch apply {
case parseApplyNone:
return os.FileMode(out), fmt.Errorf("%w: %s", ErrModeStringSyntax, perms)
case parseApplyAdd, parseApplySet:
if (out & icv) != icv {
out += icv
}
case parseApplySub:
if (out & icv) == icv {
out -= icv
}
}
}
default:
return os.FileMode(out), fmt.Errorf("%w: %s", ErrModeStringSyntax, perms)
}
}
return os.FileMode(out), nil
}