github.com/Hellyna/notify@v0.0.0-20210101060149-8ebdd4ef22cf/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 }