OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [exp/] [inotify/] [inotify_linux.go] - Blame information for rev 775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2010 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
/*
6
Package inotify implements a wrapper for the Linux inotify system.
7
 
8
Example:
9
    watcher, err := inotify.NewWatcher()
10
    if err != nil {
11
        log.Fatal(err)
12
    }
13
    err = watcher.Watch("/tmp")
14
    if err != nil {
15
        log.Fatal(err)
16
    }
17
    for {
18
        select {
19
        case ev := <-watcher.Event:
20
            log.Println("event:", ev)
21
        case err := <-watcher.Error:
22
            log.Println("error:", err)
23
        }
24
    }
25
 
26
*/
27
package inotify
28
 
29
import (
30
        "errors"
31
        "fmt"
32
        "os"
33
        "strings"
34
        "syscall"
35
        "unsafe"
36
)
37
 
38
type Event struct {
39
        Mask   uint32 // Mask of events
40
        Cookie uint32 // Unique cookie associating related events (for rename(2))
41
        Name   string // File name (optional)
42
}
43
 
44
type watch struct {
45
        wd    uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
46
        flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
47
}
48
 
49
type Watcher struct {
50
        fd       int               // File descriptor (as returned by the inotify_init() syscall)
51
        watches  map[string]*watch // Map of inotify watches (key: path)
52
        paths    map[int]string    // Map of watched paths (key: watch descriptor)
53
        Error    chan error        // Errors are sent on this channel
54
        Event    chan *Event       // Events are returned on this channel
55
        done     chan bool         // Channel for sending a "quit message" to the reader goroutine
56
        isClosed bool              // Set to true when Close() is first called
57
}
58
 
59
// NewWatcher creates and returns a new inotify instance using inotify_init(2)
60
func NewWatcher() (*Watcher, error) {
61
        fd, errno := syscall.InotifyInit()
62
        if fd == -1 {
63
                return nil, os.NewSyscallError("inotify_init", errno)
64
        }
65
        w := &Watcher{
66
                fd:      fd,
67
                watches: make(map[string]*watch),
68
                paths:   make(map[int]string),
69
                Event:   make(chan *Event),
70
                Error:   make(chan error),
71
                done:    make(chan bool, 1),
72
        }
73
 
74
        go w.readEvents()
75
        return w, nil
76
}
77
 
78
// Close closes an inotify watcher instance
79
// It sends a message to the reader goroutine to quit and removes all watches
80
// associated with the inotify instance
81
func (w *Watcher) Close() error {
82
        if w.isClosed {
83
                return nil
84
        }
85
        w.isClosed = true
86
 
87
        // Send "quit" message to the reader goroutine
88
        w.done <- true
89
        for path := range w.watches {
90
                w.RemoveWatch(path)
91
        }
92
 
93
        return nil
94
}
95
 
96
// AddWatch adds path to the watched file set.
97
// The flags are interpreted as described in inotify_add_watch(2).
98
func (w *Watcher) AddWatch(path string, flags uint32) error {
99
        if w.isClosed {
100
                return errors.New("inotify instance already closed")
101
        }
102
 
103
        watchEntry, found := w.watches[path]
104
        if found {
105
                watchEntry.flags |= flags
106
                flags |= syscall.IN_MASK_ADD
107
        }
108
        wd, err := syscall.InotifyAddWatch(w.fd, path, flags)
109
        if err != nil {
110
                return &os.PathError{
111
                        Op:   "inotify_add_watch",
112
                        Path: path,
113
                        Err:  err,
114
                }
115
        }
116
 
117
        if !found {
118
                w.watches[path] = &watch{wd: uint32(wd), flags: flags}
119
                w.paths[wd] = path
120
        }
121
        return nil
122
}
123
 
124
// Watch adds path to the watched file set, watching all events.
125
func (w *Watcher) Watch(path string) error {
126
        return w.AddWatch(path, IN_ALL_EVENTS)
127
}
128
 
129
// RemoveWatch removes path from the watched file set.
130
func (w *Watcher) RemoveWatch(path string) error {
131
        watch, ok := w.watches[path]
132
        if !ok {
133
                return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
134
        }
135
        success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
136
        if success == -1 {
137
                return os.NewSyscallError("inotify_rm_watch", errno)
138
        }
139
        delete(w.watches, path)
140
        return nil
141
}
142
 
143
// readEvents reads from the inotify file descriptor, converts the
144
// received events into Event objects and sends them via the Event channel
145
func (w *Watcher) readEvents() {
146
        var buf [syscall.SizeofInotifyEvent * 4096]byte
147
 
148
        for {
149
                n, err := syscall.Read(w.fd, buf[0:])
150
                // See if there is a message on the "done" channel
151
                var done bool
152
                select {
153
                case done = <-w.done:
154
                default:
155
                }
156
 
157
                // If EOF or a "done" message is received
158
                if n == 0 || done {
159
                        err := syscall.Close(w.fd)
160
                        if err != nil {
161
                                w.Error <- os.NewSyscallError("close", err)
162
                        }
163
                        close(w.Event)
164
                        close(w.Error)
165
                        return
166
                }
167
                if n < 0 {
168
                        w.Error <- os.NewSyscallError("read", err)
169
                        continue
170
                }
171
                if n < syscall.SizeofInotifyEvent {
172
                        w.Error <- errors.New("inotify: short read in readEvents()")
173
                        continue
174
                }
175
 
176
                var offset uint32 = 0
177
                // We don't know how many events we just read into the buffer
178
                // While the offset points to at least one whole event...
179
                for offset <= uint32(n-syscall.SizeofInotifyEvent) {
180
                        // Point "raw" to the event in the buffer
181
                        raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
182
                        event := new(Event)
183
                        event.Mask = uint32(raw.Mask)
184
                        event.Cookie = uint32(raw.Cookie)
185
                        nameLen := uint32(raw.Len)
186
                        // If the event happened to the watched directory or the watched file, the kernel
187
                        // doesn't append the filename to the event, but we would like to always fill the
188
                        // the "Name" field with a valid filename. We retrieve the path of the watch from
189
                        // the "paths" map.
190
                        event.Name = w.paths[int(raw.Wd)]
191
                        if nameLen > 0 {
192
                                // Point "bytes" at the first byte of the filename
193
                                bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
194
                                // The filename is padded with NUL bytes. TrimRight() gets rid of those.
195
                                event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
196
                        }
197
                        // Send the event on the events channel
198
                        w.Event <- event
199
 
200
                        // Move to the next event in the buffer
201
                        offset += syscall.SizeofInotifyEvent + nameLen
202
                }
203
        }
204
}
205
 
206
// String formats the event e in the form
207
// "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
208
func (e *Event) String() string {
209
        var events string = ""
210
 
211
        m := e.Mask
212
        for _, b := range eventBits {
213
                if m&b.Value != 0 {
214
                        m &^= b.Value
215
                        events += "|" + b.Name
216
                }
217
        }
218
 
219
        if m != 0 {
220
                events += fmt.Sprintf("|%#x", m)
221
        }
222
        if len(events) > 0 {
223
                events = " == " + events[1:]
224
        }
225
 
226
        return fmt.Sprintf("%q: %#x%s", e.Name, e.Mask, events)
227
}
228
 
229
const (
230
        // Options for inotify_init() are not exported
231
        // IN_CLOEXEC    uint32 = syscall.IN_CLOEXEC
232
        // IN_NONBLOCK   uint32 = syscall.IN_NONBLOCK
233
 
234
        // Options for AddWatch
235
        IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
236
        IN_ONESHOT     uint32 = syscall.IN_ONESHOT
237
        IN_ONLYDIR     uint32 = syscall.IN_ONLYDIR
238
 
239
        // The "IN_MASK_ADD" option is not exported, as AddWatch
240
        // adds it automatically, if there is already a watch for the given path
241
        // IN_MASK_ADD      uint32 = syscall.IN_MASK_ADD
242
 
243
        // Events
244
        IN_ACCESS        uint32 = syscall.IN_ACCESS
245
        IN_ALL_EVENTS    uint32 = syscall.IN_ALL_EVENTS
246
        IN_ATTRIB        uint32 = syscall.IN_ATTRIB
247
        IN_CLOSE         uint32 = syscall.IN_CLOSE
248
        IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
249
        IN_CLOSE_WRITE   uint32 = syscall.IN_CLOSE_WRITE
250
        IN_CREATE        uint32 = syscall.IN_CREATE
251
        IN_DELETE        uint32 = syscall.IN_DELETE
252
        IN_DELETE_SELF   uint32 = syscall.IN_DELETE_SELF
253
        IN_MODIFY        uint32 = syscall.IN_MODIFY
254
        IN_MOVE          uint32 = syscall.IN_MOVE
255
        IN_MOVED_FROM    uint32 = syscall.IN_MOVED_FROM
256
        IN_MOVED_TO      uint32 = syscall.IN_MOVED_TO
257
        IN_MOVE_SELF     uint32 = syscall.IN_MOVE_SELF
258
        IN_OPEN          uint32 = syscall.IN_OPEN
259
 
260
        // Special events
261
        IN_ISDIR      uint32 = syscall.IN_ISDIR
262
        IN_IGNORED    uint32 = syscall.IN_IGNORED
263
        IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
264
        IN_UNMOUNT    uint32 = syscall.IN_UNMOUNT
265
)
266
 
267
var eventBits = []struct {
268
        Value uint32
269
        Name  string
270
}{
271
        {IN_ACCESS, "IN_ACCESS"},
272
        {IN_ATTRIB, "IN_ATTRIB"},
273
        {IN_CLOSE, "IN_CLOSE"},
274
        {IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE"},
275
        {IN_CLOSE_WRITE, "IN_CLOSE_WRITE"},
276
        {IN_CREATE, "IN_CREATE"},
277
        {IN_DELETE, "IN_DELETE"},
278
        {IN_DELETE_SELF, "IN_DELETE_SELF"},
279
        {IN_MODIFY, "IN_MODIFY"},
280
        {IN_MOVE, "IN_MOVE"},
281
        {IN_MOVED_FROM, "IN_MOVED_FROM"},
282
        {IN_MOVED_TO, "IN_MOVED_TO"},
283
        {IN_MOVE_SELF, "IN_MOVE_SELF"},
284
        {IN_OPEN, "IN_OPEN"},
285
        {IN_ISDIR, "IN_ISDIR"},
286
        {IN_IGNORED, "IN_IGNORED"},
287
        {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"},
288
        {IN_UNMOUNT, "IN_UNMOUNT"},
289
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.