From 7010dc6b17fcf9a3dc7c50a66a3f5b346e4bd225 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 11:01:23 +0000 Subject: [PATCH 01/65] Added fuse dep --- go.mod | 1 + go.sum | 3 +++ 2 files changed, 4 insertions(+) diff --git a/go.mod b/go.mod index 80df00c..668793a 100644 --- a/go.mod +++ b/go.mod @@ -45,6 +45,7 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/gookit/color v1.5.1 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect + github.com/hanwen/go-fuse/v2 v2.2.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect diff --git a/go.sum b/go.sum index 0d78863..577ffe0 100644 --- a/go.sum +++ b/go.sum @@ -257,6 +257,8 @@ github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfI github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hanwen/go-fuse/v2 v2.2.0 h1:jo5QZYmBLNcl9ovypWaQ5yXMSSV+Ch68xoC3rtZvvBM= +github.com/hanwen/go-fuse/v2 v2.2.0/go.mod h1:B1nGE/6RBFyBRC1RRnf23UpwCdyJ31eukw34oAKukAc= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -339,6 +341,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -- 2.40.1 From 3a8888c003b721c808e059ab411ca41f848c6e7f Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 11:50:02 +0000 Subject: [PATCH 02/65] Added FUSE example --- fuse/main.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 fuse/main.go diff --git a/fuse/main.go b/fuse/main.go new file mode 100644 index 0000000..01c4437 --- /dev/null +++ b/fuse/main.go @@ -0,0 +1,85 @@ +package main + +import ( + "log" + "os" + "context" + "syscall" + "github.com/hanwen/go-fuse/v2/fs" + "github.com/hanwen/go-fuse/v2/fuse" +) + +type ITNode struct { + fs.Inode + kind int +} + +var _ = (fs.NodeReaddirer)((*ITNode)(nil)) + +// Readdir is part of the NodeReaddirer interface +func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { + if n.kind == 0 { + // root folder + r := make([]fuse.DirEntry, 2) + r[0] = fuse.DirEntry{ + Name: "device", + Ino: 0, + Mode: fuse.S_IFDIR, + } + r[1] = fuse.DirEntry{ + Name: "fs", + Ino: 1, + Mode: fuse.S_IFDIR, + } + return fs.NewListDirStream(r), 0 + } + r := make([]fuse.DirEntry, 0) + return fs.NewListDirStream(r), 0 +} + +var _ = (fs.NodeLookuper)((*ITNode)(nil)) +func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) { + if n.kind == 0 { + if name == "device" { + stable := fs.StableAttr{ + Mode: fuse.S_IFDIR, + Ino: uint64(0), + } + operations := &ITNode{kind: 1} + child := n.NewInode(ctx, operations, stable) + return child, 0 + } else if name == "fs" { + stable := fs.StableAttr{ + Mode: fuse.S_IFDIR, + Ino: uint64(1), + } + operations := &ITNode{kind: 2} + child := n.NewInode(ctx, operations, stable) + return child, 0 + } + } + return nil, syscall.ENOENT +} + + +func main() { + // This is where we'll mount the FS + mntDir := "/tmp/x" + os.Mkdir(mntDir, 0755) + root := &ITNode{kind: 0} + server, err := fs.Mount(mntDir, root, &fs.Options{ + MountOptions: fuse.MountOptions{ + // Set to true to see how the file system works. + Debug: false, + }, + }) + if err != nil { + log.Panic(err) + } + + log.Printf("Mounted on %s", mntDir) + log.Printf("Unmount by calling 'fusermount -u %s'", mntDir) + + // Wait until unmount before exiting + server.Wait() +} -- 2.40.1 From b820d6a674b62e408102c742b26fa0f044ef697f Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 12:08:45 +0000 Subject: [PATCH 03/65] Used switch instead of if --- fuse/main.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fuse/main.go b/fuse/main.go index 01c4437..371acd9 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -18,7 +18,8 @@ var _ = (fs.NodeReaddirer)((*ITNode)(nil)) // Readdir is part of the NodeReaddirer interface func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { - if n.kind == 0 { + switch n.kind { + case 0: // root folder r := make([]fuse.DirEntry, 2) r[0] = fuse.DirEntry{ @@ -39,7 +40,9 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { var _ = (fs.NodeLookuper)((*ITNode)(nil)) func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) { - if n.kind == 0 { + switch n.kind { + case 0: + // root folder if name == "device" { stable := fs.StableAttr{ Mode: fuse.S_IFDIR, -- 2.40.1 From 0e0bfdc1f4619270476a51479aed207a1f4538d3 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 12:08:56 +0000 Subject: [PATCH 04/65] Defined ITProperties --- fuse/main.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index 371acd9..7d45c6e 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -9,11 +9,25 @@ import ( "github.com/hanwen/go-fuse/v2/fuse" ) +type ITProperty struct { + name string + Ino uint64 +} + type ITNode struct { fs.Inode kind int } +var properties = []ITProperty { + ITProperty{"heartrate", 2}, + ITProperty{"battery", 3}, + ITProperty{"motion", 4}, + ITProperty{"stepcount", 5}, + ITProperty{"version", 6}, + ITProperty{"address", 7}, +} + var _ = (fs.NodeReaddirer)((*ITNode)(nil)) // Readdir is part of the NodeReaddirer interface @@ -33,6 +47,19 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { Mode: fuse.S_IFDIR, } return fs.NewListDirStream(r), 0 + + case 1: + // device folder + r := make([]fuse.DirEntry, 6) + for ind, value := range properties { + r[ind] = fuse.DirEntry{ + Name: value.name, + Ino: value.Ino, + Mode: fuse.S_IFREG, + } + } + + return fs.NewListDirStream(r), 0 } r := make([]fuse.DirEntry, 0) return fs.NewListDirStream(r), 0 @@ -60,6 +87,20 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* child := n.NewInode(ctx, operations, stable) return child, 0 } + case 1: + // device folder + for _, value := range properties { + if value.name == name { + stable := fs.StableAttr{ + Mode: fuse.S_IFREG, + Ino: uint64(value.Ino), + } + operations := &ITNode{kind: 3} + child := n.NewInode(ctx, operations, stable) + return child, 0 + } + } + return nil, syscall.ENOENT } return nil, syscall.ENOENT } -- 2.40.1 From eb745def04636a9bae675500dbdb15198d7ad3bb Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 12:23:18 +0000 Subject: [PATCH 05/65] Store inode in ITNode --- fuse/main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fuse/main.go b/fuse/main.go index 7d45c6e..c4580cb 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -17,6 +17,7 @@ type ITProperty struct { type ITNode struct { fs.Inode kind int + Ino uint64 } var properties = []ITProperty { @@ -75,7 +76,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* Mode: fuse.S_IFDIR, Ino: uint64(0), } - operations := &ITNode{kind: 1} + operations := &ITNode{kind: 1, Ino: 0} child := n.NewInode(ctx, operations, stable) return child, 0 } else if name == "fs" { @@ -83,7 +84,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* Mode: fuse.S_IFDIR, Ino: uint64(1), } - operations := &ITNode{kind: 2} + operations := &ITNode{kind: 2, Ino: 1} child := n.NewInode(ctx, operations, stable) return child, 0 } @@ -95,7 +96,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* Mode: fuse.S_IFREG, Ino: uint64(value.Ino), } - operations := &ITNode{kind: 3} + operations := &ITNode{kind: 3, Ino: value.Ino} child := n.NewInode(ctx, operations, stable) return child, 0 } -- 2.40.1 From 5008cdd4f408ab0e8007f2c847a339ece9f08b80 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 12:23:44 +0000 Subject: [PATCH 06/65] Define reader --- fuse/main.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index c4580cb..b6c762f 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -106,6 +106,41 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* return nil, syscall.ENOENT } +type bytesFileHandle struct { + content []byte +} +var _ = (fs.FileReader)((*bytesFileHandle)(nil)) + +func (fh *bytesFileHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { + end := off + int64(len(dest)) + if end > int64(len(fh.content)) { + end = int64(len(fh.content)) + } + return fuse.ReadResultData(fh.content[off:end]), 0 +} + +var _ = (fs.NodeOpener)((*ITNode)(nil)) +func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { + switch f.kind { + case 3: + // Device file + + // disallow writes + if fuseFlags&(syscall.O_RDWR|syscall.O_WRONLY) != 0 { + return nil, 0, syscall.EROFS + } + + for _, value := range properties { + if value.Ino == f.Ino { + fh = &bytesFileHandle{ + content: []byte(value.name), + } + return fh, fuse.FOPEN_DIRECT_IO, 0 + } + } + } + return nil, 0, syscall.EROFS +} func main() { // This is where we'll mount the FS -- 2.40.1 From 4a18622d37ec429a763eec73bf14ea146ae40dc7 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 12:59:40 +0000 Subject: [PATCH 07/65] Added functions for variables --- fuse/main.go | 56 +++++++++++++++++++++++++++++++++++++++++++++------- fuse/mock.go | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 fuse/mock.go diff --git a/fuse/main.go b/fuse/main.go index b6c762f..938ac04 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -7,11 +7,39 @@ import ( "syscall" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" + "strconv" ) +func (i *Device) HeartRateBytes() ([]byte, error) { + v, err := i.HeartRate() + return []byte(strconv.Itoa(int(v)) + "\n"), err +} +func (i *Device) BatteryLevelBytes() ([]byte, error) { + v, err := i.BatteryLevel() + return []byte(strconv.Itoa(int(v)) + "\n"), err +} +func (i *Device) StepCountBytes() ([]byte, error) { + v, err := i.StepCount() + return []byte(strconv.Itoa(int(v)) + "\n"), err +} +func (i *Device) MotionBytes() ([]byte, error) { + v, err := i.Motion() + return []byte(strconv.Itoa(int(v.X)) + " " + strconv.Itoa(int(v.Y)) + " " + strconv.Itoa(int(v.Z)) + "\n"), err +} +func (i *Device) AddressBytes() ([]byte, error) { + v := i.Address() + return []byte(v + "\n"), nil +} +func (i *Device) VersionBytes() ([]byte, error) { + v, err := i.Version() + return []byte(v + "\n"), err +} + + type ITProperty struct { name string Ino uint64 + f func() ([]byte, error) } type ITNode struct { @@ -21,12 +49,12 @@ type ITNode struct { } var properties = []ITProperty { - ITProperty{"heartrate", 2}, - ITProperty{"battery", 3}, - ITProperty{"motion", 4}, - ITProperty{"stepcount", 5}, - ITProperty{"version", 6}, - ITProperty{"address", 7}, + ITProperty{"heartrate", 2, nil}, + ITProperty{"battery", 3, nil}, + ITProperty{"motion", 4, nil}, + ITProperty{"stepcount", 5, nil}, + ITProperty{"version", 6, nil}, + ITProperty{"address", 7, nil}, } var _ = (fs.NodeReaddirer)((*ITNode)(nil)) @@ -132,8 +160,13 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, for _, value := range properties { if value.Ino == f.Ino { + ans, err := value.f() + if err != nil { + return nil, 0, syscall.EROFS + } + fh = &bytesFileHandle{ - content: []byte(value.name), + content: ans, } return fh, fuse.FOPEN_DIRECT_IO, 0 } @@ -157,6 +190,15 @@ func main() { log.Panic(err) } + dev := Device{}; + + properties[0].f = dev.HeartRateBytes; + properties[1].f = dev.BatteryLevelBytes; + properties[2].f = dev.MotionBytes; + properties[3].f = dev.StepCountBytes; + properties[4].f = dev.VersionBytes; + properties[5].f = dev.AddressBytes; + log.Printf("Mounted on %s", mntDir) log.Printf("Unmount by calling 'fusermount -u %s'", mntDir) diff --git a/fuse/mock.go b/fuse/mock.go new file mode 100644 index 0000000..7df66b1 --- /dev/null +++ b/fuse/mock.go @@ -0,0 +1,35 @@ +package main + +type Device struct { + +} + +func (i *Device) HeartRate() (uint8, error) { + return 10, nil +} + +func (i *Device) BatteryLevel() (uint8, error) { + return 95, nil +} + +func (i *Device) StepCount() (uint32, error) { + return 27000, nil +} + +type MotionValues struct { + X int16 + Y int16 + Z int16 +} + +func (i *Device) Motion() (MotionValues, error) { + return MotionValues{-12, +64, -19}, nil +} + +func (i *Device) Address() string { + return "FA:E4:00:00:00:00" +} + +func (i *Device) Version() (string, error) { + return "1.11.0", nil +} -- 2.40.1 From e4f8d0b55124920b888b30627febe3e28428c65b Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 13:13:02 +0000 Subject: [PATCH 08/65] Updated mock interfaces --- fuse/mock.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/fuse/mock.go b/fuse/mock.go index 7df66b1..17af7d0 100644 --- a/fuse/mock.go +++ b/fuse/mock.go @@ -1,8 +1,40 @@ package main +import ( + "io/fs" + "errors" +) + +var ( + ErrFileNotExists = errors.New("file does not exist") + ErrFileReadOnly = errors.New("file is read only") + ErrFileWriteOnly = errors.New("file is write only") + ErrInvalidOffset = errors.New("invalid file offset") + ErrOffsetChanged = errors.New("offset has already been changed") + ErrReadOpen = errors.New("only one file can be opened for reading at a time") + ErrWriteOpen = errors.New("only one file can be opened for writing at a time") + ErrNoRemoveRoot = errors.New("refusing to remove root directory") +) type Device struct { - } +type FS struct { +} + + +type File struct { + fs *FS + path string + offset uint32 + offsetCh chan uint32 + length uint32 + amtLeft uint32 + amtTferd uint32 + isReadOnly bool + isWriteOnly bool + offsetChanged bool +} + + func (i *Device) HeartRate() (uint8, error) { return 10, nil @@ -33,3 +65,42 @@ func (i *Device) Address() string { func (i *Device) Version() (string, error) { return "1.11.0", nil } + +func (blefs *FS) ReadDir(path string) ([]fs.DirEntry, error) { + var out []fs.DirEntry + return out, nil +} + +func (blefs *FS) Mkdir(path string) error { + return nil +} + +func (blefs *FS) Stat(path string) (fs.FileInfo, error) { + return nil, ErrFileNotExists +} + +func (blefs *FS) Rename(old, new string) error { + return nil +} + +func (blefs *FS) Remove(path string) error { + return nil +} + +func (blefs *FS) Open(path string) (*File, error) { + return &File{}, nil +} +func (blefs *FS) Create(path string, size uint32) (*File, error) { + return &File{}, nil +} +func (fl *File) Read(b []byte) (n int, err error) { + return 0, ErrFileWriteOnly +} +func (fl *File) Write(b []byte) (n int, err error) { + return 0, ErrFileWriteOnly +} +func (fl *File) Close() error { + return nil +} +// func (fl *File) Stat() (fs.FileInfo, error) { +// } -- 2.40.1 From a5d70e373ccad0aadf79811040c5f676b7ffd558 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 14:23:04 +0000 Subject: [PATCH 09/65] Implemented mocks --- fuse/mock.go | 87 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 23 deletions(-) diff --git a/fuse/mock.go b/fuse/mock.go index 17af7d0..9487758 100644 --- a/fuse/mock.go +++ b/fuse/mock.go @@ -1,9 +1,15 @@ package main import ( - "io/fs" + "os" + "io/ioutil" "errors" ) +const ( + FSStatusOk = 0x01 + FSStatusError = 0x02 +) + var ( ErrFileNotExists = errors.New("file does not exist") ErrFileReadOnly = errors.New("file is read only") @@ -20,18 +26,20 @@ type Device struct { type FS struct { } +type DirEntry struct { + status int8 + flags uint32 + modtime uint64 + size uint32 + path string +} type File struct { fs *FS path string - offset uint32 - offsetCh chan uint32 - length uint32 - amtLeft uint32 - amtTferd uint32 + fp *os.File isReadOnly bool isWriteOnly bool - offsetChanged bool } @@ -66,41 +74,74 @@ func (i *Device) Version() (string, error) { return "1.11.0", nil } -func (blefs *FS) ReadDir(path string) ([]fs.DirEntry, error) { - var out []fs.DirEntry +func (blefs *FS) ReadDir(path string) ([]DirEntry, error) { + var out []DirEntry + files, err := ioutil.ReadDir("./root/" + path) + + if err != nil { + return nil, nil + } + + for _, f := range files { + listing := DirEntry{} + listing.status = FSStatusOk + listing.modtime = uint64(f.ModTime().Unix()) + listing.size = uint32(f.Size()) + listing.path = path + "/" + f.Name() + if f.IsDir() { + listing.flags = 1; + } else { + listing.flags = 0; + } + out = append(out, listing) + } return out, nil } func (blefs *FS) Mkdir(path string) error { - return nil -} - -func (blefs *FS) Stat(path string) (fs.FileInfo, error) { - return nil, ErrFileNotExists + return os.Mkdir("./root/" + path, os.ModePerm) } func (blefs *FS) Rename(old, new string) error { - return nil + return os.Rename("./root/" + old, "./root/" + new) } func (blefs *FS) Remove(path string) error { - return nil + return os.Remove("./root/" + path) } func (blefs *FS) Open(path string) (*File, error) { - return &File{}, nil + fp, _ := os.Open("./root/" + path) + return &File{ + fs : blefs, + path : path, + fp : fp, + isReadOnly : true, + isWriteOnly : false, + }, nil } func (blefs *FS) Create(path string, size uint32) (*File, error) { - return &File{}, nil + fp, _ := os.Create("./root/" + path) + return &File{ + fs : blefs, + path : path, + fp : fp, + isReadOnly : false, + isWriteOnly : true, + }, nil } func (fl *File) Read(b []byte) (n int, err error) { - return 0, ErrFileWriteOnly + if fl.isWriteOnly { + return 0, ErrFileWriteOnly + } + return fl.fp.Read(b) } func (fl *File) Write(b []byte) (n int, err error) { - return 0, ErrFileWriteOnly + if fl.isReadOnly { + return 0, ErrFileReadOnly + } + return fl.fp.Write(b) } func (fl *File) Close() error { - return nil + return fl.fp.Close() } -// func (fl *File) Stat() (fs.FileInfo, error) { -// } -- 2.40.1 From d04af07dbed29f09bd5303e3f038f383d9ddab2b Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 14:49:53 +0000 Subject: [PATCH 10/65] Implemented ReadDir --- fuse/main.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/fuse/main.go b/fuse/main.go index 938ac04..c5e60c5 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -8,6 +8,7 @@ import ( "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" "strconv" + "strings" ) func (i *Device) HeartRateBytes() ([]byte, error) { @@ -46,6 +47,9 @@ type ITNode struct { fs.Inode kind int Ino uint64 + + lst []DirEntry + path string } var properties = []ITProperty { @@ -56,6 +60,8 @@ var properties = []ITProperty { ITProperty{"version", 6, nil}, ITProperty{"address", 7, nil}, } +var myfs *FS = nil; +var inodemap map[string]uint64 = nil; var _ = (fs.NodeReaddirer)((*ITNode)(nil)) @@ -89,6 +95,36 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { } return fs.NewListDirStream(r), 0 + + case 2: + // on device + files, _ := myfs.ReadDir(n.path) + r := make([]fuse.DirEntry, len(files)) + n.lst = files + for ind, file := range files { + name := file.path[strings.LastIndex(file.path, "/")+1:] + + ino := inodemap[file.path] + if ino == 0 { + ino = uint64(len(inodemap)) + 1 + inodemap[file.path] = ino + } + + if file.flags & 0b1 == 1 { + r[ind] = fuse.DirEntry{ + Name: name, + Mode: fuse.S_IFDIR, + Ino : ino + 10, + } + } else { + r[ind] = fuse.DirEntry{ + Name: name, + Mode: fuse.S_IFREG, + Ino : ino + 10, + } + } + } + return fs.NewListDirStream(r), 0 } r := make([]fuse.DirEntry, 0) return fs.NewListDirStream(r), 0 @@ -112,7 +148,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* Mode: fuse.S_IFDIR, Ino: uint64(1), } - operations := &ITNode{kind: 2, Ino: 1} + operations := &ITNode{kind: 2, Ino: 1, path : ""} child := n.NewInode(ctx, operations, stable) return child, 0 } @@ -130,6 +166,34 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* } } return nil, syscall.ENOENT + + case 2: + // FS object + for _, file := range n.lst { + if file.path != n.path + "/" + name { + continue; + } + log.Println("matched", name) + + if file.flags & 0b1 == 1 { + stable := fs.StableAttr{ + Mode: fuse.S_IFDIR, + Ino: inodemap[file.path], + } + operations := &ITNode{kind: 2, path: file.path} + child := n.NewInode(ctx, operations, stable) + return child, 0 + } else { + stable := fs.StableAttr{ + Mode: fuse.S_IFREG, + Ino: inodemap[file.path], + } + operations := &ITNode{kind: 2, path: file.path} + child := n.NewInode(ctx, operations, stable) + return child, 0 + } + break; + } } return nil, syscall.ENOENT } @@ -202,6 +266,9 @@ func main() { log.Printf("Mounted on %s", mntDir) log.Printf("Unmount by calling 'fusermount -u %s'", mntDir) + myfs = &FS{}; + inodemap = make(map[string]uint64) + // Wait until unmount before exiting server.Wait() } -- 2.40.1 From a8dc017a48d73b89b3b9716082f62b50253048f3 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 16:54:19 +0000 Subject: [PATCH 11/65] Implemented Read --- fuse/main.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/fuse/main.go b/fuse/main.go index c5e60c5..769f593 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -49,6 +49,7 @@ type ITNode struct { Ino uint64 lst []DirEntry + self DirEntry path string } @@ -188,7 +189,10 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* Mode: fuse.S_IFREG, Ino: inodemap[file.path], } - operations := &ITNode{kind: 2, path: file.path} + operations := &ITNode{ + kind: 2, path: file.path, + self: file, + } child := n.NewInode(ctx, operations, stable) return child, 0 } @@ -214,6 +218,24 @@ func (fh *bytesFileHandle) Read(ctx context.Context, dest []byte, off int64) (fu var _ = (fs.NodeOpener)((*ITNode)(nil)) func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { switch f.kind { + case 2: + // FS file + fp, err := myfs.Open(f.path) + if err != nil { + return nil, 0, syscall.EROFS + } + + buf := make([]byte, f.self.size); + nread, err := fp.Read(buf) + if err != nil || nread != int(f.self.size) { + return nil, 0, syscall.EROFS + } + + fh = &bytesFileHandle{ + content: buf, + } + return fh, fuse.FOPEN_DIRECT_IO, 0 + case 3: // Device file -- 2.40.1 From 2a8de96773a730bee37d7301ff892ec0fed936f3 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 19:00:20 +0000 Subject: [PATCH 12/65] Implemented Write --- fuse/main.go | 76 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/fuse/main.go b/fuse/main.go index 769f593..a0643bb 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -202,12 +202,12 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* return nil, syscall.ENOENT } -type bytesFileHandle struct { +type bytesFileReadHandle struct { content []byte } -var _ = (fs.FileReader)((*bytesFileHandle)(nil)) +var _ = (fs.FileReader)((*bytesFileReadHandle)(nil)) -func (fh *bytesFileHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { +func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { end := off + int64(len(dest)) if end > int64(len(fh.content)) { end = int64(len(fh.content)) @@ -215,32 +215,78 @@ func (fh *bytesFileHandle) Read(ctx context.Context, dest []byte, off int64) (fu return fuse.ReadResultData(fh.content[off:end]), 0 } +type bytesFileWriteHandle struct { + content []byte + path string +} + +var _ = (fs.FileWriter)((*bytesFileWriteHandle)(nil)) +func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int64) (written uint32, errno syscall.Errno) { + if off != int64(len(fh.content)) { + } + fh.content = append(fh.content[:], data[:]...) + return uint32(len(data)), 0 +} + +var _ = (fs.FileFlusher)((*bytesFileWriteHandle)(nil)) +func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) { + fp, err := myfs.Create(fh.path, uint32(len(fh.content))) + if err != nil { + return syscall.EROFS + } + nread, err := fp.Write(fh.content) + if err != nil || nread != len(fh.content) { + return syscall.EROFS + } + + return 0 +} + +var _ = (fs.NodeSetattrer)((*ITNode)(nil)) +func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno { + out.Size = 0; + out.Mtime = 0; + return 0 +} + var _ = (fs.NodeOpener)((*ITNode)(nil)) func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { switch f.kind { case 2: // FS file - fp, err := myfs.Open(f.path) - if err != nil { + if openFlags&syscall.O_RDWR != 0 { return nil, 0, syscall.EROFS } - buf := make([]byte, f.self.size); - nread, err := fp.Read(buf) - if err != nil || nread != int(f.self.size) { - return nil, 0, syscall.EROFS - } + if openFlags & syscall.O_WRONLY != 0 { + fh = &bytesFileWriteHandle{ + path : f.path, + content : make([]byte, 0), + } + return fh, fuse.FOPEN_DIRECT_IO, 0 + } else { + fp, err := myfs.Open(f.path) + if err != nil { + return nil, 0, syscall.EROFS + } - fh = &bytesFileHandle{ - content: buf, + buf := make([]byte, f.self.size); + nread, err := fp.Read(buf) + if err != nil || nread != int(f.self.size) { + return nil, 0, syscall.EROFS + } + + fh = &bytesFileReadHandle{ + content: buf, + } + return fh, fuse.FOPEN_DIRECT_IO, 0 } - return fh, fuse.FOPEN_DIRECT_IO, 0 case 3: // Device file // disallow writes - if fuseFlags&(syscall.O_RDWR|syscall.O_WRONLY) != 0 { + if openFlags&(syscall.O_RDWR|syscall.O_WRONLY) != 0 { return nil, 0, syscall.EROFS } @@ -251,7 +297,7 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, return nil, 0, syscall.EROFS } - fh = &bytesFileHandle{ + fh = &bytesFileReadHandle{ content: ans, } return fh, fuse.FOPEN_DIRECT_IO, 0 -- 2.40.1 From 74afbc7c20fe39060997708a99b02690d59dd804 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 19:11:46 +0000 Subject: [PATCH 13/65] Implemented Getattr --- fuse/main.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index a0643bb..6f24473 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -242,6 +242,16 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) return 0 } +var _ = (fs.NodeGetattrer)((*ITNode)(nil)) +func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno { + out.Ino = bn.Ino + out.Mtime = bn.self.modtime + out.Ctime = bn.self.modtime + out.Atime = bn.self.modtime + out.Size = uint64(bn.self.size) + return 0 +} + var _ = (fs.NodeSetattrer)((*ITNode)(nil)) func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno { out.Size = 0; -- 2.40.1 From 85b2145aa529230b45c8308b6b41b87baa939e88 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 19:39:26 +0000 Subject: [PATCH 14/65] Implemented Create --- fuse/main.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index 6f24473..ac1347d 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -317,6 +317,35 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, return nil, 0, syscall.EROFS } +var _ = (fs.NodeCreater)((*ITNode)(nil)) +func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (node *fs.Inode, fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { + if f.kind != 2 { + return nil, nil, 0, syscall.EROFS + } + + path := f.path + "/" + name + ino := uint64(len(inodemap)) + 11 + inodemap[path] = ino + + stable := fs.StableAttr{ + Mode: fuse.S_IFREG, + Ino: ino, + } + operations := &ITNode{ + kind: 2, Ino: ino, + path : path, + } + node = f.NewInode(ctx, operations, stable) + + fh = &bytesFileWriteHandle{ + path : path, + content : make([]byte, 0), + } + + errno = 0 + return node, fh, fuseFlags, 0 +} + func main() { // This is where we'll mount the FS mntDir := "/tmp/x" -- 2.40.1 From 9d3fdeb78f4f007fbfa6d485c887ebbc2b80170d Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 19:46:38 +0000 Subject: [PATCH 15/65] Implemented Mkdir --- fuse/main.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index ac1347d..e1a9699 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -346,6 +346,33 @@ func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uin return node, fh, fuseFlags, 0 } +var _ = (fs.NodeMkdirer)((*ITNode)(nil)) +func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) { + if f.kind != 2 { + return nil, syscall.EROFS + } + + path := f.path + "/" + name + err := myfs.Mkdir(path) + if err != nil { + return nil, syscall.EROFS + } + + ino := uint64(len(inodemap)) + 11 + inodemap[path] = ino + + stable := fs.StableAttr{ + Mode: fuse.S_IFDIR, + Ino: ino, + } + operations := &ITNode{ + kind: 2, Ino: ino, + path : path, + } + node := f.NewInode(ctx, operations, stable) + return node, 0 +} + func main() { // This is where we'll mount the FS mntDir := "/tmp/x" -- 2.40.1 From 82ed906857cfdd7b2d5ec405dbeb940a5e261f53 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 19:58:34 +0000 Subject: [PATCH 16/65] Implemented Rename --- fuse/main.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index e1a9699..3a83b3e 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -373,6 +373,23 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. return node, 0 } +var _ = (fs.NodeRenamer)((*ITNode)(nil)) +func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbedder, newName string, flags uint32) syscall.Errno { + p1 := f.path + "/" + name + p2 := newParent.EmbeddedInode().Path(nil)[2:] + "/" + newName + + err := myfs.Rename(p1, p2) + if err != nil { + return syscall.EROFS + } + + ino := inodemap[p1] + delete(inodemap, p1) + inodemap[p2] = ino + + return 0 +} + func main() { // This is where we'll mount the FS mntDir := "/tmp/x" -- 2.40.1 From 9d28a2a1f8269a6b949b80c7162339e06cb06d88 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 20:02:20 +0000 Subject: [PATCH 17/65] Implementing remove --- fuse/main.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index 3a83b3e..b1b240a 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -390,6 +390,21 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe return 0 } +var _ = (fs.NodeUnlinker)((*ITNode)(nil)) +func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { + delete(inodemap, f.path + "/" + name) + err := myfs.Remove(f.path + "/" + name) + if err != nil { + return syscall.EROFS + } + return 0 +} + +var _ = (fs.NodeRmdirer)((*ITNode)(nil)) +func (f *ITNode) Rmdir(ctx context.Context, name string) syscall.Errno { + return f.Unlink(ctx, name) +} + func main() { // This is where we'll mount the FS mntDir := "/tmp/x" -- 2.40.1 From 5d71ae245c5bd5ce7983ab13bb0a7643139eda6a Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 19 Feb 2023 20:12:38 +0000 Subject: [PATCH 18/65] Added Fsync --- fuse/main.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index b1b240a..8a5f219 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -241,6 +241,10 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) return 0 } +var _ = (fs.FileFsyncer)((*bytesFileWriteHandle)(nil)) +func (fh *bytesFileWriteHandle) Fsync(ctx context.Context, flags uint32) (errno syscall.Errno) { + return fh.Flush(ctx) +} var _ = (fs.NodeGetattrer)((*ITNode)(nil)) func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno { -- 2.40.1 From 1a5970a041adf0399b4604542771f6196be7836b Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Tue, 21 Feb 2023 19:57:36 +0000 Subject: [PATCH 19/65] Improved logging --- fuse/main.go | 63 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/fuse/main.go b/fuse/main.go index 8a5f219..023d8d0 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -1,7 +1,7 @@ package main import ( - "log" + "go.arsenm.dev/logger/log" "os" "context" "syscall" @@ -100,6 +100,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { case 2: // on device files, _ := myfs.ReadDir(n.path) + log.Info("readdir").Str("path", n.path).Int("objects", len(files)).Send() r := make([]fuse.DirEntry, len(files)) n.lst = files for ind, file := range files { @@ -174,7 +175,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* if file.path != n.path + "/" + name { continue; } - log.Println("matched", name) + log.Info("LookUp successful").Str("path", file.path).Send() if file.flags & 0b1 == 1 { stable := fs.StableAttr{ @@ -198,6 +199,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* } break; } + log.Warn("LookUp failed").Str("path", n.path + "/" + name).Send() } return nil, syscall.ENOENT } @@ -208,6 +210,7 @@ type bytesFileReadHandle struct { var _ = (fs.FileReader)((*bytesFileReadHandle)(nil)) func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { + log.Info("Executing Read").Int("size", len(fh.content)).Send() end := off + int64(len(dest)) if end > int64(len(fh.content)) { end = int64(len(fh.content)) @@ -222,6 +225,7 @@ type bytesFileWriteHandle struct { var _ = (fs.FileWriter)((*bytesFileWriteHandle)(nil)) func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int64) (written uint32, errno syscall.Errno) { + log.Info("Executing Write").Str("path", fh.path).Int("size", len(fh.content)).Send() if off != int64(len(fh.content)) { } fh.content = append(fh.content[:], data[:]...) @@ -230,14 +234,19 @@ func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int6 var _ = (fs.FileFlusher)((*bytesFileWriteHandle)(nil)) func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) { + log.Info("Attempting flush").Str("path", fh.path).Send() fp, err := myfs.Create(fh.path, uint32(len(fh.content))) if err != nil { + log.Error("Flush failed: create").Str("path", fh.path).Err(err).Send() return syscall.EROFS } nread, err := fp.Write(fh.content) if err != nil || nread != len(fh.content) { + log.Error("Flush failed: write").Str("path", fh.path).Err(err).Send() + fp.Close() return syscall.EROFS } + log.Info("Flush done").Str("path", fh.path).Int("size", len(fh.content)).Send() return 0 } @@ -248,6 +257,7 @@ func (fh *bytesFileWriteHandle) Fsync(ctx context.Context, flags uint32) (errno var _ = (fs.NodeGetattrer)((*ITNode)(nil)) func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno { + log.Info("getattr").Str("path", bn.path).Send(); out.Ino = bn.Ino out.Mtime = bn.self.modtime out.Ctime = bn.self.modtime @@ -258,6 +268,7 @@ func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOu var _ = (fs.NodeSetattrer)((*ITNode)(nil)) func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno { + log.Info("setattr").Str("path", bn.path).Send() out.Size = 0; out.Mtime = 0; return 0 @@ -269,24 +280,29 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, case 2: // FS file if openFlags&syscall.O_RDWR != 0 { + log.Warn("open: failed RDWR").Str("path", f.path).Send() return nil, 0, syscall.EROFS } if openFlags & syscall.O_WRONLY != 0 { + log.Info("Opening file: write").Str("path", f.path).Send() fh = &bytesFileWriteHandle{ path : f.path, content : make([]byte, 0), } return fh, fuse.FOPEN_DIRECT_IO, 0 } else { + log.Info("Opening file: read").Str("path", f.path).Send(); fp, err := myfs.Open(f.path) if err != nil { + log.Error("Opening file failed").Str("path", f.path).Err(err).Send(); return nil, 0, syscall.EROFS } buf := make([]byte, f.self.size); nread, err := fp.Read(buf) if err != nil || nread != int(f.self.size) { + log.Error("Reading file failed").Str("path", f.path).Err(err).Send(); return nil, 0, syscall.EROFS } @@ -346,6 +362,8 @@ func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uin content : make([]byte, 0), } + log.Info("Creating file").Str("path", path).Send() + errno = 0 return node, fh, fuseFlags, 0 } @@ -359,6 +377,10 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. path := f.path + "/" + name err := myfs.Mkdir(path) if err != nil { + log.Info("Mkdir failed"). + Str("path", path). + Err(err). + Send() return nil, syscall.EROFS } @@ -374,6 +396,11 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. path : path, } node := f.NewInode(ctx, operations, stable) + + log.Info("Mkdir sucess"). + Str("path", path). + Int("ino", int(ino)). + Send() return node, 0 } @@ -384,8 +411,18 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe err := myfs.Rename(p1, p2) if err != nil { + log.Error("Rename failed"). + Str("src", p1). + Str("dest", p2). + Err(err). + Send() + return syscall.EROFS } + log.Info("Rename sucess"). + Str("src", p1). + Str("dest", p2). + Send() ino := inodemap[p1] delete(inodemap, p1) @@ -399,8 +436,18 @@ func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { delete(inodemap, f.path + "/" + name) err := myfs.Remove(f.path + "/" + name) if err != nil { + log.Error("Unlink failed"). + Str("file", f.path + "/" + name). + Err(err). + Send() + return syscall.EROFS } + + log.Info("Unlink success"). + Str("file", f.path + "/" + name). + Err(err). + Send() return 0 } @@ -421,10 +468,17 @@ func main() { }, }) if err != nil { - log.Panic(err) + log.Error("Mounting failed"). + Str("target", mntDir). + Err(err). + Send() + return err } dev := Device{}; + log.Info("Mounted on target"). + Str("target", mntDir). + Send() properties[0].f = dev.HeartRateBytes; properties[1].f = dev.BatteryLevelBytes; @@ -433,9 +487,6 @@ func main() { properties[4].f = dev.VersionBytes; properties[5].f = dev.AddressBytes; - log.Printf("Mounted on %s", mntDir) - log.Printf("Unmount by calling 'fusermount -u %s'", mntDir) - myfs = &FS{}; inodemap = make(map[string]uint64) -- 2.40.1 From afaa5990c41fc95a81f8478b4f9fdcca107ced5a Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Tue, 21 Feb 2023 19:58:02 +0000 Subject: [PATCH 20/65] Ensure Close is always called --- fuse/main.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fuse/main.go b/fuse/main.go index 023d8d0..31ee6d6 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -246,6 +246,11 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) fp.Close() return syscall.EROFS } + err = fp.Close() + if err != nil { + log.Error("Flush failed: close").Str("path", fh.path).Err(err).Send() + return syscall.EROFS + } log.Info("Flush done").Str("path", fh.path).Int("size", len(fh.content)).Send() return 0 @@ -303,6 +308,12 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, nread, err := fp.Read(buf) if err != nil || nread != int(f.self.size) { log.Error("Reading file failed").Str("path", f.path).Err(err).Send(); + fp.Close() + return nil, 0, syscall.EROFS + } + err = fp.Close() + if err != nil { + log.Error("Closing file failed").Str("path", f.path).Err(err).Send(); return nil, 0, syscall.EROFS } -- 2.40.1 From 83726c94278172f66a45c9b6d3f1342491751aca Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Tue, 21 Feb 2023 20:05:49 +0000 Subject: [PATCH 21/65] Changed the way DirEntry is mocked --- fuse/main.go | 34 +++++++++++++++++++++++++--------- fuse/mock.go | 50 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/fuse/main.go b/fuse/main.go index 31ee6d6..21c6497 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -3,12 +3,11 @@ package main import ( "go.arsenm.dev/logger/log" "os" - "context" - "syscall" + "context" + "syscall" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" "strconv" - "strings" ) func (i *Device) HeartRateBytes() ([]byte, error) { @@ -43,6 +42,14 @@ type ITProperty struct { f func() ([]byte, error) } + +type DirEntry struct { + isDir bool + modtime uint64 + size uint32 + path string +} + type ITNode struct { fs.Inode kind int @@ -102,9 +109,18 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { files, _ := myfs.ReadDir(n.path) log.Info("readdir").Str("path", n.path).Int("objects", len(files)).Send() r := make([]fuse.DirEntry, len(files)) - n.lst = files - for ind, file := range files { - name := file.path[strings.LastIndex(file.path, "/")+1:] + n.lst = make([]DirEntry, len(files)) + for ind, entry := range files { + info, _ := entry.Info() + name := info.Name() + + file := DirEntry{ + path: n.path + "/" + name, + size: uint32(info.Size()), + modtime: uint64(info.ModTime().Unix()), + isDir: info.IsDir(), + } + n.lst[ind] = file ino := inodemap[file.path] if ino == 0 { @@ -112,7 +128,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { inodemap[file.path] = ino } - if file.flags & 0b1 == 1 { + if file.isDir { r[ind] = fuse.DirEntry{ Name: name, Mode: fuse.S_IFDIR, @@ -177,7 +193,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* } log.Info("LookUp successful").Str("path", file.path).Send() - if file.flags & 0b1 == 1 { + if file.isDir { stable := fs.StableAttr{ Mode: fuse.S_IFDIR, Ino: inodemap[file.path], @@ -483,7 +499,7 @@ func main() { Str("target", mntDir). Err(err). Send() - return err + return } dev := Device{}; diff --git a/fuse/mock.go b/fuse/mock.go index 9487758..b7cceb1 100644 --- a/fuse/mock.go +++ b/fuse/mock.go @@ -3,6 +3,7 @@ import ( "os" "io/ioutil" "errors" + "time" ) const ( @@ -26,12 +27,30 @@ type Device struct { type FS struct { } -type DirEntry struct { - status int8 - flags uint32 - modtime uint64 - size uint32 - path string +type MyFileInfo struct { + name string + size uint32 + modtime time.Time + dir bool +} +func (n *MyFileInfo) Name() string { + return n.name +} +func (n *MyFileInfo) Size() uint32 { + return n.size +} +func (n *MyFileInfo) ModTime() time.Time { + return n.modtime +} +func (n *MyFileInfo) IsDir() bool { + return n.dir +} + +type MyDirEntry struct { + self MyFileInfo +} +func (n *MyDirEntry) Info() (MyFileInfo, error) { + return n.self, nil } type File struct { @@ -74,8 +93,8 @@ func (i *Device) Version() (string, error) { return "1.11.0", nil } -func (blefs *FS) ReadDir(path string) ([]DirEntry, error) { - var out []DirEntry +func (blefs *FS) ReadDir(path string) ([]MyDirEntry, error) { + var out []MyDirEntry files, err := ioutil.ReadDir("./root/" + path) if err != nil { @@ -83,17 +102,12 @@ func (blefs *FS) ReadDir(path string) ([]DirEntry, error) { } for _, f := range files { - listing := DirEntry{} - listing.status = FSStatusOk - listing.modtime = uint64(f.ModTime().Unix()) + listing := MyFileInfo{} + listing.modtime = f.ModTime() listing.size = uint32(f.Size()) - listing.path = path + "/" + f.Name() - if f.IsDir() { - listing.flags = 1; - } else { - listing.flags = 0; - } - out = append(out, listing) + listing.name = path + "/" + f.Name() + listing.dir = f.IsDir() + out = append(out, MyDirEntry{self : listing}) } return out, nil } -- 2.40.1 From bfb21ea6a91327e28ce6a0f9d52d0643ee0d7541 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Tue, 21 Feb 2023 20:06:09 +0000 Subject: [PATCH 22/65] Enforced single thread fuse --- fuse/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/fuse/main.go b/fuse/main.go index 21c6497..18c8052 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -492,6 +492,7 @@ func main() { MountOptions: fuse.MountOptions{ // Set to true to see how the file system works. Debug: false, + SingleThreaded: true, }, }) if err != nil { -- 2.40.1 From 68f6d2071930a95cb3c34cd592c4beb5906237f0 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Tue, 21 Feb 2023 20:11:38 +0000 Subject: [PATCH 23/65] x --- fuse/mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuse/mock.go b/fuse/mock.go index b7cceb1..71c1956 100644 --- a/fuse/mock.go +++ b/fuse/mock.go @@ -105,7 +105,7 @@ func (blefs *FS) ReadDir(path string) ([]MyDirEntry, error) { listing := MyFileInfo{} listing.modtime = f.ModTime() listing.size = uint32(f.Size()) - listing.name = path + "/" + f.Name() + listing.name = f.Name() listing.dir = f.IsDir() out = append(out, MyDirEntry{self : listing}) } -- 2.40.1 From 4d3bc1ed40376e79a70b2aabca08b99650f155d5 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Tue, 21 Feb 2023 20:12:10 +0000 Subject: [PATCH 24/65] y 1a5970a --- fuse/main.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fuse/main.go b/fuse/main.go index 18c8052..094c2ca 100644 --- a/fuse/main.go +++ b/fuse/main.go @@ -1,6 +1,7 @@ package main import ( + "go.arsenm.dev/logger" "go.arsenm.dev/logger/log" "os" "context" @@ -241,7 +242,7 @@ type bytesFileWriteHandle struct { var _ = (fs.FileWriter)((*bytesFileWriteHandle)(nil)) func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int64) (written uint32, errno syscall.Errno) { - log.Info("Executing Write").Str("path", fh.path).Int("size", len(fh.content)).Send() + log.Info("Executing Write").Str("path", fh.path).Int("prev_size", len(fh.content)).Int("next_size", len(data)).Send() if off != int64(len(fh.content)) { } fh.content = append(fh.content[:], data[:]...) @@ -483,6 +484,11 @@ func (f *ITNode) Rmdir(ctx context.Context, name string) syscall.Errno { return f.Unlink(ctx, name) } +func init() { + // Default logger is JSONLogger going to stderr + log.Logger = logger.NewPretty(os.Stdout) +} + func main() { // This is where we'll mount the FS mntDir := "/tmp/x" -- 2.40.1 From b181785006ed48c9a86eb22dba2767b5f6f744f4 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:03:19 +0000 Subject: [PATCH 25/65] Removed mock --- fuse/main.go => fuse.go | 0 fuse/mock.go | 161 ---------------------------------------- 2 files changed, 161 deletions(-) rename fuse/main.go => fuse.go (100%) delete mode 100644 fuse/mock.go diff --git a/fuse/main.go b/fuse.go similarity index 100% rename from fuse/main.go rename to fuse.go diff --git a/fuse/mock.go b/fuse/mock.go deleted file mode 100644 index 71c1956..0000000 --- a/fuse/mock.go +++ /dev/null @@ -1,161 +0,0 @@ -package main -import ( - "os" - "io/ioutil" - "errors" - "time" -) - -const ( - FSStatusOk = 0x01 - FSStatusError = 0x02 -) - -var ( - ErrFileNotExists = errors.New("file does not exist") - ErrFileReadOnly = errors.New("file is read only") - ErrFileWriteOnly = errors.New("file is write only") - ErrInvalidOffset = errors.New("invalid file offset") - ErrOffsetChanged = errors.New("offset has already been changed") - ErrReadOpen = errors.New("only one file can be opened for reading at a time") - ErrWriteOpen = errors.New("only one file can be opened for writing at a time") - ErrNoRemoveRoot = errors.New("refusing to remove root directory") -) - -type Device struct { -} -type FS struct { -} - -type MyFileInfo struct { - name string - size uint32 - modtime time.Time - dir bool -} -func (n *MyFileInfo) Name() string { - return n.name -} -func (n *MyFileInfo) Size() uint32 { - return n.size -} -func (n *MyFileInfo) ModTime() time.Time { - return n.modtime -} -func (n *MyFileInfo) IsDir() bool { - return n.dir -} - -type MyDirEntry struct { - self MyFileInfo -} -func (n *MyDirEntry) Info() (MyFileInfo, error) { - return n.self, nil -} - -type File struct { - fs *FS - path string - fp *os.File - isReadOnly bool - isWriteOnly bool -} - - - -func (i *Device) HeartRate() (uint8, error) { - return 10, nil -} - -func (i *Device) BatteryLevel() (uint8, error) { - return 95, nil -} - -func (i *Device) StepCount() (uint32, error) { - return 27000, nil -} - -type MotionValues struct { - X int16 - Y int16 - Z int16 -} - -func (i *Device) Motion() (MotionValues, error) { - return MotionValues{-12, +64, -19}, nil -} - -func (i *Device) Address() string { - return "FA:E4:00:00:00:00" -} - -func (i *Device) Version() (string, error) { - return "1.11.0", nil -} - -func (blefs *FS) ReadDir(path string) ([]MyDirEntry, error) { - var out []MyDirEntry - files, err := ioutil.ReadDir("./root/" + path) - - if err != nil { - return nil, nil - } - - for _, f := range files { - listing := MyFileInfo{} - listing.modtime = f.ModTime() - listing.size = uint32(f.Size()) - listing.name = f.Name() - listing.dir = f.IsDir() - out = append(out, MyDirEntry{self : listing}) - } - return out, nil -} - -func (blefs *FS) Mkdir(path string) error { - return os.Mkdir("./root/" + path, os.ModePerm) -} - -func (blefs *FS) Rename(old, new string) error { - return os.Rename("./root/" + old, "./root/" + new) -} - -func (blefs *FS) Remove(path string) error { - return os.Remove("./root/" + path) -} - -func (blefs *FS) Open(path string) (*File, error) { - fp, _ := os.Open("./root/" + path) - return &File{ - fs : blefs, - path : path, - fp : fp, - isReadOnly : true, - isWriteOnly : false, - }, nil -} -func (blefs *FS) Create(path string, size uint32) (*File, error) { - fp, _ := os.Create("./root/" + path) - return &File{ - fs : blefs, - path : path, - fp : fp, - isReadOnly : false, - isWriteOnly : true, - }, nil -} -func (fl *File) Read(b []byte) (n int, err error) { - if fl.isWriteOnly { - return 0, ErrFileWriteOnly - } - return fl.fp.Read(b) -} -func (fl *File) Write(b []byte) (n int, err error) { - if fl.isReadOnly { - return 0, ErrFileReadOnly - } - return fl.fp.Write(b) -} -func (fl *File) Close() error { - return fl.fp.Close() -} -- 2.40.1 From ec39e649c5eccfe5ccbf620459eba7fddf0e78b5 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:04:42 +0000 Subject: [PATCH 26/65] 1. Removed main routine --- fuse.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/fuse.go b/fuse.go index 094c2ca..9e2cdec 100644 --- a/fuse.go +++ b/fuse.go @@ -1,7 +1,6 @@ package main import ( - "go.arsenm.dev/logger" "go.arsenm.dev/logger/log" "os" "context" @@ -484,12 +483,7 @@ func (f *ITNode) Rmdir(ctx context.Context, name string) syscall.Errno { return f.Unlink(ctx, name) } -func init() { - // Default logger is JSONLogger going to stderr - log.Logger = logger.NewPretty(os.Stdout) -} - -func main() { +func startFuse(ctx context.Context, dev *infinitime.Device) error { // This is where we'll mount the FS mntDir := "/tmp/x" os.Mkdir(mntDir, 0755) @@ -506,10 +500,9 @@ func main() { Str("target", mntDir). Err(err). Send() - return + return err } - dev := Device{}; log.Info("Mounted on target"). Str("target", mntDir). Send() -- 2.40.1 From ffe9d43cf867c0bdbae228d11314bac2096c9a88 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:05:58 +0000 Subject: [PATCH 27/65] 2. Inherited from infinitime.Device to extend --- fuse.go | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/fuse.go b/fuse.go index 9e2cdec..30acaa0 100644 --- a/fuse.go +++ b/fuse.go @@ -1,6 +1,7 @@ package main import ( + "go.arsenm.dev/infinitime" "go.arsenm.dev/logger/log" "os" "context" @@ -10,28 +11,32 @@ import ( "strconv" ) -func (i *Device) HeartRateBytes() ([]byte, error) { - v, err := i.HeartRate() +type Device struct { + dev *infinitime.Device +} + +func (i Device) HeartRateBytes() ([]byte, error) { + v, err := i.dev.HeartRate() return []byte(strconv.Itoa(int(v)) + "\n"), err } -func (i *Device) BatteryLevelBytes() ([]byte, error) { - v, err := i.BatteryLevel() +func (i Device) BatteryLevelBytes() ([]byte, error) { + v, err := i.dev.BatteryLevel() return []byte(strconv.Itoa(int(v)) + "\n"), err } -func (i *Device) StepCountBytes() ([]byte, error) { - v, err := i.StepCount() +func (i Device) StepCountBytes() ([]byte, error) { + v, err := i.dev.StepCount() return []byte(strconv.Itoa(int(v)) + "\n"), err } -func (i *Device) MotionBytes() ([]byte, error) { - v, err := i.Motion() +func (i Device) MotionBytes() ([]byte, error) { + v, err := i.dev.Motion() return []byte(strconv.Itoa(int(v.X)) + " " + strconv.Itoa(int(v.Y)) + " " + strconv.Itoa(int(v.Z)) + "\n"), err } -func (i *Device) AddressBytes() ([]byte, error) { - v := i.Address() +func (i Device) AddressBytes() ([]byte, error) { + v := i.dev.Address() return []byte(v + "\n"), nil } -func (i *Device) VersionBytes() ([]byte, error) { - v, err := i.Version() +func (i Device) VersionBytes() ([]byte, error) { + v, err := i.dev.Version() return []byte(v + "\n"), err } @@ -507,12 +512,14 @@ func startFuse(ctx context.Context, dev *infinitime.Device) error { Str("target", mntDir). Send() - properties[0].f = dev.HeartRateBytes; - properties[1].f = dev.BatteryLevelBytes; - properties[2].f = dev.MotionBytes; - properties[3].f = dev.StepCountBytes; - properties[4].f = dev.VersionBytes; - properties[5].f = dev.AddressBytes; + mydev := Device{dev : dev}; + + properties[0].f = mydev.HeartRateBytes; + properties[1].f = mydev.BatteryLevelBytes; + properties[2].f = mydev.MotionBytes; + properties[3].f = mydev.StepCountBytes; + properties[4].f = mydev.VersionBytes; + properties[5].f = mydev.AddressBytes; myfs = &FS{}; inodemap = make(map[string]uint64) -- 2.40.1 From a27cc090dddc5584113b9e022d3fe0013f2de9a6 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:06:58 +0000 Subject: [PATCH 28/65] 3. Interfaced FS --- fuse.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fuse.go b/fuse.go index 30acaa0..7921f97 100644 --- a/fuse.go +++ b/fuse.go @@ -2,6 +2,7 @@ package main import ( "go.arsenm.dev/infinitime" + "go.arsenm.dev/infinitime/blefs" "go.arsenm.dev/logger/log" "os" "context" @@ -73,7 +74,7 @@ var properties = []ITProperty { ITProperty{"version", 6, nil}, ITProperty{"address", 7, nil}, } -var myfs *FS = nil; +var myfs *blefs.FS = nil; var inodemap map[string]uint64 = nil; var _ = (fs.NodeReaddirer)((*ITNode)(nil)) @@ -521,9 +522,14 @@ func startFuse(ctx context.Context, dev *infinitime.Device) error { properties[4].f = mydev.VersionBytes; properties[5].f = mydev.AddressBytes; - myfs = &FS{}; + myfs, err = dev.FS() + if err != nil { + log.Warn("Error getting BLE filesystem").Err(err).Send() + return err + } inodemap = make(map[string]uint64) // Wait until unmount before exiting - server.Wait() + go server.Serve() + return nil } -- 2.40.1 From 9b9ab672170f1357e3318009316d3c1cfebbbbb2 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:08:14 +0000 Subject: [PATCH 29/65] 4. Better error handling --- fuse.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fuse.go b/fuse.go index 7921f97..2a7f6eb 100644 --- a/fuse.go +++ b/fuse.go @@ -256,6 +256,10 @@ func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int6 var _ = (fs.FileFlusher)((*bytesFileWriteHandle)(nil)) func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) { + if len(fh.content) == 0 { + return 0 + } + log.Info("Attempting flush").Str("path", fh.path).Send() fp, err := myfs.Create(fh.path, uint32(len(fh.content))) if err != nil { @@ -268,6 +272,11 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) fp.Close() return syscall.EROFS } + if int(nread) != len(fh.content) { + log.Error("Flush failed: write").Str("path", fh.path).Int("expect", len(fh.content)).Int("got", int(nread)).Send() + fp.Close() + return syscall.EROFS + } err = fp.Close() if err != nil { log.Error("Flush failed: close").Str("path", fh.path).Err(err).Send() -- 2.40.1 From c142d97ee8063e2b33dc682d9a3d880f8f3f9180 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:09:00 +0000 Subject: [PATCH 30/65] 5. Use defer for closing file --- fuse.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fuse.go b/fuse.go index 2a7f6eb..80d867f 100644 --- a/fuse.go +++ b/fuse.go @@ -335,6 +335,8 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, return nil, 0, syscall.EROFS } + defer fp.Close() + buf := make([]byte, f.self.size); nread, err := fp.Read(buf) if err != nil || nread != int(f.self.size) { @@ -342,11 +344,6 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, fp.Close() return nil, 0, syscall.EROFS } - err = fp.Close() - if err != nil { - log.Error("Closing file failed").Str("path", f.path).Err(err).Send(); - return nil, 0, syscall.EROFS - } fh = &bytesFileReadHandle{ content: buf, -- 2.40.1 From fe43a608d00e2ada79e3b423e18cda33275a2c4e Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:09:41 +0000 Subject: [PATCH 31/65] 6. Used io.Copy to move files --- fuse.go | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/fuse.go b/fuse.go index 80d867f..7bb7535 100644 --- a/fuse.go +++ b/fuse.go @@ -10,6 +10,8 @@ import ( "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" "strconv" + "io" + "bytes" ) type Device struct { @@ -266,8 +268,17 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) log.Error("Flush failed: create").Str("path", fh.path).Err(err).Send() return syscall.EROFS } - nread, err := fp.Write(fh.content) - if err != nil || nread != len(fh.content) { + + go func() { + // For every progress event + for sent := range fp.Progress() { + log.Info("Progress").Int("bytes", int(sent)).Int("of", len(fh.content)).Send(); + } + }() + + r := bytes.NewReader(fh.content) + nread, err := io.Copy(fp, r) + if err != nil { log.Error("Flush failed: write").Str("path", fh.path).Err(err).Send() fp.Close() return syscall.EROFS @@ -337,16 +348,24 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, defer fp.Close() - buf := make([]byte, f.self.size); - nread, err := fp.Read(buf) - if err != nil || nread != int(f.self.size) { - log.Error("Reading file failed").Str("path", f.path).Err(err).Send(); + b := &bytes.Buffer{} + + go func() { + // For every progress event + for sent := range fp.Progress() { + log.Info("Progress").Int("bytes", int(sent)).Int("of", int(f.self.size)).Send(); + } + }() + + _, err = io.Copy(b, fp) + if err != nil { + log.Error("Read failed").Str("path", f.path).Err(err).Send() fp.Close() return nil, 0, syscall.EROFS } fh = &bytesFileReadHandle{ - content: buf, + content: b.Bytes(), } return fh, fuse.FOPEN_DIRECT_IO, 0 } -- 2.40.1 From 5fa49adee41d6b0f85e9d832ddbfe3c489820c9f Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:10:03 +0000 Subject: [PATCH 32/65] 7. Activate fuse --- main.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/main.go b/main.go index 457a16e..dc34c4c 100644 --- a/main.go +++ b/main.go @@ -186,6 +186,11 @@ func main() { if err != nil { log.Error("Error starting socket").Err(err).Send() } + // Start fuse socket + err = startFuse(ctx, dev) + if err != nil { + log.Error("Error starting socket").Err(err).Send() + } // Block forever select {} } -- 2.40.1 From 4389609500bec4053f746067213b63f33e3bf982 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:15:09 +0000 Subject: [PATCH 33/65] Run Readdir during Lookup if necessary --- fuse.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fuse.go b/fuse.go index 7bb7535..97cec0e 100644 --- a/fuse.go +++ b/fuse.go @@ -195,6 +195,10 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* case 2: // FS object + if len(n.lst) == 0 { + n.Readdir(ctx) + } + for _, file := range n.lst { if file.path != n.path + "/" + name { continue; -- 2.40.1 From 8f57a0be8db20df77bb79c8fee3c4ce949c27b25 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:40:44 +0000 Subject: [PATCH 34/65] Added fuse to config --- config.go | 3 +++ fuse.go | 9 ++++----- main.go | 8 +++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/config.go b/config.go index 49ce23d..a188658 100644 --- a/config.go +++ b/config.go @@ -106,5 +106,8 @@ func setCfgDefaults() { "notifs.ignore.body": []string{}, "music.vol.interval": 5, + + "fuse.enabled": false, + "fuse.mountpoint": "/tmp/itd/mnt", }, "."), nil) } diff --git a/fuse.go b/fuse.go index 97cec0e..1afc06f 100644 --- a/fuse.go +++ b/fuse.go @@ -520,10 +520,9 @@ func (f *ITNode) Rmdir(ctx context.Context, name string) syscall.Errno { func startFuse(ctx context.Context, dev *infinitime.Device) error { // This is where we'll mount the FS - mntDir := "/tmp/x" - os.Mkdir(mntDir, 0755) + os.Mkdir(k.String("fuse.mountpoint"), 0755) root := &ITNode{kind: 0} - server, err := fs.Mount(mntDir, root, &fs.Options{ + server, err := fs.Mount(k.String("fuse.mountpoint"), root, &fs.Options{ MountOptions: fuse.MountOptions{ // Set to true to see how the file system works. Debug: false, @@ -532,14 +531,14 @@ func startFuse(ctx context.Context, dev *infinitime.Device) error { }) if err != nil { log.Error("Mounting failed"). - Str("target", mntDir). + Str("target", k.String("fuse.mountpoint")). Err(err). Send() return err } log.Info("Mounted on target"). - Str("target", mntDir). + Str("target", k.String("fuse.mountpoint")). Send() mydev := Device{dev : dev}; diff --git a/main.go b/main.go index dc34c4c..e9ef50c 100644 --- a/main.go +++ b/main.go @@ -187,9 +187,11 @@ func main() { log.Error("Error starting socket").Err(err).Send() } // Start fuse socket - err = startFuse(ctx, dev) - if err != nil { - log.Error("Error starting socket").Err(err).Send() + if k.Bool("fuse.enabled") { + err = startFuse(ctx, dev) + if err != nil { + log.Error("Error starting fuse socket").Err(err).Send() + } } // Block forever select {} -- 2.40.1 From d2dbcd87130316c6fe3c25d265d5e3b8d32cbbf2 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 13:54:57 +0000 Subject: [PATCH 35/65] Fixed unlink (1a5970a0) --- fuse.go | 1 - 1 file changed, 1 deletion(-) diff --git a/fuse.go b/fuse.go index 1afc06f..c41177c 100644 --- a/fuse.go +++ b/fuse.go @@ -508,7 +508,6 @@ func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { log.Info("Unlink success"). Str("file", f.path + "/" + name). - Err(err). Send() return 0 } -- 2.40.1 From 4333b83ca25d5057e275861367bd14269996d2b7 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:02:23 +0000 Subject: [PATCH 36/65] Added channel reader --- fuse.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fuse.go b/fuse.go index c41177c..708e9b9 100644 --- a/fuse.go +++ b/fuse.go @@ -246,6 +246,15 @@ func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) return fuse.ReadResultData(fh.content[off:end]), 0 } +type sensorFileReadHandle struct { + ch <-chan uint8 +} +var _ = (fs.FileReader)((*sensorFileReadHandle)(nil)) +func (fh *sensorFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { + return nil, 0 +} + + type bytesFileWriteHandle struct { content []byte path string -- 2.40.1 From 083da5b3f0b592899e3c5c2b89b201749cda8bbf Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:03:27 +0000 Subject: [PATCH 37/65] Used generator instead of function in ITProperty --- fuse.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fuse.go b/fuse.go index 708e9b9..fa1d855 100644 --- a/fuse.go +++ b/fuse.go @@ -47,7 +47,7 @@ func (i Device) VersionBytes() ([]byte, error) { type ITProperty struct { name string Ino uint64 - f func() ([]byte, error) + gen func(context.Context) (<-chan uint8, error) } @@ -393,13 +393,13 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, for _, value := range properties { if value.Ino == f.Ino { - ans, err := value.f() + ans, err := value.gen(ctx) if err != nil { return nil, 0, syscall.EROFS } - fh = &bytesFileReadHandle{ - content: ans, + fh = &sensorFileReadHandle{ + ch: ans, } return fh, fuse.FOPEN_DIRECT_IO, 0 } @@ -551,12 +551,13 @@ func startFuse(ctx context.Context, dev *infinitime.Device) error { mydev := Device{dev : dev}; - properties[0].f = mydev.HeartRateBytes; - properties[1].f = mydev.BatteryLevelBytes; - properties[2].f = mydev.MotionBytes; - properties[3].f = mydev.StepCountBytes; - properties[4].f = mydev.VersionBytes; - properties[5].f = mydev.AddressBytes; + properties[0].gen = mydev.dev.WatchHeartRate; + // properties[0].f = mydev.HeartRateBytes; + // properties[1].f = mydev.BatteryLevelBytes; + // properties[2].f = mydev.MotionBytes; + // properties[3].f = mydev.StepCountBytes; + // properties[4].f = mydev.VersionBytes; + // properties[5].f = mydev.AddressBytes; myfs, err = dev.FS() if err != nil { -- 2.40.1 From 2c899b4660ed7b560d03359acd65966ef7aff913 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:04:47 +0000 Subject: [PATCH 38/65] Implemented Read for watcher --- fuse.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fuse.go b/fuse.go index fa1d855..17cb865 100644 --- a/fuse.go +++ b/fuse.go @@ -251,7 +251,9 @@ type sensorFileReadHandle struct { } var _ = (fs.FileReader)((*sensorFileReadHandle)(nil)) func (fh *sensorFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { - return nil, 0 + v := <-fh.ch + content := []byte(strconv.Itoa(int(v)) + "\n") + return fuse.ReadResultData(content), 0 } -- 2.40.1 From e2bd52b5a022639713bcf77056331bc088d9e828 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:06:11 +0000 Subject: [PATCH 39/65] Implemented Read for watcher --- fuse.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fuse.go b/fuse.go index 17cb865..9c128f0 100644 --- a/fuse.go +++ b/fuse.go @@ -248,6 +248,7 @@ func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) type sensorFileReadHandle struct { ch <-chan uint8 + cancel context.CancelFunc } var _ = (fs.FileReader)((*sensorFileReadHandle)(nil)) func (fh *sensorFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { @@ -256,6 +257,12 @@ func (fh *sensorFileReadHandle) Read(ctx context.Context, dest []byte, off int64 return fuse.ReadResultData(content), 0 } +var _ = (fs.FileFlusher)((*sensorFileReadHandle)(nil)) +func (fh *sensorFileReadHandle) Flush(ctx context.Context) (errno syscall.Errno) { + fh.cancel() + return 0 +} + type bytesFileWriteHandle struct { content []byte @@ -395,13 +402,15 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, for _, value := range properties { if value.Ino == f.Ino { - ans, err := value.gen(ctx) + sub_ctx, cancel := context.WithCancel(ctx) + ans, err := value.gen(sub_ctx) if err != nil { return nil, 0, syscall.EROFS } fh = &sensorFileReadHandle{ ch: ans, + cancel : cancel, } return fh, fuse.FOPEN_DIRECT_IO, 0 } -- 2.40.1 From c046c67dbda07e54f6844509267961b1bf7039bb Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:07:09 +0000 Subject: [PATCH 40/65] Turned generator to return []byte --- fuse.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fuse.go b/fuse.go index 9c128f0..32d2a98 100644 --- a/fuse.go +++ b/fuse.go @@ -47,7 +47,7 @@ func (i Device) VersionBytes() ([]byte, error) { type ITProperty struct { name string Ino uint64 - gen func(context.Context) (<-chan uint8, error) + gen func(context.Context) (<-chan []byte, error) } @@ -247,13 +247,12 @@ func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) } type sensorFileReadHandle struct { - ch <-chan uint8 + ch <-chan []byte cancel context.CancelFunc } var _ = (fs.FileReader)((*sensorFileReadHandle)(nil)) func (fh *sensorFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { - v := <-fh.ch - content := []byte(strconv.Itoa(int(v)) + "\n") + content := <-fh.ch return fuse.ReadResultData(content), 0 } -- 2.40.1 From c5ca30cd0a44ee4af082e4f72c77398b169528f6 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:08:10 +0000 Subject: [PATCH 41/65] Added format converters --- fuse.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/fuse.go b/fuse.go index 32d2a98..d4c141a 100644 --- a/fuse.go +++ b/fuse.go @@ -43,6 +43,50 @@ func (i Device) VersionBytes() ([]byte, error) { return []byte(v + "\n"), err } +func converterU8(ctx context.Context, in <-chan uint8) <-chan []byte { + out := make(chan []byte, 2) + go func() { + for { + select { + case <- ctx.Done(): + return + case event := <-in: + out <- []byte(strconv.Itoa(int(event)) + "\n") + } + } + }() + return out +} + +func converterU32(ctx context.Context, in <-chan uint32) <-chan []byte { + out := make(chan []byte, 2) + go func() { + for { + select { + case <- ctx.Done(): + return + case event := <-in: + out <- []byte(strconv.Itoa(int(event)) + "\n") + } + } + }() + return out +} + +func converterMotionValues(ctx context.Context, in <-chan infinitime.MotionValues) <-chan []byte { + out := make(chan []byte, 2) + go func() { + for { + select { + case <- ctx.Done(): + return + case event := <-in: + out <- []byte(strconv.Itoa(int(event.X)) + " " + strconv.Itoa(int(event.Y)) + " " + strconv.Itoa(int(event.Z)) + "\n") + } + } + }() + return out +} type ITProperty struct { name string @@ -559,15 +603,22 @@ func startFuse(ctx context.Context, dev *infinitime.Device) error { Str("target", k.String("fuse.mountpoint")). Send() - mydev := Device{dev : dev}; - - properties[0].gen = mydev.dev.WatchHeartRate; - // properties[0].f = mydev.HeartRateBytes; - // properties[1].f = mydev.BatteryLevelBytes; - // properties[2].f = mydev.MotionBytes; - // properties[3].f = mydev.StepCountBytes; - // properties[4].f = mydev.VersionBytes; - // properties[5].f = mydev.AddressBytes; + properties[0].gen = func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchHeartRate(ctx) + return converterU8(ctx, ans), err + } + properties[1].gen = func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchBatteryLevel(ctx) + return converterU8(ctx, ans), err + } + properties[2].gen = func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchMotion(ctx) + return converterMotionValues(ctx, ans), err + } + properties[3].gen = func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchStepCount(ctx) + return converterU32(ctx, ans), err + } myfs, err = dev.FS() if err != nil { -- 2.40.1 From 1799c072ffbd2ae5d8725b7626d3693c0915da12 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:08:35 +0000 Subject: [PATCH 42/65] Added one-shot converter for strings --- fuse.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fuse.go b/fuse.go index d4c141a..3dc1ec1 100644 --- a/fuse.go +++ b/fuse.go @@ -88,6 +88,13 @@ func converterMotionValues(ctx context.Context, in <-chan infinitime.MotionValue return out } +func converter1String(ctx context.Context, in string) <-chan []byte { + out := make(chan []byte, 2) + out <- []byte(in + "\n") + close(out) + return out +} + type ITProperty struct { name string Ino uint64 @@ -619,6 +626,14 @@ func startFuse(ctx context.Context, dev *infinitime.Device) error { ans, err := dev.WatchStepCount(ctx) return converterU32(ctx, ans), err } + properties[4].gen = func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.Version() + return converter1String(ctx, ans), err + } + properties[5].gen = func(ctx context.Context) (<-chan []byte, error) { + ans := dev.Address() + return converter1String(ctx, ans), nil + } myfs, err = dev.FS() if err != nil { -- 2.40.1 From 08c8d7e8deaede5de33480ef4118816d15c0506e Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:09:45 +0000 Subject: [PATCH 43/65] Removed device wrapper --- fuse.go | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/fuse.go b/fuse.go index 3dc1ec1..fc6f87c 100644 --- a/fuse.go +++ b/fuse.go @@ -14,35 +14,6 @@ import ( "bytes" ) -type Device struct { - dev *infinitime.Device -} - -func (i Device) HeartRateBytes() ([]byte, error) { - v, err := i.dev.HeartRate() - return []byte(strconv.Itoa(int(v)) + "\n"), err -} -func (i Device) BatteryLevelBytes() ([]byte, error) { - v, err := i.dev.BatteryLevel() - return []byte(strconv.Itoa(int(v)) + "\n"), err -} -func (i Device) StepCountBytes() ([]byte, error) { - v, err := i.dev.StepCount() - return []byte(strconv.Itoa(int(v)) + "\n"), err -} -func (i Device) MotionBytes() ([]byte, error) { - v, err := i.dev.Motion() - return []byte(strconv.Itoa(int(v.X)) + " " + strconv.Itoa(int(v.Y)) + " " + strconv.Itoa(int(v.Z)) + "\n"), err -} -func (i Device) AddressBytes() ([]byte, error) { - v := i.dev.Address() - return []byte(v + "\n"), nil -} -func (i Device) VersionBytes() ([]byte, error) { - v, err := i.dev.Version() - return []byte(v + "\n"), err -} - func converterU8(ctx context.Context, in <-chan uint8) <-chan []byte { out := make(chan []byte, 2) go func() { -- 2.40.1 From 2440cb954cd6f2c98582e0f37ee56861b29ebc8b Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 26 Feb 2023 19:10:47 +0000 Subject: [PATCH 44/65] Merged two properties lists --- fuse.go | 63 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/fuse.go b/fuse.go index fc6f87c..5c3fdec 100644 --- a/fuse.go +++ b/fuse.go @@ -90,14 +90,7 @@ type ITNode struct { path string } -var properties = []ITProperty { - ITProperty{"heartrate", 2, nil}, - ITProperty{"battery", 3, nil}, - ITProperty{"motion", 4, nil}, - ITProperty{"stepcount", 5, nil}, - ITProperty{"version", 6, nil}, - ITProperty{"address", 7, nil}, -} +var properties = make([]ITProperty, 6) var myfs *blefs.FS = nil; var inodemap map[string]uint64 = nil; @@ -581,30 +574,36 @@ func startFuse(ctx context.Context, dev *infinitime.Device) error { Str("target", k.String("fuse.mountpoint")). Send() - properties[0].gen = func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchHeartRate(ctx) - return converterU8(ctx, ans), err - } - properties[1].gen = func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchBatteryLevel(ctx) - return converterU8(ctx, ans), err - } - properties[2].gen = func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchMotion(ctx) - return converterMotionValues(ctx, ans), err - } - properties[3].gen = func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchStepCount(ctx) - return converterU32(ctx, ans), err - } - properties[4].gen = func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.Version() - return converter1String(ctx, ans), err - } - properties[5].gen = func(ctx context.Context) (<-chan []byte, error) { - ans := dev.Address() - return converter1String(ctx, ans), nil - } + properties[0] = ITProperty{"heartrate", 2, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchHeartRate(ctx) + return converterU8(ctx, ans), err + }} + properties[1] = ITProperty{"battery", 3, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchBatteryLevel(ctx) + return converterU8(ctx, ans), err + }} + properties[2] = ITProperty{"motion", 4, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchMotion(ctx) + return converterMotionValues(ctx, ans), err + }} + properties[3] = ITProperty{"stepcount", 5, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchStepCount(ctx) + return converterU32(ctx, ans), err + }} + properties[4] = ITProperty{"version", 6, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.Version() + return converter1String(ctx, ans), err + }} + properties[5] = ITProperty{"address", 7, + func(ctx context.Context) (<-chan []byte, error) { + ans := dev.Address() + return converter1String(ctx, ans), nil + }} myfs, err = dev.FS() if err != nil { -- 2.40.1 From bf13b96660587aafa00c64b4c079b27b50a7345e Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 15:04:17 +0000 Subject: [PATCH 45/65] 1. moved fuse.go --- fuse.go => internal/fusefs/fuse.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename fuse.go => internal/fusefs/fuse.go (100%) diff --git a/fuse.go b/internal/fusefs/fuse.go similarity index 100% rename from fuse.go rename to internal/fusefs/fuse.go -- 2.40.1 From 8dd8f3d0120302502cbb17dadd990ff59862d45d Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 15:12:48 +0000 Subject: [PATCH 46/65] 2. added fuse.go in main --- fuse.go | 76 +++++++++++++++++++++++++++++++++++++++++ internal/fusefs/fuse.go | 69 +------------------------------------ 2 files changed, 77 insertions(+), 68 deletions(-) create mode 100644 fuse.go diff --git a/fuse.go b/fuse.go new file mode 100644 index 0000000..3b7ee77 --- /dev/null +++ b/fuse.go @@ -0,0 +1,76 @@ +package main +import ( + "go.arsenm.dev/itd/internal/fusefs" + "os" + "github.com/hanwen/go-fuse/v2/fs" + "github.com/hanwen/go-fuse/v2/fuse" + "go.arsenm.dev/logger/log" + "context" + "go.arsenm.dev/infinitime" +) + +func startFuse(ctx context.Context, dev *infinitime.Device) error { + // This is where we'll mount the FS + os.Mkdir(k.String("fuse.mountpoint"), 0755) + root := &ITNode{kind: 0} + server, err := fs.Mount(k.String("fuse.mountpoint"), root, &fs.Options{ + MountOptions: fuse.MountOptions{ + // Set to true to see how the file system works. + Debug: false, + SingleThreaded: true, + }, + }) + if err != nil { + log.Error("Mounting failed"). + Str("target", k.String("fuse.mountpoint")). + Err(err). + Send() + return err + } + + log.Info("Mounted on target"). + Str("target", k.String("fuse.mountpoint")). + Send() + + properties[0] = ITProperty{"heartrate", 2, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchHeartRate(ctx) + return converterU8(ctx, ans), err + }} + properties[1] = ITProperty{"battery", 3, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchBatteryLevel(ctx) + return converterU8(ctx, ans), err + }} + properties[2] = ITProperty{"motion", 4, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchMotion(ctx) + return converterMotionValues(ctx, ans), err + }} + properties[3] = ITProperty{"stepcount", 5, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchStepCount(ctx) + return converterU32(ctx, ans), err + }} + properties[4] = ITProperty{"version", 6, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.Version() + return converter1String(ctx, ans), err + }} + properties[5] = ITProperty{"address", 7, + func(ctx context.Context) (<-chan []byte, error) { + ans := dev.Address() + return converter1String(ctx, ans), nil + }} + + myfs, err = dev.FS() + if err != nil { + log.Warn("Error getting BLE filesystem").Err(err).Send() + return err + } + inodemap = make(map[string]uint64) + + // Wait until unmount before exiting + go server.Serve() + return nil +} diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index 5c3fdec..d8b6530 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -1,10 +1,9 @@ -package main +package fusefs import ( "go.arsenm.dev/infinitime" "go.arsenm.dev/infinitime/blefs" "go.arsenm.dev/logger/log" - "os" "context" "syscall" "github.com/hanwen/go-fuse/v2/fs" @@ -550,69 +549,3 @@ var _ = (fs.NodeRmdirer)((*ITNode)(nil)) func (f *ITNode) Rmdir(ctx context.Context, name string) syscall.Errno { return f.Unlink(ctx, name) } - -func startFuse(ctx context.Context, dev *infinitime.Device) error { - // This is where we'll mount the FS - os.Mkdir(k.String("fuse.mountpoint"), 0755) - root := &ITNode{kind: 0} - server, err := fs.Mount(k.String("fuse.mountpoint"), root, &fs.Options{ - MountOptions: fuse.MountOptions{ - // Set to true to see how the file system works. - Debug: false, - SingleThreaded: true, - }, - }) - if err != nil { - log.Error("Mounting failed"). - Str("target", k.String("fuse.mountpoint")). - Err(err). - Send() - return err - } - - log.Info("Mounted on target"). - Str("target", k.String("fuse.mountpoint")). - Send() - - properties[0] = ITProperty{"heartrate", 2, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchHeartRate(ctx) - return converterU8(ctx, ans), err - }} - properties[1] = ITProperty{"battery", 3, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchBatteryLevel(ctx) - return converterU8(ctx, ans), err - }} - properties[2] = ITProperty{"motion", 4, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchMotion(ctx) - return converterMotionValues(ctx, ans), err - }} - properties[3] = ITProperty{"stepcount", 5, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchStepCount(ctx) - return converterU32(ctx, ans), err - }} - properties[4] = ITProperty{"version", 6, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.Version() - return converter1String(ctx, ans), err - }} - properties[5] = ITProperty{"address", 7, - func(ctx context.Context) (<-chan []byte, error) { - ans := dev.Address() - return converter1String(ctx, ans), nil - }} - - myfs, err = dev.FS() - if err != nil { - log.Warn("Error getting BLE filesystem").Err(err).Send() - return err - } - inodemap = make(map[string]uint64) - - // Wait until unmount before exiting - go server.Serve() - return nil -} -- 2.40.1 From 87c78566c1750aac86c0cd99cae85489e6dee182 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 15:14:06 +0000 Subject: [PATCH 47/65] 3. Added builder --- fuse.go | 35 ++------------------------------ internal/fusefs/fuse.go | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/fuse.go b/fuse.go index 3b7ee77..5496f6c 100644 --- a/fuse.go +++ b/fuse.go @@ -12,7 +12,7 @@ import ( func startFuse(ctx context.Context, dev *infinitime.Device) error { // This is where we'll mount the FS os.Mkdir(k.String("fuse.mountpoint"), 0755) - root := &ITNode{kind: 0} + root := fusefs.BuildRootNode(dev) server, err := fs.Mount(k.String("fuse.mountpoint"), root, &fs.Options{ MountOptions: fuse.MountOptions{ // Set to true to see how the file system works. @@ -32,43 +32,12 @@ func startFuse(ctx context.Context, dev *infinitime.Device) error { Str("target", k.String("fuse.mountpoint")). Send() - properties[0] = ITProperty{"heartrate", 2, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchHeartRate(ctx) - return converterU8(ctx, ans), err - }} - properties[1] = ITProperty{"battery", 3, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchBatteryLevel(ctx) - return converterU8(ctx, ans), err - }} - properties[2] = ITProperty{"motion", 4, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchMotion(ctx) - return converterMotionValues(ctx, ans), err - }} - properties[3] = ITProperty{"stepcount", 5, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchStepCount(ctx) - return converterU32(ctx, ans), err - }} - properties[4] = ITProperty{"version", 6, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.Version() - return converter1String(ctx, ans), err - }} - properties[5] = ITProperty{"address", 7, - func(ctx context.Context) (<-chan []byte, error) { - ans := dev.Address() - return converter1String(ctx, ans), nil - }} + fusefs.BuildProperties(dev) - myfs, err = dev.FS() if err != nil { log.Warn("Error getting BLE filesystem").Err(err).Send() return err } - inodemap = make(map[string]uint64) // Wait until unmount before exiting go server.Serve() diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index d8b6530..feb5c03 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -89,7 +89,51 @@ type ITNode struct { path string } +func BuildRootNode(dev *infinitime.Device) *ITNode { + inodemap = make(map[string]uint64) + myfs, _ = dev.FS() + + return &ITNode{kind: 0} +} + var properties = make([]ITProperty, 6) + +func BuildProperties(dev *infinitime.Device) { + properties[0] = ITProperty{"heartrate", 2, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchHeartRate(ctx) + return converterU8(ctx, ans), err + }} + properties[1] = ITProperty{"battery", 3, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchBatteryLevel(ctx) + return converterU8(ctx, ans), err + }} + properties[2] = ITProperty{"motion", 4, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchMotion(ctx) + return converterMotionValues(ctx, ans), err + }} + properties[3] = ITProperty{"stepcount", 5, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchStepCount(ctx) + return converterU32(ctx, ans), err + }} + properties[4] = ITProperty{"version", 6, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.Version() + return converter1String(ctx, ans), err + }} + properties[5] = ITProperty{"address", 7, + func(ctx context.Context) (<-chan []byte, error) { + ans := dev.Address() + return converter1String(ctx, ans), nil + }} + +} + + + var myfs *blefs.FS = nil; var inodemap map[string]uint64 = nil; -- 2.40.1 From c05d4fe9519ee78ab58fdbd178333832f8c5dc90 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 15:15:32 +0000 Subject: [PATCH 48/65] 4. Split converters --- internal/fusefs/converters.go | 61 +++++++++++++++++++++++++++++++++++ internal/fusefs/fuse.go | 53 ------------------------------ 2 files changed, 61 insertions(+), 53 deletions(-) create mode 100644 internal/fusefs/converters.go diff --git a/internal/fusefs/converters.go b/internal/fusefs/converters.go new file mode 100644 index 0000000..c0a5cee --- /dev/null +++ b/internal/fusefs/converters.go @@ -0,0 +1,61 @@ +package fusefs + +import ( + "go.arsenm.dev/infinitime" + "context" + "strconv" +) + +func converterU8(ctx context.Context, in <-chan uint8) <-chan []byte { + out := make(chan []byte, 2) + go func() { + for { + select { + case <- ctx.Done(): + return + case event := <-in: + out <- []byte(strconv.Itoa(int(event)) + "\n") + } + } + }() + return out +} + +func converterU32(ctx context.Context, in <-chan uint32) <-chan []byte { + out := make(chan []byte, 2) + go func() { + for { + select { + case <- ctx.Done(): + return + case event := <-in: + out <- []byte(strconv.Itoa(int(event)) + "\n") + } + } + }() + return out +} + +func converterMotionValues(ctx context.Context, in <-chan infinitime.MotionValues) <-chan []byte { + out := make(chan []byte, 2) + go func() { + for { + select { + case <- ctx.Done(): + return + case event := <-in: + out <- []byte(strconv.Itoa(int(event.X)) + " " + strconv.Itoa(int(event.Y)) + " " + strconv.Itoa(int(event.Z)) + "\n") + } + } + }() + return out +} + +func converter1String(ctx context.Context, in string) <-chan []byte { + out := make(chan []byte, 2) + out <- []byte(in + "\n") + close(out) + return out +} + + diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index feb5c03..f394c2d 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -8,63 +8,10 @@ import ( "syscall" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" - "strconv" "io" "bytes" ) -func converterU8(ctx context.Context, in <-chan uint8) <-chan []byte { - out := make(chan []byte, 2) - go func() { - for { - select { - case <- ctx.Done(): - return - case event := <-in: - out <- []byte(strconv.Itoa(int(event)) + "\n") - } - } - }() - return out -} - -func converterU32(ctx context.Context, in <-chan uint32) <-chan []byte { - out := make(chan []byte, 2) - go func() { - for { - select { - case <- ctx.Done(): - return - case event := <-in: - out <- []byte(strconv.Itoa(int(event)) + "\n") - } - } - }() - return out -} - -func converterMotionValues(ctx context.Context, in <-chan infinitime.MotionValues) <-chan []byte { - out := make(chan []byte, 2) - go func() { - for { - select { - case <- ctx.Done(): - return - case event := <-in: - out <- []byte(strconv.Itoa(int(event.X)) + " " + strconv.Itoa(int(event.Y)) + " " + strconv.Itoa(int(event.Z)) + "\n") - } - } - }() - return out -} - -func converter1String(ctx context.Context, in string) <-chan []byte { - out := make(chan []byte, 2) - out <- []byte(in + "\n") - close(out) - return out -} - type ITProperty struct { name string Ino uint64 -- 2.40.1 From cc6fc3e1dc9eeae7624922f622d3e09277594377 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 16:45:42 +0000 Subject: [PATCH 49/65] removed godebug dep --- go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/go.sum b/go.sum index 577ffe0..347e737 100644 --- a/go.sum +++ b/go.sum @@ -341,7 +341,6 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -- 2.40.1 From 673383f7953beadbdacbde1c49536883386e7f19 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 18:01:25 +0000 Subject: [PATCH 50/65] Stylistic changes --- fuse.go | 2 +- internal/fusefs/fuse.go | 25 ++++++++++++------------- main.go | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/fuse.go b/fuse.go index 5496f6c..a4c8ca4 100644 --- a/fuse.go +++ b/fuse.go @@ -9,7 +9,7 @@ import ( "go.arsenm.dev/infinitime" ) -func startFuse(ctx context.Context, dev *infinitime.Device) error { +func startFUSE(ctx context.Context, dev *infinitime.Device) error { // This is where we'll mount the FS os.Mkdir(k.String("fuse.mountpoint"), 0755) root := fusefs.BuildRootNode(dev) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index f394c2d..ec5bde4 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -36,6 +36,9 @@ type ITNode struct { path string } +var myfs *blefs.FS = nil +var inodemap map[string]uint64 = nil + func BuildRootNode(dev *infinitime.Device) *ITNode { inodemap = make(map[string]uint64) myfs, _ = dev.FS() @@ -80,10 +83,6 @@ func BuildProperties(dev *infinitime.Device) { } - -var myfs *blefs.FS = nil; -var inodemap map[string]uint64 = nil; - var _ = (fs.NodeReaddirer)((*ITNode)(nil)) // Readdir is part of the NodeReaddirer interface @@ -206,7 +205,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* for _, file := range n.lst { if file.path != n.path + "/" + name { - continue; + continue } log.Info("LookUp successful").Str("path", file.path).Send() @@ -230,7 +229,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* child := n.NewInode(ctx, operations, stable) return child, 0 } - break; + break } log.Warn("LookUp failed").Str("path", n.path + "/" + name).Send() } @@ -298,7 +297,7 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) go func() { // For every progress event for sent := range fp.Progress() { - log.Info("Progress").Int("bytes", int(sent)).Int("of", len(fh.content)).Send(); + log.Info("Progress").Int("bytes", int(sent)).Int("of", len(fh.content)).Send() } }() @@ -330,7 +329,7 @@ func (fh *bytesFileWriteHandle) Fsync(ctx context.Context, flags uint32) (errno var _ = (fs.NodeGetattrer)((*ITNode)(nil)) func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno { - log.Info("getattr").Str("path", bn.path).Send(); + log.Info("getattr").Str("path", bn.path).Send() out.Ino = bn.Ino out.Mtime = bn.self.modtime out.Ctime = bn.self.modtime @@ -342,8 +341,8 @@ func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOu var _ = (fs.NodeSetattrer)((*ITNode)(nil)) func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno { log.Info("setattr").Str("path", bn.path).Send() - out.Size = 0; - out.Mtime = 0; + out.Size = 0 + out.Mtime = 0 return 0 } @@ -365,10 +364,10 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, } return fh, fuse.FOPEN_DIRECT_IO, 0 } else { - log.Info("Opening file: read").Str("path", f.path).Send(); + log.Info("Opening file: read").Str("path", f.path).Send() fp, err := myfs.Open(f.path) if err != nil { - log.Error("Opening file failed").Str("path", f.path).Err(err).Send(); + log.Error("Opening file failed").Str("path", f.path).Err(err).Send() return nil, 0, syscall.EROFS } @@ -379,7 +378,7 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, go func() { // For every progress event for sent := range fp.Progress() { - log.Info("Progress").Int("bytes", int(sent)).Int("of", int(f.self.size)).Send(); + log.Info("Progress").Int("bytes", int(sent)).Int("of", int(f.self.size)).Send() } }() diff --git a/main.go b/main.go index e9ef50c..9f3619a 100644 --- a/main.go +++ b/main.go @@ -188,7 +188,7 @@ func main() { } // Start fuse socket if k.Bool("fuse.enabled") { - err = startFuse(ctx, dev) + err = startFUSE(ctx, dev) if err != nil { log.Error("Error starting fuse socket").Err(err).Send() } -- 2.40.1 From a54ca7afdf1c16dd026df9bd36b4243867abfc42 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 18:08:58 +0000 Subject: [PATCH 51/65] Handle more errors --- fuse.go | 10 +++++++++- internal/fusefs/fuse.go | 24 +++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/fuse.go b/fuse.go index a4c8ca4..714d19e 100644 --- a/fuse.go +++ b/fuse.go @@ -12,7 +12,15 @@ import ( func startFUSE(ctx context.Context, dev *infinitime.Device) error { // This is where we'll mount the FS os.Mkdir(k.String("fuse.mountpoint"), 0755) - root := fusefs.BuildRootNode(dev) + root, err := fusefs.BuildRootNode(dev) + if err != nil { + log.Error("Building root node failed"). + Err(err). + Send() + return err + return err + } + server, err := fs.Mount(k.String("fuse.mountpoint"), root, &fs.Options{ MountOptions: fuse.MountOptions{ // Set to true to see how the file system works. diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index ec5bde4..0799d61 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -39,11 +39,16 @@ type ITNode struct { var myfs *blefs.FS = nil var inodemap map[string]uint64 = nil -func BuildRootNode(dev *infinitime.Device) *ITNode { +func BuildRootNode(dev *infinitime.Device) (*ITNode, error) { + var err error inodemap = make(map[string]uint64) - myfs, _ = dev.FS() + myfs, err = dev.FS() + if err != nil { + log.Error("FUSE failed to get filesystem").Err(err).Send() + return nil, err + } - return &ITNode{kind: 0} + return &ITNode{kind: 0}, nil } var properties = make([]ITProperty, 6) @@ -118,12 +123,21 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { case 2: // on device - files, _ := myfs.ReadDir(n.path) + files, err := myfs.ReadDir(n.path) + if err != nil { + log.Error("ReadDir failed").Str("path", n.path).Err(err).Send() + return nil, syscall.ENOENT + } + log.Info("readdir").Str("path", n.path).Int("objects", len(files)).Send() r := make([]fuse.DirEntry, len(files)) n.lst = make([]DirEntry, len(files)) for ind, entry := range files { - info, _ := entry.Info() + info, err := entry.Info() + if err != nil { + log.Error("Info failed").Str("path", n.path).Err(err).Send() + return nil, syscall.ENOENT + } name := info.Name() file := DirEntry{ -- 2.40.1 From 2396623c730201d84e653d5f62efb5e3e2376951 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 18:57:02 +0000 Subject: [PATCH 52/65] Formatted interface checks --- internal/fusefs/fuse.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index 0799d61..03456f8 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -88,7 +88,7 @@ func BuildProperties(dev *infinitime.Device) { } -var _ = (fs.NodeReaddirer)((*ITNode)(nil)) +var _ fs.NodeReaddirer = (*ITNode)(nil) // Readdir is part of the NodeReaddirer interface func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { @@ -174,7 +174,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { return fs.NewListDirStream(r), 0 } -var _ = (fs.NodeLookuper)((*ITNode)(nil)) +var _ fs.NodeLookuper = (*ITNode)(nil) func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) { switch n.kind { case 0: @@ -253,8 +253,8 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* type bytesFileReadHandle struct { content []byte } -var _ = (fs.FileReader)((*bytesFileReadHandle)(nil)) +var _ fs.FileReader = (*bytesFileReadHandle)(nil) func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { log.Info("Executing Read").Int("size", len(fh.content)).Send() end := off + int64(len(dest)) @@ -268,13 +268,13 @@ type sensorFileReadHandle struct { ch <-chan []byte cancel context.CancelFunc } -var _ = (fs.FileReader)((*sensorFileReadHandle)(nil)) +var _ fs.FileReader = (*sensorFileReadHandle)(nil) func (fh *sensorFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { content := <-fh.ch return fuse.ReadResultData(content), 0 } -var _ = (fs.FileFlusher)((*sensorFileReadHandle)(nil)) +var _ fs.FileFlusher = (*sensorFileReadHandle)(nil) func (fh *sensorFileReadHandle) Flush(ctx context.Context) (errno syscall.Errno) { fh.cancel() return 0 @@ -286,7 +286,7 @@ type bytesFileWriteHandle struct { path string } -var _ = (fs.FileWriter)((*bytesFileWriteHandle)(nil)) +var _ fs.FileWriter = (*bytesFileWriteHandle)(nil) func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int64) (written uint32, errno syscall.Errno) { log.Info("Executing Write").Str("path", fh.path).Int("prev_size", len(fh.content)).Int("next_size", len(data)).Send() if off != int64(len(fh.content)) { @@ -295,7 +295,7 @@ func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int6 return uint32(len(data)), 0 } -var _ = (fs.FileFlusher)((*bytesFileWriteHandle)(nil)) +var _ fs.FileFlusher = (*bytesFileWriteHandle)(nil) func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) { if len(fh.content) == 0 { return 0 @@ -336,12 +336,12 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) return 0 } -var _ = (fs.FileFsyncer)((*bytesFileWriteHandle)(nil)) +var _ fs.FileFsyncer = (*bytesFileWriteHandle)(nil) func (fh *bytesFileWriteHandle) Fsync(ctx context.Context, flags uint32) (errno syscall.Errno) { return fh.Flush(ctx) } -var _ = (fs.NodeGetattrer)((*ITNode)(nil)) +var _ fs.NodeGetattrer = (*ITNode)(nil) func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno { log.Info("getattr").Str("path", bn.path).Send() out.Ino = bn.Ino @@ -352,7 +352,7 @@ func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOu return 0 } -var _ = (fs.NodeSetattrer)((*ITNode)(nil)) +var _ fs.NodeSetattrer = (*ITNode)(nil) func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno { log.Info("setattr").Str("path", bn.path).Send() out.Size = 0 @@ -360,7 +360,7 @@ func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAtt return 0 } -var _ = (fs.NodeOpener)((*ITNode)(nil)) +var _ fs.NodeOpener = (*ITNode)(nil) func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { switch f.kind { case 2: @@ -436,7 +436,7 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, return nil, 0, syscall.EROFS } -var _ = (fs.NodeCreater)((*ITNode)(nil)) +var _ fs.NodeCreater = (*ITNode)(nil) func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (node *fs.Inode, fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { if f.kind != 2 { return nil, nil, 0, syscall.EROFS @@ -467,7 +467,7 @@ func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uin return node, fh, fuseFlags, 0 } -var _ = (fs.NodeMkdirer)((*ITNode)(nil)) +var _ fs.NodeMkdirer = (*ITNode)(nil) func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) { if f.kind != 2 { return nil, syscall.EROFS @@ -503,7 +503,7 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. return node, 0 } -var _ = (fs.NodeRenamer)((*ITNode)(nil)) +var _ fs.NodeRenamer = (*ITNode)(nil) func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbedder, newName string, flags uint32) syscall.Errno { p1 := f.path + "/" + name p2 := newParent.EmbeddedInode().Path(nil)[2:] + "/" + newName @@ -530,7 +530,7 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe return 0 } -var _ = (fs.NodeUnlinker)((*ITNode)(nil)) +var _ fs.NodeUnlinker = (*ITNode)(nil) func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { delete(inodemap, f.path + "/" + name) err := myfs.Remove(f.path + "/" + name) @@ -549,7 +549,7 @@ func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { return 0 } -var _ = (fs.NodeRmdirer)((*ITNode)(nil)) +var _ fs.NodeRmdirer = (*ITNode)(nil) func (f *ITNode) Rmdir(ctx context.Context, name string) syscall.Errno { return f.Unlink(ctx, name) } -- 2.40.1 From b5328ece92b8edfdc347634c0c646037675dec30 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 19:04:13 +0000 Subject: [PATCH 53/65] Made logging more consistent --- internal/fusefs/fuse.go | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index 03456f8..875bf60 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -44,7 +44,7 @@ func BuildRootNode(dev *infinitime.Device) (*ITNode, error) { inodemap = make(map[string]uint64) myfs, err = dev.FS() if err != nil { - log.Error("FUSE failed to get filesystem").Err(err).Send() + log.Error("FUSE Failed to get filesystem").Err(err).Send() return nil, err } @@ -125,17 +125,17 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { // on device files, err := myfs.ReadDir(n.path) if err != nil { - log.Error("ReadDir failed").Str("path", n.path).Err(err).Send() + log.Error("FUSE ReadDir failed").Str("path", n.path).Err(err).Send() return nil, syscall.ENOENT } - log.Info("readdir").Str("path", n.path).Int("objects", len(files)).Send() + log.Debug("FUSE ReadDir succeeded").Str("path", n.path).Int("objects", len(files)).Send() r := make([]fuse.DirEntry, len(files)) n.lst = make([]DirEntry, len(files)) for ind, entry := range files { info, err := entry.Info() if err != nil { - log.Error("Info failed").Str("path", n.path).Err(err).Send() + log.Error("FUSE Info failed").Str("path", n.path).Err(err).Send() return nil, syscall.ENOENT } name := info.Name() @@ -221,7 +221,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* if file.path != n.path + "/" + name { continue } - log.Info("LookUp successful").Str("path", file.path).Send() + log.Debug("FUSE Lookup successful").Str("path", file.path).Send() if file.isDir { stable := fs.StableAttr{ @@ -245,7 +245,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* } break } - log.Warn("LookUp failed").Str("path", n.path + "/" + name).Send() + log.Warn("FUSE Lookup failed").Str("path", n.path + "/" + name).Send() } return nil, syscall.ENOENT } @@ -256,7 +256,7 @@ type bytesFileReadHandle struct { var _ fs.FileReader = (*bytesFileReadHandle)(nil) func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { - log.Info("Executing Read").Int("size", len(fh.content)).Send() + log.Debug("FUSE Executing Read").Int("size", len(fh.content)).Send() end := off + int64(len(dest)) if end > int64(len(fh.content)) { end = int64(len(fh.content)) @@ -301,38 +301,38 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) return 0 } - log.Info("Attempting flush").Str("path", fh.path).Send() + log.Debug("FUSE Attempting flush").Str("path", fh.path).Send() fp, err := myfs.Create(fh.path, uint32(len(fh.content))) if err != nil { - log.Error("Flush failed: create").Str("path", fh.path).Err(err).Send() + log.Error("FUSE Flush failed: create").Str("path", fh.path).Err(err).Send() return syscall.EROFS } go func() { // For every progress event for sent := range fp.Progress() { - log.Info("Progress").Int("bytes", int(sent)).Int("of", len(fh.content)).Send() + log.Debug("FUSE Flush progress").Int("bytes", int(sent)).Int("total", len(fh.content)).Send() } }() r := bytes.NewReader(fh.content) nread, err := io.Copy(fp, r) if err != nil { - log.Error("Flush failed: write").Str("path", fh.path).Err(err).Send() + log.Error("FUSE Flush failed during write").Str("path", fh.path).Err(err).Send() fp.Close() return syscall.EROFS } if int(nread) != len(fh.content) { - log.Error("Flush failed: write").Str("path", fh.path).Int("expect", len(fh.content)).Int("got", int(nread)).Send() + log.Error("FUSE Flush failed during write").Str("path", fh.path).Int("expect", len(fh.content)).Int("got", int(nread)).Send() fp.Close() return syscall.EROFS } err = fp.Close() if err != nil { - log.Error("Flush failed: close").Str("path", fh.path).Err(err).Send() + log.Error("FUSE Flush failed during close").Str("path", fh.path).Err(err).Send() return syscall.EROFS } - log.Info("Flush done").Str("path", fh.path).Int("size", len(fh.content)).Send() + log.Debug("FUSE Flush done").Str("path", fh.path).Int("size", len(fh.content)).Send() return 0 } @@ -343,7 +343,7 @@ func (fh *bytesFileWriteHandle) Fsync(ctx context.Context, flags uint32) (errno var _ fs.NodeGetattrer = (*ITNode)(nil) func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno { - log.Info("getattr").Str("path", bn.path).Send() + log.Debug("FUSE getattr").Str("path", bn.path).Send() out.Ino = bn.Ino out.Mtime = bn.self.modtime out.Ctime = bn.self.modtime @@ -354,7 +354,7 @@ func (bn *ITNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOu var _ fs.NodeSetattrer = (*ITNode)(nil) func (bn *ITNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno { - log.Info("setattr").Str("path", bn.path).Send() + log.Debug("FUSE setattr").Str("path", bn.path).Send() out.Size = 0 out.Mtime = 0 return 0 @@ -366,22 +366,22 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, case 2: // FS file if openFlags&syscall.O_RDWR != 0 { - log.Warn("open: failed RDWR").Str("path", f.path).Send() + log.Error("FUSE Open failed: RDWR").Str("path", f.path).Send() return nil, 0, syscall.EROFS } if openFlags & syscall.O_WRONLY != 0 { - log.Info("Opening file: write").Str("path", f.path).Send() + log.Debug("FUSE Opening for write").Str("path", f.path).Send() fh = &bytesFileWriteHandle{ path : f.path, content : make([]byte, 0), } return fh, fuse.FOPEN_DIRECT_IO, 0 } else { - log.Info("Opening file: read").Str("path", f.path).Send() + log.Debug("FUSE Opening for read").Str("path", f.path).Send() fp, err := myfs.Open(f.path) if err != nil { - log.Error("Opening file failed").Str("path", f.path).Err(err).Send() + log.Error("FUSE: Opening failed").Str("path", f.path).Err(err).Send() return nil, 0, syscall.EROFS } @@ -392,13 +392,13 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, go func() { // For every progress event for sent := range fp.Progress() { - log.Info("Progress").Int("bytes", int(sent)).Int("of", int(f.self.size)).Send() + log.Debug("FUSE Read progress").Int("bytes", int(sent)).Int("total", int(f.self.size)).Send() } }() _, err = io.Copy(b, fp) if err != nil { - log.Error("Read failed").Str("path", f.path).Err(err).Send() + log.Error("FUSE Read failed").Str("path", f.path).Err(err).Send() fp.Close() return nil, 0, syscall.EROFS } @@ -461,7 +461,7 @@ func (f *ITNode) Create(ctx context.Context, name string, flags uint32, mode uin content : make([]byte, 0), } - log.Info("Creating file").Str("path", path).Send() + log.Debug("FUSE Creating file").Str("path", path).Send() errno = 0 return node, fh, fuseFlags, 0 @@ -476,7 +476,7 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. path := f.path + "/" + name err := myfs.Mkdir(path) if err != nil { - log.Info("Mkdir failed"). + log.Error("FUSE Mkdir failed"). Str("path", path). Err(err). Send() @@ -496,7 +496,7 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. } node := f.NewInode(ctx, operations, stable) - log.Info("Mkdir sucess"). + log.Debug("FUSE Mkdir success"). Str("path", path). Int("ino", int(ino)). Send() @@ -510,7 +510,7 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe err := myfs.Rename(p1, p2) if err != nil { - log.Error("Rename failed"). + log.Error("FUSE Rename failed"). Str("src", p1). Str("dest", p2). Err(err). @@ -518,7 +518,7 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe return syscall.EROFS } - log.Info("Rename sucess"). + log.Debug("FUSE Rename sucess"). Str("src", p1). Str("dest", p2). Send() @@ -535,7 +535,7 @@ func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { delete(inodemap, f.path + "/" + name) err := myfs.Remove(f.path + "/" + name) if err != nil { - log.Error("Unlink failed"). + log.Error("FUSE Unlink failed"). Str("file", f.path + "/" + name). Err(err). Send() @@ -543,7 +543,7 @@ func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { return syscall.EROFS } - log.Info("Unlink success"). + log.Debug("FUSE Unlink success"). Str("file", f.path + "/" + name). Send() return 0 -- 2.40.1 From 3b9690103b489b23383c1c076837731f6a815bd8 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 19:07:14 +0000 Subject: [PATCH 54/65] Moved starting of fuse --- main.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 9f3619a..0accec8 100644 --- a/main.go +++ b/main.go @@ -181,11 +181,6 @@ func main() { log.Error("Error intializing puremaps integration").Err(err).Send() } - // Start control socket - err = startSocket(ctx, dev) - if err != nil { - log.Error("Error starting socket").Err(err).Send() - } // Start fuse socket if k.Bool("fuse.enabled") { err = startFUSE(ctx, dev) @@ -193,6 +188,12 @@ func main() { log.Error("Error starting fuse socket").Err(err).Send() } } + + // Start control socket + err = startSocket(ctx, dev) + if err != nil { + log.Error("Error starting socket").Err(err).Send() + } // Block forever select {} } -- 2.40.1 From 955e1323ce970dc33a17d91f29eab638d0c7d0a1 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Wed, 1 Mar 2023 19:35:58 +0000 Subject: [PATCH 55/65] Send better syscall status codes --- internal/fusefs/fuse.go | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index 875bf60..70fb1eb 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -126,6 +126,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { files, err := myfs.ReadDir(n.path) if err != nil { log.Error("FUSE ReadDir failed").Str("path", n.path).Err(err).Send() + // TODO we probably should figure out why it failed return nil, syscall.ENOENT } @@ -209,7 +210,6 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* return child, 0 } } - return nil, syscall.ENOENT case 2: // FS object @@ -290,6 +290,8 @@ var _ fs.FileWriter = (*bytesFileWriteHandle)(nil) func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int64) (written uint32, errno syscall.Errno) { log.Info("Executing Write").Str("path", fh.path).Int("prev_size", len(fh.content)).Int("next_size", len(data)).Send() if off != int64(len(fh.content)) { + log.Error("FUSE Write file size changed unexpectedly").Int("expect", int(off)).Int("received", len(fh.content)).Send() + return 0, syscall.ENXIO } fh.content = append(fh.content[:], data[:]...) return uint32(len(data)), 0 @@ -320,17 +322,17 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) if err != nil { log.Error("FUSE Flush failed during write").Str("path", fh.path).Err(err).Send() fp.Close() - return syscall.EROFS + return syscall.EIO } if int(nread) != len(fh.content) { log.Error("FUSE Flush failed during write").Str("path", fh.path).Int("expect", len(fh.content)).Int("got", int(nread)).Send() fp.Close() - return syscall.EROFS + return syscall.EIO } err = fp.Close() if err != nil { log.Error("FUSE Flush failed during close").Str("path", fh.path).Err(err).Send() - return syscall.EROFS + return syscall.EIO } log.Debug("FUSE Flush done").Str("path", fh.path).Int("size", len(fh.content)).Send() @@ -381,6 +383,7 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, log.Debug("FUSE Opening for read").Str("path", f.path).Send() fp, err := myfs.Open(f.path) if err != nil { + // TODO we probably should figure out why it failed log.Error("FUSE: Opening failed").Str("path", f.path).Err(err).Send() return nil, 0, syscall.EROFS } @@ -400,7 +403,7 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, if err != nil { log.Error("FUSE Read failed").Str("path", f.path).Err(err).Send() fp.Close() - return nil, 0, syscall.EROFS + return nil, 0, syscall.EIO } fh = &bytesFileReadHandle{ @@ -422,7 +425,8 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, sub_ctx, cancel := context.WithCancel(ctx) ans, err := value.gen(sub_ctx) if err != nil { - return nil, 0, syscall.EROFS + // TODO we probably should figure out why it failed + return nil, 0, syscall.EIO } fh = &sensorFileReadHandle{ @@ -433,7 +437,7 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, } } } - return nil, 0, syscall.EROFS + return nil, 0, syscall.EINVAL } var _ fs.NodeCreater = (*ITNode)(nil) @@ -480,6 +484,7 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. Str("path", path). Err(err). Send() + // TODO we probably should figure out why it failed return nil, syscall.EROFS } @@ -505,6 +510,10 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. var _ fs.NodeRenamer = (*ITNode)(nil) func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbedder, newName string, flags uint32) syscall.Errno { + if f.kind != 2 { + return syscall.EROFS + } + p1 := f.path + "/" + name p2 := newParent.EmbeddedInode().Path(nil)[2:] + "/" + newName @@ -516,7 +525,8 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe Err(err). Send() - return syscall.EROFS + // TODO we probably should figure out why it failed + return syscall.EIO } log.Debug("FUSE Rename sucess"). Str("src", p1). @@ -532,6 +542,10 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe var _ fs.NodeUnlinker = (*ITNode)(nil) func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { + if f.kind != 2 { + return syscall.EROFS + } + delete(inodemap, f.path + "/" + name) err := myfs.Remove(f.path + "/" + name) if err != nil { @@ -540,7 +554,8 @@ func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { Err(err). Send() - return syscall.EROFS + // TODO we probably should figure out why it failed + return syscall.EIO } log.Debug("FUSE Unlink success"). -- 2.40.1 From 4c59561a993fad04afe8eabf050410443b40110c Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sat, 4 Mar 2023 09:14:49 +0000 Subject: [PATCH 56/65] Added error to syscall function Some of these aren't ideal.. --- internal/fusefs/syscallerr.go | 67 +++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 internal/fusefs/syscallerr.go diff --git a/internal/fusefs/syscallerr.go b/internal/fusefs/syscallerr.go new file mode 100644 index 0000000..e055acb --- /dev/null +++ b/internal/fusefs/syscallerr.go @@ -0,0 +1,67 @@ +package fusefs +import ( + "go.arsenm.dev/infinitime/blefs" + "syscall" +) + +func syscallErr(err error) syscall.Errno { + if err == nil { + return 0 + } + + switch err { + case blefs.FSError{0x02}: // filesystem error + return syscall.EIO // TODO + case blefs.FSError{0x05}: // read-only filesystem + return syscall.EROFS + case blefs.FSError{0x03}: // no such file + return syscall.ENOENT + case blefs.FSError{0x04}: // protocol error + return syscall.EPROTO + case blefs.FSError{-5}: // input/output error + return syscall.EIO + case blefs.FSError{-84}: // filesystem is corrupted + return syscall.ENOTRECOVERABLE // TODO + case blefs.FSError{-2}: // no such directory entry + return syscall.ENOENT + case blefs.FSError{-17}: // entry already exists + return syscall.EEXIST + case blefs.FSError{-20}: // entry is not a directory + return syscall.ENOTDIR + case blefs.FSError{-39}: // directory is not empty + return syscall.ENOTEMPTY + case blefs.FSError{-9}: // bad file number + return syscall.EBADF + case blefs.FSError{-27}: // file is too large + return syscall.EFBIG + case blefs.FSError{-22}: // invalid parameter + return syscall.EINVAL + case blefs.FSError{-28}: // no space left on device + return syscall.ENOSPC + case blefs.FSError{-12}: // no more memory available + return syscall.ENOMEM + case blefs.FSError{-61}: // no attr available + return syscall.ENODATA // TODO + case blefs.FSError{-36}: // file name is too long + return syscall.ENAMETOOLONG + case blefs.ErrFileNotExists: // file does not exist + return syscall.ENOENT + case blefs.ErrFileReadOnly: // file is read only + return syscall.EACCES + case blefs.ErrFileWriteOnly: // file is write only + return syscall.EACCES + case blefs.ErrInvalidOffset: // invalid file offset + return syscall.EFAULT // TODO + case blefs.ErrOffsetChanged: // offset has already been changed + return syscall.ESPIPE + case blefs.ErrReadOpen: // only one file can be opened for reading at a time + return syscall.ENFILE + case blefs.ErrWriteOpen: // only one file can be opened for writing at a time + return syscall.ENFILE + case blefs.ErrNoRemoveRoot: // refusing to remove root directory + return syscall.EPERM + } + + return syscall.EIO // TODO + +} -- 2.40.1 From b28c386c4ebd36ca5c814e134d15f784b50f2b82 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sat, 4 Mar 2023 09:19:27 +0000 Subject: [PATCH 57/65] Used new error conversion routine --- internal/fusefs/fuse.go | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index 70fb1eb..a9adaba 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -126,8 +126,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { files, err := myfs.ReadDir(n.path) if err != nil { log.Error("FUSE ReadDir failed").Str("path", n.path).Err(err).Send() - // TODO we probably should figure out why it failed - return nil, syscall.ENOENT + return nil, syscallErr(err) } log.Debug("FUSE ReadDir succeeded").Str("path", n.path).Int("objects", len(files)).Send() @@ -137,7 +136,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { info, err := entry.Info() if err != nil { log.Error("FUSE Info failed").Str("path", n.path).Err(err).Send() - return nil, syscall.ENOENT + return nil, syscallErr(err) } name := info.Name() @@ -307,7 +306,7 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) fp, err := myfs.Create(fh.path, uint32(len(fh.content))) if err != nil { log.Error("FUSE Flush failed: create").Str("path", fh.path).Err(err).Send() - return syscall.EROFS + return syscallErr(err) } go func() { @@ -322,7 +321,7 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) if err != nil { log.Error("FUSE Flush failed during write").Str("path", fh.path).Err(err).Send() fp.Close() - return syscall.EIO + return syscallErr(err) } if int(nread) != len(fh.content) { log.Error("FUSE Flush failed during write").Str("path", fh.path).Int("expect", len(fh.content)).Int("got", int(nread)).Send() @@ -332,7 +331,7 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) err = fp.Close() if err != nil { log.Error("FUSE Flush failed during close").Str("path", fh.path).Err(err).Send() - return syscall.EIO + return syscallErr(err) } log.Debug("FUSE Flush done").Str("path", fh.path).Int("size", len(fh.content)).Send() @@ -383,9 +382,8 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, log.Debug("FUSE Opening for read").Str("path", f.path).Send() fp, err := myfs.Open(f.path) if err != nil { - // TODO we probably should figure out why it failed log.Error("FUSE: Opening failed").Str("path", f.path).Err(err).Send() - return nil, 0, syscall.EROFS + return nil, 0, syscallErr(err) } defer fp.Close() @@ -403,7 +401,7 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, if err != nil { log.Error("FUSE Read failed").Str("path", f.path).Err(err).Send() fp.Close() - return nil, 0, syscall.EIO + return nil, 0, syscallErr(err) } fh = &bytesFileReadHandle{ @@ -425,8 +423,7 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, sub_ctx, cancel := context.WithCancel(ctx) ans, err := value.gen(sub_ctx) if err != nil { - // TODO we probably should figure out why it failed - return nil, 0, syscall.EIO + return nil, 0, syscallErr(err) } fh = &sensorFileReadHandle{ @@ -484,8 +481,7 @@ func (f *ITNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse. Str("path", path). Err(err). Send() - // TODO we probably should figure out why it failed - return nil, syscall.EROFS + return nil, syscallErr(err) } ino := uint64(len(inodemap)) + 11 @@ -525,8 +521,7 @@ func (f *ITNode) Rename(ctx context.Context, name string, newParent fs.InodeEmbe Err(err). Send() - // TODO we probably should figure out why it failed - return syscall.EIO + return syscallErr(err) } log.Debug("FUSE Rename sucess"). Str("src", p1). @@ -554,8 +549,7 @@ func (f *ITNode) Unlink(ctx context.Context, name string) syscall.Errno { Err(err). Send() - // TODO we probably should figure out why it failed - return syscall.EIO + return syscallErr(err) } log.Debug("FUSE Unlink success"). -- 2.40.1 From 9bbdc3bd5203af3235c73ddcff119eec7f337788 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sat, 11 Mar 2023 14:05:13 +0000 Subject: [PATCH 58/65] fixed typo --- fuse.go | 1 - 1 file changed, 1 deletion(-) diff --git a/fuse.go b/fuse.go index 714d19e..83b4570 100644 --- a/fuse.go +++ b/fuse.go @@ -17,7 +17,6 @@ func startFUSE(ctx context.Context, dev *infinitime.Device) error { log.Error("Building root node failed"). Err(err). Send() - return err return err } -- 2.40.1 From dc53ead3391800b01dec394326e53f8b28337913 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sat, 11 Mar 2023 14:08:49 +0000 Subject: [PATCH 59/65] Fixed 'touch' behaviour --- internal/fusefs/fuse.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index a9adaba..2686695 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -298,9 +298,6 @@ func (fh *bytesFileWriteHandle) Write(ctx context.Context, data []byte, off int6 var _ fs.FileFlusher = (*bytesFileWriteHandle)(nil) func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) { - if len(fh.content) == 0 { - return 0 - } log.Debug("FUSE Attempting flush").Str("path", fh.path).Send() fp, err := myfs.Create(fh.path, uint32(len(fh.content))) @@ -309,6 +306,16 @@ func (fh *bytesFileWriteHandle) Flush(ctx context.Context) (errno syscall.Errno) return syscallErr(err) } + if len(fh.content) == 0 { + log.Debug("FUSE Flush no data to write").Str("path", fh.path).Send() + err = fp.Close() + if err != nil { + log.Error("FUSE Flush failed during close").Str("path", fh.path).Err(err).Send() + return syscallErr(err) + } + return 0 + } + go func() { // For every progress event for sent := range fp.Progress() { -- 2.40.1 From 84c7a33c40dcab7b674fd7367474ff5b5a3030a3 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 12 Mar 2023 12:32:56 +0000 Subject: [PATCH 60/65] Added unmount function Designed by Arsen6331 --- fuse.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fuse.go b/fuse.go index 83b4570..a5dea5b 100644 --- a/fuse.go +++ b/fuse.go @@ -11,7 +11,15 @@ import ( func startFUSE(ctx context.Context, dev *infinitime.Device) error { // This is where we'll mount the FS - os.Mkdir(k.String("fuse.mountpoint"), 0755) + err := os.MkdirAll(k.String("fuse.mountpoint"), 0755) + if err != nil && !os.IsExist(err) { + return err + } + + // Ignore the error because nothing might be mounted on the mountpoint + _ = fusefs.Unmount(k.String("fuse.mountpoint")) + + root, err := fusefs.BuildRootNode(dev) if err != nil { log.Error("Building root node failed"). -- 2.40.1 From c5a6e0d2980c51a6ca3d4bd3bc751c0406b65387 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 12 Mar 2023 12:43:42 +0000 Subject: [PATCH 61/65] Added oneshot property to ITProperty --- internal/fusefs/fuse.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index 2686695..5613150 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -15,6 +15,7 @@ import ( type ITProperty struct { name string Ino uint64 + oneshot bool gen func(context.Context) (<-chan []byte, error) } @@ -54,32 +55,37 @@ func BuildRootNode(dev *infinitime.Device) (*ITNode, error) { var properties = make([]ITProperty, 6) func BuildProperties(dev *infinitime.Device) { - properties[0] = ITProperty{"heartrate", 2, + properties[0] = ITProperty{"heartrate", 2, true, func(ctx context.Context) (<-chan []byte, error) { ans, err := dev.WatchHeartRate(ctx) return converterU8(ctx, ans), err }} - properties[1] = ITProperty{"battery", 3, + properties[1] = ITProperty{"battery", 3, true, func(ctx context.Context) (<-chan []byte, error) { ans, err := dev.WatchBatteryLevel(ctx) return converterU8(ctx, ans), err }} - properties[2] = ITProperty{"motion", 4, + properties[2] = ITProperty{"motion", 4, true, func(ctx context.Context) (<-chan []byte, error) { ans, err := dev.WatchMotion(ctx) return converterMotionValues(ctx, ans), err }} - properties[3] = ITProperty{"stepcount", 5, + properties[3] = ITProperty{"motion", 5, true, + func(ctx context.Context) (<-chan []byte, error) { + ans, err := dev.WatchMotion(ctx) + return converterMotionValues(ctx, ans), err + }} + properties[4] = ITProperty{"stepcount", 6, true, func(ctx context.Context) (<-chan []byte, error) { ans, err := dev.WatchStepCount(ctx) return converterU32(ctx, ans), err }} - properties[4] = ITProperty{"version", 6, + properties[5] = ITProperty{"version", 7, true, func(ctx context.Context) (<-chan []byte, error) { ans, err := dev.Version() return converter1String(ctx, ans), err }} - properties[5] = ITProperty{"address", 7, + properties[6] = ITProperty{"address", 8, true, func(ctx context.Context) (<-chan []byte, error) { ans := dev.Address() return converter1String(ctx, ans), nil -- 2.40.1 From 1a1bc30df991c396b039957581e8964dc882f256 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Sun, 12 Mar 2023 12:55:44 +0000 Subject: [PATCH 62/65] Renamed device folder --- internal/fusefs/fuse.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index 5613150..b9f8ed0 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -103,7 +103,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { // root folder r := make([]fuse.DirEntry, 2) r[0] = fuse.DirEntry{ - Name: "device", + Name: "info", Ino: 0, Mode: fuse.S_IFDIR, } @@ -115,7 +115,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { return fs.NewListDirStream(r), 0 case 1: - // device folder + // info folder r := make([]fuse.DirEntry, 6) for ind, value := range properties { r[ind] = fuse.DirEntry{ @@ -128,7 +128,7 @@ func (n *ITNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) { return fs.NewListDirStream(r), 0 case 2: - // on device + // on info files, err := myfs.ReadDir(n.path) if err != nil { log.Error("FUSE ReadDir failed").Str("path", n.path).Err(err).Send() @@ -185,7 +185,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* switch n.kind { case 0: // root folder - if name == "device" { + if name == "info" { stable := fs.StableAttr{ Mode: fuse.S_IFDIR, Ino: uint64(0), @@ -203,7 +203,7 @@ func (n *ITNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (* return child, 0 } case 1: - // device folder + // info folder for _, value := range properties { if value.name == name { stable := fs.StableAttr{ -- 2.40.1 From 613d33ff4d6ad8b8990d6fc68f8ccbc55ec12d26 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Thu, 23 Mar 2023 15:20:31 +0000 Subject: [PATCH 63/65] Follow-up to 84c7a33: added unmount.go --- internal/fusefs/unmount.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 internal/fusefs/unmount.go diff --git a/internal/fusefs/unmount.go b/internal/fusefs/unmount.go new file mode 100644 index 0000000..99f9aa6 --- /dev/null +++ b/internal/fusefs/unmount.go @@ -0,0 +1,15 @@ +package fusefs + +import ( + _ "unsafe" + "github.com/hanwen/go-fuse/v2/fuse" +) + +func Unmount(mountPoint string) error { + return unmount(mountPoint, &fuse.MountOptions{DirectMount: false}) +} + +// Unfortunately, the FUSE library does not export its unmount function, +// so this is required until that changes +//go:linkname unmount github.com/hanwen/go-fuse/v2/fuse.unmount +func unmount(mountPoint string, opts *fuse.MountOptions) error -- 2.40.1 From 98775600af451710e6993980b294c0576a531fa4 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Thu, 23 Mar 2023 15:13:59 +0000 Subject: [PATCH 64/65] [ci skip] 1. dropped channels in ITProperty --- internal/fusefs/converters.go | 61 ----------------------------------- internal/fusefs/fuse.go | 53 ++++++++++++++---------------- 2 files changed, 24 insertions(+), 90 deletions(-) delete mode 100644 internal/fusefs/converters.go diff --git a/internal/fusefs/converters.go b/internal/fusefs/converters.go deleted file mode 100644 index c0a5cee..0000000 --- a/internal/fusefs/converters.go +++ /dev/null @@ -1,61 +0,0 @@ -package fusefs - -import ( - "go.arsenm.dev/infinitime" - "context" - "strconv" -) - -func converterU8(ctx context.Context, in <-chan uint8) <-chan []byte { - out := make(chan []byte, 2) - go func() { - for { - select { - case <- ctx.Done(): - return - case event := <-in: - out <- []byte(strconv.Itoa(int(event)) + "\n") - } - } - }() - return out -} - -func converterU32(ctx context.Context, in <-chan uint32) <-chan []byte { - out := make(chan []byte, 2) - go func() { - for { - select { - case <- ctx.Done(): - return - case event := <-in: - out <- []byte(strconv.Itoa(int(event)) + "\n") - } - } - }() - return out -} - -func converterMotionValues(ctx context.Context, in <-chan infinitime.MotionValues) <-chan []byte { - out := make(chan []byte, 2) - go func() { - for { - select { - case <- ctx.Done(): - return - case event := <-in: - out <- []byte(strconv.Itoa(int(event.X)) + " " + strconv.Itoa(int(event.Y)) + " " + strconv.Itoa(int(event.Z)) + "\n") - } - } - }() - return out -} - -func converter1String(ctx context.Context, in string) <-chan []byte { - out := make(chan []byte, 2) - out <- []byte(in + "\n") - close(out) - return out -} - - diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index b9f8ed0..fceaae0 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -10,13 +10,13 @@ import ( "github.com/hanwen/go-fuse/v2/fuse" "io" "bytes" + "strconv" ) type ITProperty struct { name string Ino uint64 - oneshot bool - gen func(context.Context) (<-chan []byte, error) + gen func() ([]byte, error) } @@ -55,40 +55,35 @@ func BuildRootNode(dev *infinitime.Device) (*ITNode, error) { var properties = make([]ITProperty, 6) func BuildProperties(dev *infinitime.Device) { - properties[0] = ITProperty{"heartrate", 2, true, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchHeartRate(ctx) - return converterU8(ctx, ans), err + properties[0] = ITProperty{"heartrate", 2, + func() ([]byte, error) { + ans, err := dev.HeartRate() + return []byte(strconv.Itoa(int(ans)) + "\n"), err }} - properties[1] = ITProperty{"battery", 3, true, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchBatteryLevel(ctx) - return converterU8(ctx, ans), err + properties[1] = ITProperty{"battery", 3, + func() ([]byte, error) { + ans, err := dev.BatteryLevel() + return []byte(strconv.Itoa(int(ans)) + "\n"), err }} - properties[2] = ITProperty{"motion", 4, true, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchMotion(ctx) - return converterMotionValues(ctx, ans), err + properties[2] = ITProperty{"motion", 4, + func() ([]byte, error) { + ans, err := dev.Motion() + return []byte(strconv.Itoa(int(ans.X)) + " " + strconv.Itoa(int(ans.Y)) + " " + strconv.Itoa(int(ans.Z)) + "\n"), err }} - properties[3] = ITProperty{"motion", 5, true, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchMotion(ctx) - return converterMotionValues(ctx, ans), err + properties[3] = ITProperty{"stepcount", 6, + func() ([]byte, error) { + ans, err := dev.StepCount() + return []byte(strconv.Itoa(int(ans)) + "\n"), err }} - properties[4] = ITProperty{"stepcount", 6, true, - func(ctx context.Context) (<-chan []byte, error) { - ans, err := dev.WatchStepCount(ctx) - return converterU32(ctx, ans), err - }} - properties[5] = ITProperty{"version", 7, true, - func(ctx context.Context) (<-chan []byte, error) { + properties[4] = ITProperty{"version", 7, + func() ([]byte, error) { ans, err := dev.Version() - return converter1String(ctx, ans), err + return []byte(ans + "\n"), err }} - properties[6] = ITProperty{"address", 8, true, - func(ctx context.Context) (<-chan []byte, error) { + properties[5] = ITProperty{"address", 8, + func() ([]byte, error) { ans := dev.Address() - return converter1String(ctx, ans), nil + return []byte(ans + "\n"), nil }} } -- 2.40.1 From 008f6b35a991bd653a833c658ce87eed6b2b6566 Mon Sep 17 00:00:00 2001 From: Yannick Ulrich Date: Thu, 23 Mar 2023 15:15:25 +0000 Subject: [PATCH 65/65] 2. Dropped channel in sensorFileReadHandle --- internal/fusefs/fuse.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/fusefs/fuse.go b/internal/fusefs/fuse.go index fceaae0..9855d3f 100644 --- a/internal/fusefs/fuse.go +++ b/internal/fusefs/fuse.go @@ -265,18 +265,20 @@ func (fh *bytesFileReadHandle) Read(ctx context.Context, dest []byte, off int64) } type sensorFileReadHandle struct { - ch <-chan []byte - cancel context.CancelFunc + content []byte } var _ fs.FileReader = (*sensorFileReadHandle)(nil) func (fh *sensorFileReadHandle) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { - content := <-fh.ch - return fuse.ReadResultData(content), 0 + log.Info("Executing Read").Int("size", len(fh.content)).Send() + end := off + int64(len(dest)) + if end > int64(len(fh.content)) { + end = int64(len(fh.content)) + } + return fuse.ReadResultData(fh.content[off:end]), 0 } var _ fs.FileFlusher = (*sensorFileReadHandle)(nil) func (fh *sensorFileReadHandle) Flush(ctx context.Context) (errno syscall.Errno) { - fh.cancel() return 0 } @@ -428,15 +430,13 @@ func (f *ITNode) Open(ctx context.Context, openFlags uint32) (fh fs.FileHandle, for _, value := range properties { if value.Ino == f.Ino { - sub_ctx, cancel := context.WithCancel(ctx) - ans, err := value.gen(sub_ctx) + ans, err := value.gen() if err != nil { return nil, 0, syscallErr(err) } fh = &sensorFileReadHandle{ - ch: ans, - cancel : cancel, + content : ans, } return fh, fuse.FOPEN_DIRECT_IO, 0 } -- 2.40.1