github.com/FabianKramm/notify@v0.9.3-0.20210719135015-4705c29227a1/watcher_fen_cgo.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 illumos
     6  
     7  package notify
     8  
     9  // #include <port.h>
    10  // #include <stdio.h>
    11  // #include <stdlib.h>
    12  // struct file_obj* newFo() { return (struct file_obj*) malloc(sizeof(struct file_obj)); }
    13  // port_event_t* newPe() { return (port_event_t*) malloc(sizeof(port_event_t)); }
    14  // uintptr_t conv(struct file_obj* fo) { return (uintptr_t) fo; }
    15  // struct file_obj* dconv(uintptr_t fo) { return (struct file_obj*) fo; }
    16  import "C"
    17  
    18  import (
    19  	"syscall"
    20  	"unsafe"
    21  )
    22  
    23  const (
    24  	fileAccess     = Event(C.FILE_ACCESS)
    25  	fileModified   = Event(C.FILE_MODIFIED)
    26  	fileAttrib     = Event(C.FILE_ATTRIB)
    27  	fileDelete     = Event(C.FILE_DELETE)
    28  	fileRenameTo   = Event(C.FILE_RENAME_TO)
    29  	fileRenameFrom = Event(C.FILE_RENAME_FROM)
    30  	fileTrunc      = Event(C.FILE_TRUNC)
    31  	fileNoFollow   = Event(C.FILE_NOFOLLOW)
    32  	unmounted      = Event(C.UNMOUNTED)
    33  	mountedOver    = Event(C.MOUNTEDOVER)
    34  )
    35  
    36  // PortEvent is a notify's equivalent of port_event_t.
    37  type PortEvent struct {
    38  	PortevEvents int         // PortevEvents is an equivalent of portev_events.
    39  	PortevSource uint8       // PortevSource is an equivalent of portev_source.
    40  	PortevPad    uint8       // Portevpad is an equivalent of portev_pad.
    41  	PortevObject interface{} // PortevObject is an equivalent of portev_object.
    42  	PortevUser   uintptr     // PortevUser is an equivalent of portev_user.
    43  }
    44  
    45  // FileObj is a notify's equivalent of file_obj.
    46  type FileObj struct {
    47  	Atim syscall.Timespec // Atim is an equivalent of fo_atime.
    48  	Mtim syscall.Timespec // Mtim is an equivalent of fo_mtime.
    49  	Ctim syscall.Timespec // Ctim is an equivalent of fo_ctime.
    50  	Pad  [3]uintptr       // Pad is an equivalent of fo_pad.
    51  	Name string           // Name is an equivalent of fo_name.
    52  }
    53  
    54  type cfen struct {
    55  	p2pe map[string]*C.port_event_t
    56  	p2fo map[string]*C.struct_file_obj
    57  }
    58  
    59  func newCfen() cfen {
    60  	return cfen{
    61  		p2pe: make(map[string]*C.port_event_t),
    62  		p2fo: make(map[string]*C.struct_file_obj),
    63  	}
    64  }
    65  
    66  func unix2C(sec int64, nsec int64) (C.time_t, C.long) {
    67  	return C.time_t(sec), C.long(nsec)
    68  }
    69  
    70  func (c *cfen) portAssociate(p int, fo FileObj, e int) (err error) {
    71  	cfo := C.newFo()
    72  	cfo.fo_atime.tv_sec, cfo.fo_atime.tv_nsec = unix2C(fo.Atim.Unix())
    73  	cfo.fo_mtime.tv_sec, cfo.fo_mtime.tv_nsec = unix2C(fo.Mtim.Unix())
    74  	cfo.fo_ctime.tv_sec, cfo.fo_ctime.tv_nsec = unix2C(fo.Ctim.Unix())
    75  	cfo.fo_name = C.CString(fo.Name)
    76  	c.p2fo[fo.Name] = cfo
    77  	_, err = C.port_associate(C.int(p), srcFile, C.conv(cfo), C.int(e), nil)
    78  	return
    79  }
    80  
    81  func (c *cfen) portDissociate(port int, fo FileObj) (err error) {
    82  	cfo, ok := c.p2fo[fo.Name]
    83  	if !ok {
    84  		return errNotWatched
    85  	}
    86  	_, err = C.port_dissociate(C.int(port), srcFile, C.conv(cfo))
    87  	C.free(unsafe.Pointer(cfo.fo_name))
    88  	C.free(unsafe.Pointer(cfo))
    89  	delete(c.p2fo, fo.Name)
    90  	return
    91  }
    92  
    93  const srcAlert = C.PORT_SOURCE_ALERT
    94  const srcFile = C.PORT_SOURCE_FILE
    95  const alertSet = C.PORT_ALERT_SET
    96  
    97  func cfo2fo(cfo *C.struct_file_obj) *FileObj {
    98  	// Currently remaining attributes are not used.
    99  	if cfo == nil {
   100  		return nil
   101  	}
   102  	var fo FileObj
   103  	fo.Name = C.GoString(cfo.fo_name)
   104  	return &fo
   105  }
   106  
   107  func (c *cfen) portGet(port int, pe *PortEvent) (err error) {
   108  	cpe := C.newPe()
   109  	if _, err = C.port_get(C.int(port), cpe, nil); err != nil {
   110  		C.free(unsafe.Pointer(cpe))
   111  		return
   112  	}
   113  	pe.PortevEvents, pe.PortevSource, pe.PortevPad =
   114  		int(cpe.portev_events), uint8(cpe.portev_source), uint8(cpe.portev_pad)
   115  	pe.PortevObject = cfo2fo(C.dconv(cpe.portev_object))
   116  	pe.PortevUser = uintptr(cpe.portev_user)
   117  	C.free(unsafe.Pointer(cpe))
   118  	return
   119  }
   120  
   121  func (c *cfen) portCreate() (int, error) {
   122  	p, err := C.port_create()
   123  	return int(p), err
   124  }
   125  
   126  func (c *cfen) portAlert(p int) (err error) {
   127  	_, err = C.port_alert(C.int(p), alertSet, C.int(666), nil)
   128  	return
   129  }
   130  
   131  func (c *cfen) free() {
   132  	for i := range c.p2fo {
   133  		C.free(unsafe.Pointer(c.p2fo[i].fo_name))
   134  		C.free(unsafe.Pointer(c.p2fo[i]))
   135  	}
   136  	for i := range c.p2pe {
   137  		C.free(unsafe.Pointer(c.p2pe[i]))
   138  	}
   139  	c.p2fo = make(map[string]*C.struct_file_obj)
   140  	c.p2pe = make(map[string]*C.port_event_t)
   141  }