2020-04-27 16:46:23 +00:00
|
|
|
package node
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"math"
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
"github.com/hanwen/go-fuse/v2/fs"
|
|
|
|
"github.com/hanwen/go-fuse/v2/fuse"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ fs.NodeGetattrer = &File{}
|
|
|
|
var _ fs.NodeOpener = &File{}
|
|
|
|
var _ fs.NodeReader = &File{}
|
2020-06-03 09:03:13 +00:00
|
|
|
var _ fs.NodeReleaser = &File{}
|
2020-04-27 16:46:23 +00:00
|
|
|
|
|
|
|
// File is a fuse node for files inside a torrent
|
|
|
|
type File struct {
|
|
|
|
fs.Inode
|
|
|
|
|
|
|
|
f ReaderFunc
|
|
|
|
r io.ReaderAt
|
|
|
|
len int64
|
|
|
|
pieceLen int32
|
|
|
|
numPieces int64
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewFile(readerFunc ReaderFunc, len int64) *File {
|
|
|
|
return &File{
|
|
|
|
f: readerFunc,
|
|
|
|
len: len,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewFileWithBlocks(readerFunc ReaderFunc, len int64, pieceLen int32, numPieces int64) *File {
|
|
|
|
return &File{
|
|
|
|
f: readerFunc,
|
|
|
|
len: len,
|
|
|
|
pieceLen: pieceLen,
|
|
|
|
numPieces: numPieces,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tr *File) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
|
|
|
|
out.Mode = syscall.S_IFREG & 07777
|
|
|
|
out.Nlink = 1
|
|
|
|
out.Size = uint64(tr.len)
|
|
|
|
if tr.pieceLen != 0 {
|
|
|
|
out.Blksize = uint32(tr.pieceLen)
|
|
|
|
out.Blocks = uint64(tr.numPieces)
|
|
|
|
}
|
|
|
|
|
|
|
|
return fs.OK
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tr *File) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
|
|
|
// TODO use filehandle
|
|
|
|
if tr.r == nil {
|
|
|
|
r, err := tr.f()
|
|
|
|
if err != nil {
|
|
|
|
log.Println("error opening reader for file", err)
|
2020-06-03 09:03:13 +00:00
|
|
|
return nil, 0, syscall.EIO
|
2020-04-27 16:46:23 +00:00
|
|
|
}
|
2020-05-02 12:06:18 +00:00
|
|
|
|
2020-04-27 16:46:23 +00:00
|
|
|
tr.r = r
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fuse.FOPEN_KEEP_CACHE, fs.OK
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tr *File) Read(ctx context.Context, f fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
|
|
|
|
end := int(math.Min(float64(len(dest)), float64(int64(tr.len)-off)))
|
2020-06-03 09:03:13 +00:00
|
|
|
if end < 0 {
|
|
|
|
end = 0
|
|
|
|
}
|
2020-04-27 16:46:23 +00:00
|
|
|
|
|
|
|
buf := dest[:end]
|
|
|
|
|
|
|
|
n, err := tr.r.ReadAt(buf, off)
|
|
|
|
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
log.Println("error read data", err)
|
|
|
|
return nil, syscall.EIO
|
|
|
|
}
|
2020-05-02 12:06:18 +00:00
|
|
|
|
2020-04-27 16:46:23 +00:00
|
|
|
buf = buf[:n]
|
|
|
|
return fuse.ReadResultData(buf), fs.OK
|
|
|
|
}
|
2020-06-03 09:03:13 +00:00
|
|
|
|
|
|
|
func (tr *File) Release(ctx context.Context, f fs.FileHandle) syscall.Errno {
|
|
|
|
log.Println("closing file...")
|
|
|
|
if tr.r != nil {
|
|
|
|
closer, ok := tr.r.(io.Closer)
|
|
|
|
if ok {
|
|
|
|
if err := closer.Close(); err != nil {
|
|
|
|
log.Println("error closing file", err)
|
|
|
|
return syscall.EIO
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Println("file is not implementing close method")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return fs.OK
|
|
|
|
}
|