2016-03-18 13:37:29 -05:00
|
|
|
// Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by the MIT license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
// +build solaris
|
|
|
|
|
|
|
|
package notify
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"syscall"
|
|
|
|
)
|
|
|
|
|
|
|
|
// newTrigger returns implementation of trigger.
|
|
|
|
func newTrigger(pthLkp map[string]*watched) trigger {
|
|
|
|
return &fen{
|
|
|
|
pthLkp: pthLkp,
|
|
|
|
cf: newCfen(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fen is a structure implementing trigger for FEN.
|
|
|
|
type fen struct {
|
|
|
|
// p is a FEN port identifier
|
|
|
|
p int
|
|
|
|
// pthLkp is a structure mapping monitored files/dir with data about them,
|
|
|
|
// shared with parent trg structure
|
|
|
|
pthLkp map[string]*watched
|
|
|
|
// cf wraps C operations for FEN
|
|
|
|
cf cfen
|
|
|
|
}
|
|
|
|
|
|
|
|
// watched is a data structure representing watched file/directory.
|
|
|
|
type watched struct {
|
|
|
|
// p is a path to watched file/directory
|
|
|
|
p string
|
|
|
|
// fi provides information about watched file/dir
|
|
|
|
fi os.FileInfo
|
|
|
|
// eDir represents events watched directly
|
|
|
|
eDir Event
|
|
|
|
// eNonDir represents events watched indirectly
|
|
|
|
eNonDir Event
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop implements trigger.
|
|
|
|
func (f *fen) Stop() error {
|
2017-02-16 06:21:11 -06:00
|
|
|
return f.cf.portAlert(f.p)
|
2016-03-18 13:37:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close implements trigger.
|
|
|
|
func (f *fen) Close() (err error) {
|
|
|
|
return syscall.Close(f.p)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewWatched implements trigger.
|
|
|
|
func (*fen) NewWatched(p string, fi os.FileInfo) (*watched, error) {
|
|
|
|
return &watched{p: p, fi: fi}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Record implements trigger.
|
|
|
|
func (f *fen) Record(w *watched) {
|
|
|
|
f.pthLkp[w.p] = w
|
|
|
|
}
|
|
|
|
|
|
|
|
// Del implements trigger.
|
|
|
|
func (f *fen) Del(w *watched) {
|
|
|
|
delete(f.pthLkp, w.p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func inter2pe(n interface{}) PortEvent {
|
|
|
|
pe, ok := n.(PortEvent)
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Sprintf("fen: type should be PortEvent, %T instead", n))
|
|
|
|
}
|
|
|
|
return pe
|
|
|
|
}
|
|
|
|
|
|
|
|
// Watched implements trigger.
|
|
|
|
func (f *fen) Watched(n interface{}) (*watched, int64, error) {
|
|
|
|
pe := inter2pe(n)
|
|
|
|
fo, ok := pe.PortevObject.(*FileObj)
|
|
|
|
if !ok || fo == nil {
|
|
|
|
panic(fmt.Sprintf("fen: type should be *FileObj, %T instead", fo))
|
|
|
|
}
|
|
|
|
w, ok := f.pthLkp[fo.Name]
|
|
|
|
if !ok {
|
|
|
|
return nil, 0, errNotWatched
|
|
|
|
}
|
|
|
|
return w, int64(pe.PortevEvents), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// init initializes FEN.
|
|
|
|
func (f *fen) Init() (err error) {
|
2017-02-16 06:21:11 -06:00
|
|
|
f.p, err = f.cf.portCreate()
|
2016-03-18 13:37:29 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func fi2fo(fi os.FileInfo, p string) FileObj {
|
|
|
|
st, ok := fi.Sys().(*syscall.Stat_t)
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Sprintf("fen: type should be *syscall.Stat_t, %T instead", st))
|
|
|
|
}
|
|
|
|
return FileObj{Name: p, Atim: st.Atim, Mtim: st.Mtim, Ctim: st.Ctim}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unwatch implements trigger.
|
|
|
|
func (f *fen) Unwatch(w *watched) error {
|
2017-02-16 06:21:11 -06:00
|
|
|
return f.cf.portDissociate(f.p, FileObj{Name: w.p})
|
2016-03-18 13:37:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Watch implements trigger.
|
|
|
|
func (f *fen) Watch(fi os.FileInfo, w *watched, e int64) error {
|
2017-02-16 06:21:11 -06:00
|
|
|
return f.cf.portAssociate(f.p, fi2fo(fi, w.p), int(e))
|
2016-03-18 13:37:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Wait implements trigger.
|
|
|
|
func (f *fen) Wait() (interface{}, error) {
|
|
|
|
var (
|
|
|
|
pe PortEvent
|
|
|
|
err error
|
|
|
|
)
|
2017-02-16 06:21:11 -06:00
|
|
|
err = f.cf.portGet(f.p, &pe)
|
2016-03-18 13:37:29 -05:00
|
|
|
return pe, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsStop implements trigger.
|
|
|
|
func (f *fen) IsStop(n interface{}, err error) bool {
|
|
|
|
return err == syscall.EBADF || inter2pe(n).PortevSource == srcAlert
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
2017-02-16 06:21:11 -06:00
|
|
|
encode = func(e Event, dir bool) (o int64) {
|
2016-03-18 13:37:29 -05:00
|
|
|
// Create event is not supported by FEN. Instead FileModified event will
|
|
|
|
// be registered. If this event will be reported on dir which is to be
|
|
|
|
// monitored for Create, dir will be rescanned and Create events will
|
|
|
|
// be generated and returned for new files. In case of files,
|
|
|
|
// if not requested FileModified event is reported, it will be ignored.
|
2017-02-16 06:21:11 -06:00
|
|
|
o = int64(e &^ Create)
|
|
|
|
if (e&Create != 0 && dir) || e&Write != 0 {
|
2016-03-18 13:37:29 -05:00
|
|
|
o = (o &^ int64(Write)) | int64(FileModified)
|
|
|
|
}
|
|
|
|
// Following events are 'exception events' and as such cannot be requested
|
|
|
|
// explicitly for monitoring or filtered out. If the will be reported
|
|
|
|
// by FEN and not subscribed with by user, they will be filtered out by
|
|
|
|
// watcher's logic.
|
|
|
|
o &= int64(^Rename & ^Remove &^ FileDelete &^ FileRenameTo &^
|
|
|
|
FileRenameFrom &^ Unmounted &^ MountedOver)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
nat2not = map[Event]Event{
|
|
|
|
FileModified: Write,
|
|
|
|
FileRenameFrom: Rename,
|
|
|
|
FileDelete: Remove,
|
|
|
|
FileAccess: Event(0),
|
|
|
|
FileAttrib: Event(0),
|
|
|
|
FileRenameTo: Event(0),
|
|
|
|
FileTrunc: Event(0),
|
|
|
|
FileNoFollow: Event(0),
|
|
|
|
Unmounted: Event(0),
|
|
|
|
MountedOver: Event(0),
|
|
|
|
}
|
|
|
|
not2nat = map[Event]Event{
|
|
|
|
Write: FileModified,
|
|
|
|
Rename: FileRenameFrom,
|
|
|
|
Remove: FileDelete,
|
|
|
|
}
|
|
|
|
}
|