github.com/Hellyna/notify@v0.0.0-20210101060149-8ebdd4ef22cf/node.go (about) 1 // Copyright (c) 2014-2015 The Notify Authors. All rights reserved. 2 // Use of this source code is governed by the MIT license that can be 3 // found in the LICENSE file. 4 5 package notify 6 7 import ( 8 "errors" 9 "os" 10 "path/filepath" 11 ) 12 13 var errSkip = errors.New("notify: skip") 14 15 type walkPathFunc func(nd node, isbase bool) error 16 17 type walkFunc func(node) error 18 19 func errnotexist(name string) error { 20 return &os.PathError{ 21 Op: "Node", 22 Path: name, 23 Err: os.ErrNotExist, 24 } 25 } 26 27 type node struct { 28 Name string 29 Watch watchpoint 30 Child map[string]node 31 } 32 33 func newnode(name string) node { 34 return node{ 35 Name: name, 36 Watch: make(watchpoint), 37 Child: make(map[string]node), 38 } 39 } 40 41 func (nd node) addchild(name, base string) node { 42 child, ok := nd.Child[base] 43 if !ok { 44 child = newnode(name) 45 nd.Child[base] = child 46 } 47 return child 48 } 49 50 func (nd node) Add(name string) node { 51 i := indexbase(nd.Name, name) 52 if i == -1 { 53 return node{} 54 } 55 for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) { 56 nd = nd.addchild(name[:i+j], name[i:i+j]) 57 i += j + 1 58 } 59 return nd.addchild(name, name[i:]) 60 } 61 62 func (nd node) AddDir(fn walkFunc, doNotWatch DoNotWatchFn) error { 63 stack := []node{nd} 64 Traverse: 65 for n := len(stack); n != 0; n = len(stack) { 66 nd, stack = stack[n-1], stack[:n-1] 67 switch err := fn(nd); err { 68 case nil: 69 case errSkip: 70 continue Traverse 71 default: 72 return &os.PathError{ 73 Op: "error while traversing", 74 Path: nd.Name, 75 Err: err, 76 } 77 } 78 // TODO(rjeczalik): tolerate open failures - add failed names to 79 // AddDirError and notify users which names are not added to the tree. 80 f, err := os.Open(nd.Name) 81 if err != nil { 82 return err 83 } 84 names, err := f.Readdirnames(-1) 85 f.Close() 86 if err != nil { 87 return err 88 } 89 for _, name := range names { 90 name = filepath.Join(nd.Name, name) 91 if doNotWatch != nil && doNotWatch(name) { 92 continue 93 } 94 fi, err := os.Lstat(name) 95 if err != nil { 96 return err 97 } 98 if fi.Mode()&(os.ModeSymlink|os.ModeDir) == os.ModeDir { 99 stack = append(stack, nd.addchild(name, name[len(nd.Name)+1:])) 100 } 101 } 102 } 103 return nil 104 } 105 106 func (nd node) Get(name string) (node, error) { 107 i := indexbase(nd.Name, name) 108 if i == -1 { 109 return node{}, errnotexist(name) 110 } 111 ok := false 112 for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) { 113 if nd, ok = nd.Child[name[i:i+j]]; !ok { 114 return node{}, errnotexist(name) 115 } 116 i += j + 1 117 } 118 if nd, ok = nd.Child[name[i:]]; !ok { 119 return node{}, errnotexist(name) 120 } 121 return nd, nil 122 } 123 124 func (nd node) Del(name string) error { 125 i := indexbase(nd.Name, name) 126 if i == -1 { 127 return errnotexist(name) 128 } 129 stack := []node{nd} 130 ok := false 131 for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) { 132 if nd, ok = nd.Child[name[i:i+j]]; !ok { 133 return errnotexist(name[:i+j]) 134 } 135 stack = append(stack, nd) 136 } 137 if nd, ok = nd.Child[name[i:]]; !ok { 138 return errnotexist(name) 139 } 140 nd.Child = nil 141 nd.Watch = nil 142 for name, i = base(nd.Name), len(stack); i != 0; name, i = base(nd.Name), i-1 { 143 nd = stack[i-1] 144 if nd := nd.Child[name]; len(nd.Watch) > 1 || len(nd.Child) != 0 { 145 break 146 } else { 147 nd.Child = nil 148 nd.Watch = nil 149 } 150 delete(nd.Child, name) 151 } 152 return nil 153 } 154 155 func (nd node) Walk(fn walkFunc, doNotWatch DoNotWatchFn) error { 156 stack := []node{nd} 157 Traverse: 158 for n := len(stack); n != 0; n = len(stack) { 159 nd, stack = stack[n-1], stack[:n-1] 160 switch err := fn(nd); err { 161 case nil: 162 case errSkip: 163 continue Traverse 164 default: 165 return err 166 } 167 for name, nd := range nd.Child { 168 if name == "" { 169 // Node storing inactive watchpoints has empty name, skip it 170 // form traversing. Root node has also an empty name, but it 171 // never has a parent node. 172 continue 173 } 174 if doNotWatch != nil && doNotWatch(nd.Name) { 175 continue 176 } 177 stack = append(stack, nd) 178 } 179 } 180 return nil 181 } 182 183 func (nd node) WalkPath(name string, fn walkPathFunc) error { 184 i := indexbase(nd.Name, name) 185 if i == -1 { 186 return errnotexist(name) 187 } 188 ok := false 189 for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) { 190 switch err := fn(nd, false); err { 191 case nil: 192 case errSkip: 193 return nil 194 default: 195 return err 196 } 197 if nd, ok = nd.Child[name[i:i+j]]; !ok { 198 return errnotexist(name[:i+j]) 199 } 200 i += j + 1 201 } 202 switch err := fn(nd, false); err { 203 case nil: 204 case errSkip: 205 return nil 206 default: 207 return err 208 } 209 if nd, ok = nd.Child[name[i:]]; !ok { 210 return errnotexist(name) 211 } 212 switch err := fn(nd, true); err { 213 case nil, errSkip: 214 return nil 215 default: 216 return err 217 } 218 } 219 220 type root struct { 221 nd node 222 } 223 224 func (r root) addroot(name string) node { 225 if vol := filepath.VolumeName(name); vol != "" { 226 root, ok := r.nd.Child[vol] 227 if !ok { 228 root = r.nd.addchild(vol, vol) 229 } 230 return root 231 } 232 return r.nd 233 } 234 235 func (r root) root(name string) (node, error) { 236 if vol := filepath.VolumeName(name); vol != "" { 237 nd, ok := r.nd.Child[vol] 238 if !ok { 239 return node{}, errnotexist(name) 240 } 241 return nd, nil 242 } 243 return r.nd, nil 244 } 245 246 func (r root) Add(name string) node { 247 return r.addroot(name).Add(name) 248 } 249 250 func (r root) AddDir(dir string, fn walkFunc, doNotWatch DoNotWatchFn) error { 251 return r.Add(dir).AddDir(fn, doNotWatch) 252 } 253 254 func (r root) Del(name string) error { 255 nd, err := r.root(name) 256 if err != nil { 257 return err 258 } 259 return nd.Del(name) 260 } 261 262 func (r root) Get(name string) (node, error) { 263 nd, err := r.root(name) 264 if err != nil { 265 return node{}, err 266 } 267 if nd.Name != name { 268 if nd, err = nd.Get(name); err != nil { 269 return node{}, err 270 } 271 } 272 return nd, nil 273 } 274 275 func (r root) Walk(name string, fn walkFunc, doNotWatch DoNotWatchFn) error { 276 nd, err := r.Get(name) 277 if err != nil { 278 return err 279 } 280 return nd.Walk(fn, doNotWatch) 281 } 282 283 func (r root) WalkPath(name string, fn walkPathFunc) error { 284 nd, err := r.root(name) 285 if err != nil { 286 return err 287 } 288 return nd.WalkPath(name, fn) 289 }