]> Sergey Matveev's repositories - btrtrc.git/blob - file.go
Fix file piece index offset calculations
[btrtrc.git] / file.go
1 package torrent
2
3 import (
4         "strings"
5
6         "github.com/anacrolix/torrent/metainfo"
7         pwp "github.com/anacrolix/torrent/peer_protocol"
8 )
9
10 // Provides access to regions of torrent data that correspond to its files.
11 type File struct {
12         t      *Torrent
13         path   string
14         offset int64
15         length int64
16         fi     metainfo.FileInfo
17         prio   piecePriority
18 }
19
20 func (f *File) Torrent() *Torrent {
21         return f.t
22 }
23
24 // Data for this file begins this many bytes into the Torrent.
25 func (f *File) Offset() int64 {
26         return f.offset
27 }
28
29 // The FileInfo from the metainfo.Info to which this file corresponds.
30 func (f File) FileInfo() metainfo.FileInfo {
31         return f.fi
32 }
33
34 // The file's path components joined by '/'.
35 func (f File) Path() string {
36         return f.path
37 }
38
39 // The file's length in bytes.
40 func (f *File) Length() int64 {
41         return f.length
42 }
43
44 // The relative file path for a multi-file torrent, and the torrent name for a
45 // single-file torrent.
46 func (f *File) DisplayPath() string {
47         fip := f.FileInfo().Path
48         if len(fip) == 0 {
49                 return f.t.info.Name
50         }
51         return strings.Join(fip, "/")
52
53 }
54
55 // The download status of a piece that comprises part of a File.
56 type FilePieceState struct {
57         Bytes int64 // Bytes within the piece that are part of this File.
58         PieceState
59 }
60
61 // Returns the state of pieces in this file.
62 func (f *File) State() (ret []FilePieceState) {
63         f.t.cl.mu.RLock()
64         defer f.t.cl.mu.RUnlock()
65         pieceSize := int64(f.t.usualPieceSize())
66         off := f.offset % pieceSize
67         remaining := f.length
68         for i := int(f.offset / pieceSize); ; i++ {
69                 if remaining == 0 {
70                         break
71                 }
72                 len1 := pieceSize - off
73                 if len1 > remaining {
74                         len1 = remaining
75                 }
76                 ps := f.t.pieceState(i)
77                 ret = append(ret, FilePieceState{len1, ps})
78                 off = 0
79                 remaining -= len1
80         }
81         return
82 }
83
84 // Requests that all pieces containing data in the file be downloaded.
85 func (f *File) Download() {
86         f.SetPriority(PiecePriorityNormal)
87 }
88
89 func byteRegionExclusivePieces(off, size, pieceSize int64) (begin, end int) {
90         begin = int((off + pieceSize - 1) / pieceSize)
91         end = int((off + size) / pieceSize)
92         return
93 }
94
95 func (f *File) exclusivePieces() (begin, end int) {
96         return byteRegionExclusivePieces(f.offset, f.length, int64(f.t.usualPieceSize()))
97 }
98
99 // Deprecated: Use File.SetPriority.
100 func (f *File) Cancel() {
101         f.SetPriority(PiecePriorityNone)
102 }
103
104 func (f *File) NewReader() Reader {
105         tr := reader{
106                 mu:        &f.t.cl.mu,
107                 t:         f.t,
108                 readahead: 5 * 1024 * 1024,
109                 offset:    f.Offset(),
110                 length:    f.Length(),
111         }
112         f.t.addReader(&tr)
113         return &tr
114 }
115
116 // Sets the minimum priority for pieces in the File.
117 func (f *File) SetPriority(prio piecePriority) {
118         f.t.cl.mu.Lock()
119         defer f.t.cl.mu.Unlock()
120         if prio == f.prio {
121                 return
122         }
123         f.prio = prio
124         f.t.updatePiecePriorities(f.firstPieceIndex().Int(), f.endPieceIndex().Int())
125 }
126
127 // Returns the priority per File.SetPriority.
128 func (f *File) Priority() piecePriority {
129         f.t.cl.mu.Lock()
130         defer f.t.cl.mu.Unlock()
131         return f.prio
132 }
133
134 func (f *File) firstPieceIndex() pwp.Integer {
135         if f.t.usualPieceSize() == 0 {
136                 return 0
137         }
138         return pwp.Integer(f.offset / int64(f.t.usualPieceSize()))
139 }
140
141 func (f *File) endPieceIndex() pwp.Integer {
142         if f.t.usualPieceSize() == 0 {
143                 return 0
144         }
145         return pwp.Integer((f.offset+f.length-1)/int64(f.t.usualPieceSize())) + 1
146 }