package torrentfs import ( "context" "io" "github.com/anacrolix/fuse" "github.com/anacrolix/fuse/fs" "github.com/anacrolix/missinggo/v2" "github.com/anacrolix/torrent" ) type fileHandle struct { fn fileNode r torrent.Reader } var _ interface { fs.HandleReader fs.HandleReleaser } = fileHandle{} func (me fileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { torrentfsReadRequests.Add(1) if req.Dir { panic("read on directory") } r := me.r pos, err := r.Seek(req.Offset, io.SeekStart) if err != nil { panic(err) } if pos != req.Offset { panic("seek failed") } resp.Data = resp.Data[:req.Size] readDone := make(chan struct{}) ctx, cancel := context.WithCancel(ctx) var readErr error go func() { defer close(readDone) me.fn.FS.mu.Lock() me.fn.FS.blockedReads++ me.fn.FS.event.Broadcast() me.fn.FS.mu.Unlock() var n int r := missinggo.ContextedReader{r, ctx} // log.Printf("reading %v bytes at %v", len(resp.Data), req.Offset) if true { // A user reported on that on freebsd 12.2, the system requires that reads are // completely filled. Their system only asks for 64KiB at a time. I've seen systems that // can demand up to 16MiB at a time, so this gets tricky. For now, I'll restore the old // behaviour from before 2a7352a, which nobody reported problems with. n, readErr = io.ReadFull(r, resp.Data) } else { n, readErr = r.Read(resp.Data) if readErr == io.EOF { readErr = nil } } resp.Data = resp.Data[:n] }() defer func() { <-readDone me.fn.FS.mu.Lock() me.fn.FS.blockedReads-- me.fn.FS.event.Broadcast() me.fn.FS.mu.Unlock() }() defer cancel() select { case <-readDone: return readErr case <-me.fn.FS.destroyed: return fuse.EIO case <-ctx.Done(): return fuse.EINTR } } func (me fileHandle) Release(context.Context, *fuse.ReleaseRequest) error { return me.r.Close() }