github.com/mattolenik/notify@v0.9.1/watcher_fen.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 // +build solaris 6 7 package notify 8 9 import ( 10 "fmt" 11 "os" 12 "syscall" 13 ) 14 15 // newTrigger returns implementation of trigger. 16 func newTrigger(pthLkp map[string]*watched) trigger { 17 return &fen{ 18 pthLkp: pthLkp, 19 cf: newCfen(), 20 } 21 } 22 23 // fen is a structure implementing trigger for FEN. 24 type fen struct { 25 // p is a FEN port identifier 26 p int 27 // pthLkp is a structure mapping monitored files/dir with data about them, 28 // shared with parent trg structure 29 pthLkp map[string]*watched 30 // cf wraps C operations for FEN 31 cf cfen 32 } 33 34 // watched is a data structure representing watched file/directory. 35 type watched struct { 36 trgWatched 37 } 38 39 // Stop implements trigger. 40 func (f *fen) Stop() error { 41 return f.cf.portAlert(f.p) 42 } 43 44 // Close implements trigger. 45 func (f *fen) Close() (err error) { 46 return syscall.Close(f.p) 47 } 48 49 // NewWatched implements trigger. 50 func (*fen) NewWatched(p string, fi os.FileInfo) (*watched, error) { 51 return &watched{trgWatched{p: p, fi: fi}}, nil 52 } 53 54 // Record implements trigger. 55 func (f *fen) Record(w *watched) { 56 f.pthLkp[w.p] = w 57 } 58 59 // Del implements trigger. 60 func (f *fen) Del(w *watched) { 61 delete(f.pthLkp, w.p) 62 } 63 64 func inter2pe(n interface{}) PortEvent { 65 pe, ok := n.(PortEvent) 66 if !ok { 67 panic(fmt.Sprintf("fen: type should be PortEvent, %T instead", n)) 68 } 69 return pe 70 } 71 72 // Watched implements trigger. 73 func (f *fen) Watched(n interface{}) (*watched, int64, error) { 74 pe := inter2pe(n) 75 fo, ok := pe.PortevObject.(*FileObj) 76 if !ok || fo == nil { 77 panic(fmt.Sprintf("fen: type should be *FileObj, %T instead", fo)) 78 } 79 w, ok := f.pthLkp[fo.Name] 80 if !ok { 81 return nil, 0, errNotWatched 82 } 83 return w, int64(pe.PortevEvents), nil 84 } 85 86 // init initializes FEN. 87 func (f *fen) Init() (err error) { 88 f.p, err = f.cf.portCreate() 89 return 90 } 91 92 func fi2fo(fi os.FileInfo, p string) FileObj { 93 st, ok := fi.Sys().(*syscall.Stat_t) 94 if !ok { 95 panic(fmt.Sprintf("fen: type should be *syscall.Stat_t, %T instead", st)) 96 } 97 return FileObj{Name: p, Atim: st.Atim, Mtim: st.Mtim, Ctim: st.Ctim} 98 } 99 100 // Unwatch implements trigger. 101 func (f *fen) Unwatch(w *watched) error { 102 return f.cf.portDissociate(f.p, FileObj{Name: w.p}) 103 } 104 105 // Watch implements trigger. 106 func (f *fen) Watch(fi os.FileInfo, w *watched, e int64) error { 107 return f.cf.portAssociate(f.p, fi2fo(fi, w.p), int(e)) 108 } 109 110 // Wait implements trigger. 111 func (f *fen) Wait() (interface{}, error) { 112 var ( 113 pe PortEvent 114 err error 115 ) 116 err = f.cf.portGet(f.p, &pe) 117 return pe, err 118 } 119 120 // IsStop implements trigger. 121 func (f *fen) IsStop(n interface{}, err error) bool { 122 return err == syscall.EBADF || inter2pe(n).PortevSource == srcAlert 123 } 124 125 func init() { 126 encode = func(e Event, dir bool) (o int64) { 127 // Create event is not supported by FEN. Instead FileModified event will 128 // be registered. If this event will be reported on dir which is to be 129 // monitored for Create, dir will be rescanned and Create events will 130 // be generated and returned for new files. In case of files, 131 // if not requested FileModified event is reported, it will be ignored. 132 o = int64(e &^ Create) 133 if (e&Create != 0 && dir) || e&Write != 0 { 134 o = (o &^ int64(Write)) | int64(FileModified) 135 } 136 // Following events are 'exception events' and as such cannot be requested 137 // explicitly for monitoring or filtered out. If the will be reported 138 // by FEN and not subscribed with by user, they will be filtered out by 139 // watcher's logic. 140 o &= int64(^Rename & ^Remove &^ FileDelete &^ FileRenameTo &^ 141 FileRenameFrom &^ Unmounted &^ MountedOver) 142 return 143 } 144 nat2not = map[Event]Event{ 145 FileModified: Write, 146 FileRenameFrom: Rename, 147 FileDelete: Remove, 148 FileAccess: Event(0), 149 FileAttrib: Event(0), 150 FileRenameTo: Event(0), 151 FileTrunc: Event(0), 152 FileNoFollow: Event(0), 153 Unmounted: Event(0), 154 MountedOver: Event(0), 155 } 156 not2nat = map[Event]Event{ 157 Write: FileModified, 158 Rename: FileRenameFrom, 159 Remove: FileDelete, 160 } 161 }