Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call getfsstat() and strip mount paths from provided paths ; resolves 49 #58

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,41 @@ func main() {
if err != nil {
log.Fatalf("Failed to create TempDir: %v", err)
}
rootDev, err := fsevents.DeviceForPath("/")
if err != nil {
log.Fatalf("Failed to retrieve device for root path: %v", err)
}

dev, err := fsevents.DeviceForPath(path)
if err != nil {
log.Fatalf("Failed to retrieve device for path: %v", err)
}
log.Print(dev)
if dev == rootDev {
dev = 0
}

log.Println(fsevents.EventIDForDeviceBeforeTime(dev, time.Now()))

es := &fsevents.EventStream{
Paths: []string{path},
Latency: 500 * time.Millisecond,
Device: dev,
Flags: fsevents.FileEvents | fsevents.WatchRoot}
es.Start()
ec := es.Events
Flags: fsevents.FileEvents | fsevents.WatchRoot | fsevents.NoDefer}
if dev != 0 {
es.Resume = true
es.EventID = fsevents.EventIDForDeviceBeforeTime(dev, time.Now())
}

log.Println("Device UUID", fsevents.GetDeviceUUID(dev))
log.Printf("Device UUID %s, device ID: %d, path :%s\n", fsevents.GetDeviceUUID(dev), dev, path)
es.Start()

go func() {
for msg := range ec {
for msg := range es.Events {
for _, event := range msg {
logEvent(event)
}
}
log.Println("Finished logging events")
}()

in := bufio.NewReader(os.Stdin)
Expand Down
85 changes: 73 additions & 12 deletions wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ package fsevents
#cgo LDFLAGS: -framework CoreServices
#include <CoreServices/CoreServices.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>

int getfsstat(struct statfs *buf, int bufsize, int flags);

static CFArrayRef ArrayCreateMutable(int len) {
return CFArrayCreateMutable(NULL, len, &kCFTypeArrayCallBacks);
Expand All @@ -23,6 +28,8 @@ static FSEventStreamRef EventStreamCreate(FSEventStreamContext * context, uintpt
context->info = (void*) info;
return FSEventStreamCreate(NULL, (FSEventStreamCallback) fsevtCallback, context, paths, since, latency, flags);
}


*/
import "C"
import (
Expand All @@ -31,6 +38,8 @@ import (
"path/filepath"
"reflect"
"runtime"
"strings"
"syscall"
"time"
"unsafe"
)
Expand Down Expand Up @@ -150,22 +159,72 @@ func EventIDForDeviceBeforeTime(dev int32, before time.Time) uint64 {
return uint64(C.FSEventsGetLastEventIdForDeviceBeforeTime(C.dev_t(dev), tm))
}

func charsToString(buf []int8) string {
ret := make([]byte, 0, len(buf))
for _, c := range buf {
if c == 0 {
continue
}
ret = append(ret, byte(c))
}
return string(ret)
}

func getRelativePathsForDevices() (map[int32]string, error) {
num, err := syscall.Getfsstat(nil, C.MNT_NOWAIT)
if err != nil {
return nil, err
}

buf := make([]syscall.Statfs_t, num)
_, err = syscall.Getfsstat(buf, C.MNT_NOWAIT)
if err != nil {
return nil, err
}

ret := make(map[int32]string)
for _, fs := range buf[:num] {
ret[fs.Fsid.Val[0]] = charsToString(fs.Mntonname[:])
}

return ret, nil
}

// createPaths accepts the user defined set of paths and returns FSEvents
// compatible array of paths
func createPaths(paths []string) (C.CFArrayRef, error) {
cPaths := C.ArrayCreateMutable(C.int(len(paths)))
var errs []error
for _, path := range paths {
p, err := filepath.Abs(path)
if err != nil {
// hack up some reporting errors, but don't prevent execution
// because of them
errs = append(errs, err)
func createPaths(paths []string, deviceID int32) (C.CFArrayRef, error) {
var (
cPaths = C.ArrayCreateMutable(C.int(len(paths)))
relativePaths map[int32]string
errs []error
str C.CFStringRef
p, path string
err error
)

if deviceID > 0 {
relativePaths, err = getRelativePathsForDevices()
}
for _, path = range paths {
if devicePath, ok := relativePaths[deviceID]; ok {
// Ensure each path is stripped of it's device's mount path
if strings.HasPrefix(filepath.Clean(path), filepath.Clean(devicePath)) {
path = strings.TrimLeft(filepath.Clean(path), filepath.Clean(devicePath))
}
str = makeCFString(path)
} else {
// Use absolute path
p, err = filepath.Abs(path)
if err != nil {
// hack up some reporting errors, but don't prevent execution
// because of them
errs = append(errs, err)
}
str = makeCFString(p)
}
str := makeCFString(p)
C.CFArrayAppendValue(C.CFMutableArrayRef(cPaths), unsafe.Pointer(str))
}
var err error

if len(errs) > 0 {
err = fmt.Errorf("%q", errs)
}
Expand All @@ -188,7 +247,9 @@ func cfArrayLen(ref C.CFArrayRef) int {
}

func setupStream(paths []string, flags CreateFlags, callbackInfo uintptr, eventID uint64, latency time.Duration, deviceID int32) FSEventStreamRef {
cPaths, err := createPaths(paths)

// Use relative paths for devices since the device path is already present; issue #49
cPaths, err := createPaths(paths, deviceID)
if err != nil {
log.Printf("Error creating paths: %s", err)
}
Expand Down