aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/rjeczalik/notify/watcher_fen_cgo.go
blob: 8ec8ead34396e1ae44042c795f4a5d9d2d17332b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// 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

// #include <port.h>
// #include <stdio.h>
// #include <stdlib.h>
// struct file_obj* newFo() { return (struct file_obj*) malloc(sizeof(struct file_obj)); }
// port_event_t* newPe() { return (port_event_t*) malloc(sizeof(port_event_t)); }
// uintptr_t conv(struct file_obj* fo) { return (uintptr_t) fo; }
// struct file_obj* dconv(uintptr_t fo) { return (struct file_obj*) fo; }
import "C"

import (
    "syscall"
    "unsafe"
)

const (
    fileAccess     = Event(C.FILE_ACCESS)
    fileModified   = Event(C.FILE_MODIFIED)
    fileAttrib     = Event(C.FILE_ATTRIB)
    fileDelete     = Event(C.FILE_DELETE)
    fileRenameTo   = Event(C.FILE_RENAME_TO)
    fileRenameFrom = Event(C.FILE_RENAME_FROM)
    fileTrunc      = Event(C.FILE_TRUNC)
    fileNoFollow   = Event(C.FILE_NOFOLLOW)
    unmounted      = Event(C.UNMOUNTED)
    mountedOver    = Event(C.MOUNTEDOVER)
)

// PortEvent is a notify's equivalent of port_event_t.
type PortEvent struct {
    PortevEvents int         // PortevEvents is an equivalent of portev_events.
    PortevSource uint8       // PortevSource is an equivalent of portev_source.
    PortevPad    uint8       // Portevpad is an equivalent of portev_pad.
    PortevObject interface{} // PortevObject is an equivalent of portev_object.
    PortevUser   uintptr     // PortevUser is an equivalent of portev_user.
}

// FileObj is a notify's equivalent of file_obj.
type FileObj struct {
    Atim syscall.Timespec // Atim is an equivalent of fo_atime.
    Mtim syscall.Timespec // Mtim is an equivalent of fo_mtime.
    Ctim syscall.Timespec // Ctim is an equivalent of fo_ctime.
    Pad  [3]uintptr       // Pad is an equivalent of fo_pad.
    Name string           // Name is an equivalent of fo_name.
}

type cfen struct {
    p2pe map[string]*C.port_event_t
    p2fo map[string]*C.struct_file_obj
}

func newCfen() cfen {
    return cfen{
        p2pe: make(map[string]*C.port_event_t),
        p2fo: make(map[string]*C.struct_file_obj),
    }
}

func unix2C(sec int64, nsec int64) (C.time_t, C.long) {
    return C.time_t(sec), C.long(nsec)
}

func (c *cfen) portAssociate(p int, fo FileObj, e int) (err error) {
    cfo := C.newFo()
    cfo.fo_atime.tv_sec, cfo.fo_atime.tv_nsec = unix2C(fo.Atim.Unix())
    cfo.fo_mtime.tv_sec, cfo.fo_mtime.tv_nsec = unix2C(fo.Mtim.Unix())
    cfo.fo_ctime.tv_sec, cfo.fo_ctime.tv_nsec = unix2C(fo.Ctim.Unix())
    cfo.fo_name = C.CString(fo.Name)
    c.p2fo[fo.Name] = cfo
    _, err = C.port_associate(C.int(p), srcFile, C.conv(cfo), C.int(e), nil)
    return
}

func (c *cfen) portDissociate(port int, fo FileObj) (err error) {
    cfo, ok := c.p2fo[fo.Name]
    if !ok {
        return errNotWatched
    }
    _, err = C.port_dissociate(C.int(port), srcFile, C.conv(cfo))
    C.free(unsafe.Pointer(cfo.fo_name))
    C.free(unsafe.Pointer(cfo))
    delete(c.p2fo, fo.Name)
    return
}

const srcAlert = C.PORT_SOURCE_ALERT
const srcFile = C.PORT_SOURCE_FILE
const alertSet = C.PORT_ALERT_SET

func cfo2fo(cfo *C.struct_file_obj) *FileObj {
    // Currently remaining attributes are not used.
    if cfo == nil {
        return nil
    }
    var fo FileObj
    fo.Name = C.GoString(cfo.fo_name)
    return &fo
}

func (c *cfen) portGet(port int, pe *PortEvent) (err error) {
    cpe := C.newPe()
    if _, err = C.port_get(C.int(port), cpe, nil); err != nil {
        C.free(unsafe.Pointer(cpe))
        return
    }
    pe.PortevEvents, pe.PortevSource, pe.PortevPad =
        int(cpe.portev_events), uint8(cpe.portev_source), uint8(cpe.portev_pad)
    pe.PortevObject = cfo2fo(C.dconv(cpe.portev_object))
    pe.PortevUser = uintptr(cpe.portev_user)
    C.free(unsafe.Pointer(cpe))
    return
}

func (c *cfen) portCreate() (int, error) {
    p, err := C.port_create()
    return int(p), err
}

func (c *cfen) portAlert(p int) (err error) {
    _, err = C.port_alert(C.int(p), alertSet, C.int(666), nil)
    return
}

func (c *cfen) free() {
    for i := range c.p2fo {
        C.free(unsafe.Pointer(c.p2fo[i].fo_name))
        C.free(unsafe.Pointer(c.p2fo[i]))
    }
    for i := range c.p2pe {
        C.free(unsafe.Pointer(c.p2pe[i]))
    }
    c.p2fo = make(map[string]*C.struct_file_obj)
    c.p2pe = make(map[string]*C.port_event_t)
}