Added FUSE support #55

Merged
Elara6331 merged 65 commits from yannickulrich/itd:fuse into master 2023-03-25 22:23:52 +00:00
Showing only changes of commit b5328ece92 - Show all commits

View File

@ -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
Elara6331 marked this conversation as resolved Outdated

How would you recommend doing this? I suppose it could fail for all sorts of reasons such as

  • no such file or directory ENOENT
  • generic input/output error EIO
  • invalid argument EINVAL
  • connection aborted ECONNABORTED
  • connection refused ECONNREFUSED
  • connection reset ECONNRESET
  • is actually a file EISNAM

In other places such as when we open a file, we could have

  • is actually a folder EISDIR
  • file exists EEXIST

Again, I'm sorry but I'm not a Go expert and don't really now how to do this properly.. especially when dealing with FSError

How would you recommend doing this? I suppose it could fail for all sorts of reasons such as * no such file or directory `ENOENT` * generic input/output error `EIO` * invalid argument `EINVAL` * connection aborted `ECONNABORTED` * connection refused `ECONNREFUSED` * connection reset `ECONNRESET` * is actually a file `EISNAM` In other places such as when we open a file, we could have * is actually a folder `EISDIR` * file exists `EEXIST` Again, I'm sorry but I'm not a Go expert and don't really now how to do this properly.. especially when dealing with `FSError`

The err can be several different kinds of errors, and FSError is just one of them. It's actually a type I made. You can see it here: https://gitea.arsenm.dev/Arsen6331/infinitime/src/commit/512d48bc2469/blefs/error.go#L20. It contains an error code you can check to see what went wrong, and you can scroll down to see the meaning of each code.

In this case, I'd use a Go type switch to check which error type actually occurred and then check the code or do whatever else needs to be done. Maybe there could be a function like syscallErr() that takes an error and returns the proper syscall error?

If you don't feel comfortable doing that, I can merge this and then implement it myself and send you the commit so you can see how I did it, or you can just try it yourself, whatever you feel would be better.

The `err` can be several different kinds of errors, and `FSError` is just one of them. It's actually a type I made. You can see it here: https://gitea.arsenm.dev/Arsen6331/infinitime/src/commit/512d48bc2469/blefs/error.go#L20. It contains an error code you can check to see what went wrong, and you can scroll down to see the meaning of each code. In this case, I'd use a Go type switch to check which error type actually occurred and then check the code or do whatever else needs to be done. Maybe there could be a function like `syscallErr()` that takes an `error` and returns the proper syscall error? If you don't feel comfortable doing that, I can merge this and then implement it myself and send you the commit so you can see how I did it, or you can just try it yourself, whatever you feel would be better.

Something like in 4c59561a99? There are a few TODO where I'm not sure what the correct POSIX error would be and improvised. If you have a better idea, feel free to change them though

Something like in 4c59561a99? There are a few `TODO` where I'm not sure what the correct POSIX error would be and improvised. If you have a better idea, feel free to change them though

That looks good, thanks

That looks good, thanks
}
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
yannickulrich marked this conversation as resolved Outdated
- log.Info("Progress").Int("bytes", int(sent)).Int("of", len(fh.content)).Send()
+ log.Info("FUSE Write Progress").Int("bytes", int(sent)).Int("total", len(fh.content)).Send()
```diff - log.Info("Progress").Int("bytes", int(sent)).Int("of", len(fh.content)).Send() + log.Info("FUSE Write Progress").Int("bytes", int(sent)).Int("total", len(fh.content)).Send()

Done in b5328ec

Done in b5328ec
}
yannickulrich marked this conversation as resolved Outdated

This is not correct. If no content has been written, you should still create the file because the user might want to create an empty file using a command like touch.

This is not correct. If no content has been written, you should still create the file because the user might want to create an empty file using a command like `touch`.

Oh, good point, thank you. Should be fixed now.

Oh, good point, thank you. Should be fixed now.
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
yannickulrich marked this conversation as resolved
Review

These should be debug logs rather than info logs. Also, the message should be a bit more specific, something like "FUSE getattr". Same for all the similar logs.

These should be debug logs rather than info logs. Also, the message should be a bit more specific, something like "FUSE getattr". Same for all the similar logs.
Review

Done in b5328ec

Done in b5328ec
}
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