-
-
Notifications
You must be signed in to change notification settings - Fork 615
/
file_handle.go
84 lines (77 loc) · 1.86 KB
/
file_handle.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package torrentfs
import (
"context"
"io"
"bazil.org/fuse"
"bazil.org/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()
}