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