Source file FileUtilMode.ml
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
type who = [`User | `Group | `Other | `All]
type wholist = [ who | `List of who list ]
type permcopy = [`User | `Group | `Other]
type perm = [ `Read | `Write | `Exec | `ExecX | `Sticky | `StickyO ]
type permlist = [ perm | `List of perm list ]
type actionarg = [ permlist | permcopy ]
type action = [ `Set of actionarg | `Add of actionarg | `Remove of actionarg]
type actionlist = [ action | `List of action list ]
type clause = [ `User of actionlist | `Group of actionlist
| `Other of actionlist | `All of actionlist
| `None of actionlist ]
type t = clause list
let all_masks =
[
`User, `Sticky, 0o4000;
`User, `Exec, 0o0100;
`User, `Write, 0o0200;
`User, `Read, 0o0400;
`Group, `Sticky, 0o2000;
`Group, `Exec, 0o0010;
`Group, `Write, 0o0020;
`Group, `Read, 0o0040;
`Other, `StickyO, 0o1000;
`Other, `Exec, 0o0001;
`Other, `Write, 0o0002;
`Other, `Read, 0o0004;
]
let mask =
let module M =
Map.Make
(struct
type t = who * perm
let compare = Stdlib.compare
end)
in
let m =
List.fold_left
(fun m (who, prm, msk) -> M.add (who, prm) msk m)
M.empty all_masks
in
fun who prm ->
try
M.find (who, prm) m
with Not_found ->
0
let of_int i =
let user, group, other =
List.fold_left
(fun (user, group, other) (who, perm, mask) ->
if (i land mask) <> 0 then begin
match who with
| `User -> perm :: user, group, other
| `Group -> user, perm :: group, other
| `Other -> user, group, perm :: other
end else begin
(user, group, other)
end)
([], [], [])
all_masks
in
[`User (`Set (`List user));
`Group (`Set (`List group));
`Other (`Set (`List other))]
let to_string =
let perm =
function
| `Read -> "r"
| `Write -> "w"
| `Exec -> "x"
| `Sticky -> "s"
| `ExecX -> "X"
| `StickyO -> "t"
in
let permlist =
function
| `List lst -> String.concat "" (List.map perm lst)
| #perm as prm -> perm prm
in
let permcopy =
function
| `User -> "u"
| `Group -> "g"
| `Other -> "o"
in
let action act =
let sact, arg =
match act with
| `Set arg -> "=", arg
| `Add arg -> "+", arg
| `Remove arg -> "-", arg
in
let sarg =
match arg with
| #permlist as lst -> permlist lst
| #permcopy as prm -> permcopy prm
in
sact^sarg
in
let actionlist =
function
| `List lst -> String.concat "" (List.map action lst)
| #action as act -> action act
in
let clause cls =
let swho, lst =
match cls with
| `User lst -> "u", lst
| `Group lst -> "g", lst
| `Other lst -> "o", lst
| `All lst -> "a", lst
| `None lst -> "", lst
in
swho^(actionlist lst)
in
fun t -> String.concat "," (List.map clause t)
let apply ~is_dir ~umask i (t: t) =
let set who prm b i =
let m = mask who prm in
if b then i lor m else i land (lnot m)
in
let get who prm i =
let m = mask who prm in
(i land m) <> 0
in
let permlist _who i lst =
List.fold_left
(fun acc ->
function
| `Exec | `Read | `Write | `Sticky | `StickyO as a -> a :: acc
| `ExecX ->
if is_dir ||
List.exists (fun who -> get who `Exec i)
[`User; `Group; `Other] then
`Exec :: acc
else
acc)
[]
(match lst with
| `List lst -> lst
| #perm as prm -> [prm])
in
let permcopy _who i =
List.fold_left
(fun acc (who, prm, _) ->
if get who prm i then
prm :: acc
else
acc)
[] all_masks
in
let args who i =
function
| #permlist as lst -> permlist who i lst
| #permcopy as who -> permcopy who i
in
let rec action who i act =
match act with
| `Set arg ->
action who
(action who i (`Remove (`List (permcopy who i))))
(`Add arg)
| `Add arg ->
List.fold_left (fun i prm -> set who prm true i) i (args who i arg)
| `Remove arg ->
List.fold_left (fun i prm -> set who prm false i) i (args who i arg)
in
let actionlist who i lst =
match lst with
| `List lst -> List.fold_left (action who) i lst
| #action as act -> action who i act
in
let actionlist_none i lst =
let numask = lnot umask in
let arg_set_if_mask who i arg b =
List.fold_left
(fun i prm ->
if get who prm numask then
set who prm b i
else
i)
i (args who i arg)
in
List.fold_left
(fun i who ->
List.fold_left
(fun i ->
function
| `Set _ -> i
| `Add arg -> arg_set_if_mask who i arg true
| `Remove arg -> arg_set_if_mask who i arg false)
i
(match lst with
| `List lst -> lst
| #action as act -> [act]))
i [`User; `Group; `Other]
in
let rec clause i cls =
match cls with
| `User lst -> actionlist `User i lst
| `Group lst -> actionlist `Group i lst
| `Other lst -> actionlist `Other i lst
| `All lst ->
List.fold_left clause i [`User lst; `Group lst; `Other lst]
| `None lst -> actionlist_none i lst
in
List.fold_left clause i t