]> Sergey Matveev's repositories - btrtrc.git/blob - fs/file_handle.go
Switch to goimports import sorting
[btrtrc.git] / fs / file_handle.go
1 package torrentfs
2
3 import (
4         "context"
5         "io"
6
7         "bazil.org/fuse"
8         "bazil.org/fuse/fs"
9         "github.com/anacrolix/missinggo"
10         "github.com/anacrolix/torrent"
11 )
12
13 type fileHandle struct {
14         fn fileNode
15         r  torrent.Reader
16 }
17
18 var _ interface {
19         fs.HandleReader
20         fs.HandleReleaser
21 } = fileHandle{}
22
23 func (me fileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
24         torrentfsReadRequests.Add(1)
25         if req.Dir {
26                 panic("read on directory")
27         }
28         pos, err := me.r.Seek(req.Offset, io.SeekStart)
29         if err != nil {
30                 panic(err)
31         }
32         if pos != req.Offset {
33                 panic("seek failed")
34         }
35         resp.Data = resp.Data[:req.Size]
36         readDone := make(chan struct{})
37         ctx, cancel := context.WithCancel(ctx)
38         var readErr error
39         go func() {
40                 defer close(readDone)
41                 me.fn.FS.mu.Lock()
42                 me.fn.FS.blockedReads++
43                 me.fn.FS.event.Broadcast()
44                 me.fn.FS.mu.Unlock()
45                 var n int
46                 r := missinggo.ContextedReader{me.r, ctx}
47                 n, readErr = r.Read(resp.Data)
48                 if readErr == io.EOF {
49                         readErr = nil
50                 }
51                 resp.Data = resp.Data[:n]
52         }()
53         defer func() {
54                 <-readDone
55                 me.fn.FS.mu.Lock()
56                 me.fn.FS.blockedReads--
57                 me.fn.FS.event.Broadcast()
58                 me.fn.FS.mu.Unlock()
59         }()
60         defer cancel()
61
62         select {
63         case <-readDone:
64                 return readErr
65         case <-me.fn.FS.destroyed:
66                 return fuse.EIO
67         case <-ctx.Done():
68                 return fuse.EINTR
69         }
70 }
71
72 func (me fileHandle) Release(context.Context, *fuse.ReleaseRequest) error {
73         return me.r.Close()
74 }