github.com/checksum/notify@v0.0.0-20190119234841-59aa2d88664f/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  }