-
Notifications
You must be signed in to change notification settings - Fork 1
/
relation.go
104 lines (93 loc) · 2.4 KB
/
relation.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
//go:build windows
// +build windows
package winproc
// Relation is a collection option that includes processes related to those
// already matched.
type Relation int
const (
// IncludeAncestors is a collection option that includes all ancestors
// of matched processes.
IncludeAncestors Relation = 1 << iota
// IncludeDescendants is a collection option that includes all descendants
// of matched processes.
IncludeDescendants
)
// Contains returns true if r contains b.
func (r Relation) Contains(b Relation) bool {
return r&b == b
}
// Apply applies the relation to the collection.
func (r Relation) Apply(col *Collection) {
if r == 0 {
return
}
// Pass 1: Build relationships
parents := make(map[ID]ID) // Maps process ID to parent ID
children := make(map[ID][]ID) // Maps parent ID to child process ID
for _, process := range col.Procs {
parents[process.ID] = process.ParentID
children[process.ParentID] = append(children[process.ParentID], process.ID)
}
// Pass 2: Include ancestors
descendantMatched := make(map[ID]bool) // Processes with a matched descendant
if r.Contains(IncludeAncestors) {
for i := range col.Procs {
if col.Excluded[i] {
continue
}
pid := col.Procs[i].ID
for {
if descendantMatched[pid] {
break // Already processed
}
descendantMatched[pid] = true
parent, ok := parents[pid]
if !ok || parent == pid {
break
}
pid = parent
}
}
}
// Pass 3: Include descendants
ancestorMatched := make(map[ID]bool) // Processes with a matched ancestor
if r.Contains(IncludeDescendants) {
for i := range col.Procs {
if col.Excluded[i] {
continue
}
pid := col.Procs[i].ID
next, ok := children[pid]
if !ok {
continue
}
for len(next) > 0 {
current := next
next = nil
for _, child := range current {
if ancestorMatched[child] {
continue // Already processed
}
ancestorMatched[child] = true
next = append(next, children[child]...)
}
}
}
}
// Pass 4: Include matches
for i := range col.Procs {
pid := col.Procs[i].ID
if ancestorMatched[pid] || descendantMatched[pid] {
col.Excluded[i] = false
}
}
}
// Merge attempts to merge the relation with the next option. It returns true
// if successful.
func (r Relation) Merge(next CollectionOption) (merged CollectionOption, ok bool) {
n, ok := next.(Relation)
if !ok {
return nil, false
}
return r | n, true
}