github.com/anacrolix/torrent@v1.61.0/fs/file_handle.go (about) 1 //go:build !windows 2 3 package torrentfs 4 5 import ( 6 "context" 7 "io" 8 9 "github.com/anacrolix/fuse" 10 "github.com/anacrolix/fuse/fs" 11 "github.com/anacrolix/missinggo/v2" 12 13 "github.com/anacrolix/torrent" 14 ) 15 16 type fileHandle struct { 17 fn fileNode 18 tf *torrent.File 19 } 20 21 var _ interface { 22 fs.HandleReader 23 fs.HandleReleaser 24 } = fileHandle{} 25 26 func (me fileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { 27 torrentfsReadRequests.Add(1) 28 if req.Dir { 29 panic("read on directory") 30 } 31 r := me.tf.NewReader() 32 defer r.Close() 33 pos, err := r.Seek(req.Offset, io.SeekStart) 34 if err != nil { 35 panic(err) 36 } 37 if pos != req.Offset { 38 panic("seek failed") 39 } 40 resp.Data = resp.Data[:req.Size] 41 readDone := make(chan struct{}) 42 ctx, cancel := context.WithCancel(ctx) 43 var readErr error 44 go func() { 45 defer close(readDone) 46 me.fn.FS.mu.Lock() 47 me.fn.FS.blockedReads++ 48 me.fn.FS.event.Broadcast() 49 me.fn.FS.mu.Unlock() 50 var n int 51 r := missinggo.ContextedReader{r, ctx} 52 // log.Printf("reading %v bytes at %v", len(resp.Data), req.Offset) 53 if true { 54 // A user reported on that on freebsd 12.2, the system requires that reads are 55 // completely filled. Their system only asks for 64KiB at a time. I've seen systems that 56 // can demand up to 16MiB at a time, so this gets tricky. For now, I'll restore the old 57 // behaviour from before 2a7352a, which nobody reported problems with. 58 n, readErr = io.ReadFull(r, resp.Data) 59 if readErr == io.ErrUnexpectedEOF { 60 readErr = nil 61 } 62 } else { 63 n, readErr = r.Read(resp.Data) 64 if readErr == io.EOF { 65 readErr = nil 66 } 67 } 68 resp.Data = resp.Data[:n] 69 }() 70 defer func() { 71 <-readDone 72 me.fn.FS.mu.Lock() 73 me.fn.FS.blockedReads-- 74 me.fn.FS.event.Broadcast() 75 me.fn.FS.mu.Unlock() 76 }() 77 defer cancel() 78 79 select { 80 case <-readDone: 81 return readErr 82 case <-me.fn.FS.destroyed: 83 return fuse.EIO 84 case <-ctx.Done(): 85 return fuse.EINTR 86 } 87 } 88 89 func (me fileHandle) Release(context.Context, *fuse.ReleaseRequest) error { 90 return nil 91 }