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