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