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  }