file.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package torrent
  2. import (
  3. "crypto/sha256"
  4. "github.com/RoaringBitmap/roaring"
  5. g "github.com/anacrolix/generics"
  6. "github.com/anacrolix/missinggo/v2/bitmap"
  7. "github.com/anacrolix/torrent/metainfo"
  8. )
  9. // Provides access to regions of torrent data that correspond to its files.
  10. type File struct {
  11. t *Torrent
  12. path string
  13. offset int64
  14. length int64
  15. fi metainfo.FileInfo
  16. displayPath string
  17. prio PiecePriority
  18. piecesRoot g.Option[[sha256.Size]byte]
  19. }
  20. func (f *File) String() string {
  21. return f.Path()
  22. }
  23. func (f *File) Torrent() *Torrent {
  24. return f.t
  25. }
  26. // Data for this file begins this many bytes into the Torrent.
  27. func (f *File) Offset() int64 {
  28. return f.offset
  29. }
  30. // The FileInfo from the metainfo.Info to which this file corresponds.
  31. func (f *File) FileInfo() metainfo.FileInfo {
  32. return f.fi
  33. }
  34. // The file's path components joined by '/'.
  35. func (f *File) Path() string {
  36. return f.path
  37. }
  38. // The file's length in bytes.
  39. func (f *File) Length() int64 {
  40. return f.length
  41. }
  42. // Number of bytes of the entire file we have completed. This is the sum of
  43. // completed pieces, and dirtied chunks of incomplete pieces.
  44. func (f *File) BytesCompleted() (n int64) {
  45. f.t.cl.rLock()
  46. n = f.bytesCompletedLocked()
  47. f.t.cl.rUnlock()
  48. return
  49. }
  50. func (f *File) bytesCompletedLocked() int64 {
  51. return f.length - f.bytesLeft()
  52. }
  53. func fileBytesLeft(
  54. torrentUsualPieceSize int64,
  55. fileFirstPieceIndex int,
  56. fileEndPieceIndex int,
  57. fileTorrentOffset int64,
  58. fileLength int64,
  59. torrentCompletedPieces *roaring.Bitmap,
  60. pieceSizeCompletedFn func(pieceIndex int) int64,
  61. ) (left int64) {
  62. if fileLength == 0 {
  63. return
  64. }
  65. noCompletedMiddlePieces := roaring.New()
  66. noCompletedMiddlePieces.AddRange(bitmap.BitRange(fileFirstPieceIndex), bitmap.BitRange(fileEndPieceIndex))
  67. noCompletedMiddlePieces.AndNot(torrentCompletedPieces)
  68. noCompletedMiddlePieces.Iterate(func(pieceIndex uint32) bool {
  69. i := int(pieceIndex)
  70. pieceSizeCompleted := pieceSizeCompletedFn(i)
  71. if i == fileFirstPieceIndex {
  72. beginOffset := fileTorrentOffset % torrentUsualPieceSize
  73. beginSize := torrentUsualPieceSize - beginOffset
  74. beginDownLoaded := pieceSizeCompleted - beginOffset
  75. if beginDownLoaded < 0 {
  76. beginDownLoaded = 0
  77. }
  78. left += beginSize - beginDownLoaded
  79. } else if i == fileEndPieceIndex-1 {
  80. endSize := (fileTorrentOffset + fileLength) % torrentUsualPieceSize
  81. if endSize == 0 {
  82. endSize = torrentUsualPieceSize
  83. }
  84. endDownloaded := pieceSizeCompleted
  85. if endDownloaded > endSize {
  86. endDownloaded = endSize
  87. }
  88. left += endSize - endDownloaded
  89. } else {
  90. left += torrentUsualPieceSize - pieceSizeCompleted
  91. }
  92. return true
  93. })
  94. if left > fileLength {
  95. left = fileLength
  96. }
  97. //
  98. //numPiecesSpanned := f.EndPieceIndex() - f.BeginPieceIndex()
  99. //completedMiddlePieces := f.t._completedPieces.Clone()
  100. //completedMiddlePieces.RemoveRange(0, bitmap.BitRange(f.BeginPieceIndex()+1))
  101. //completedMiddlePieces.RemoveRange(bitmap.BitRange(f.EndPieceIndex()-1), bitmap.ToEnd)
  102. //left += int64(numPiecesSpanned-2-pieceIndex(completedMiddlePieces.GetCardinality())) * torrentUsualPieceSize
  103. return
  104. }
  105. func (f *File) bytesLeft() (left int64) {
  106. return fileBytesLeft(int64(f.t.usualPieceSize()), f.BeginPieceIndex(), f.EndPieceIndex(), f.offset, f.length, &f.t._completedPieces, func(pieceIndex int) int64 {
  107. return int64(f.t.piece(pieceIndex).numDirtyBytes())
  108. })
  109. }
  110. // The relative file path for a multi-file torrent, and the torrent name for a
  111. // single-file torrent. Dir separators are '/'.
  112. func (f *File) DisplayPath() string {
  113. return f.displayPath
  114. }
  115. // The download status of a piece that comprises part of a File.
  116. type FilePieceState struct {
  117. Bytes int64 // Bytes within the piece that are part of this File.
  118. PieceState
  119. }
  120. // Returns the state of pieces in this file.
  121. func (f *File) State() (ret []FilePieceState) {
  122. f.t.cl.rLock()
  123. defer f.t.cl.rUnlock()
  124. pieceSize := int64(f.t.usualPieceSize())
  125. off := f.offset % pieceSize
  126. remaining := f.length
  127. for i := pieceIndex(f.offset / pieceSize); ; i++ {
  128. if remaining == 0 {
  129. break
  130. }
  131. len1 := pieceSize - off
  132. if len1 > remaining {
  133. len1 = remaining
  134. }
  135. ps := f.t.pieceState(i)
  136. ret = append(ret, FilePieceState{len1, ps})
  137. off = 0
  138. remaining -= len1
  139. }
  140. return
  141. }
  142. // Requests that all pieces containing data in the file be downloaded.
  143. func (f *File) Download() {
  144. f.SetPriority(PiecePriorityNormal)
  145. }
  146. func byteRegionExclusivePieces(off, size, pieceSize int64) (begin, end int) {
  147. begin = int((off + pieceSize - 1) / pieceSize)
  148. end = int((off + size) / pieceSize)
  149. return
  150. }
  151. // Deprecated: Use File.SetPriority.
  152. func (f *File) Cancel() {
  153. f.SetPriority(PiecePriorityNone)
  154. }
  155. func (f *File) NewReader() Reader {
  156. return f.t.newReader(f.Offset(), f.Length())
  157. }
  158. // Sets the minimum priority for pieces in the File.
  159. func (f *File) SetPriority(prio PiecePriority) {
  160. f.t.cl.lock()
  161. if prio != f.prio {
  162. f.prio = prio
  163. f.t.updatePiecePriorities(f.BeginPieceIndex(), f.EndPieceIndex(), "File.SetPriority")
  164. }
  165. f.t.cl.unlock()
  166. }
  167. // Returns the priority per File.SetPriority.
  168. func (f *File) Priority() (prio PiecePriority) {
  169. f.t.cl.rLock()
  170. prio = f.prio
  171. f.t.cl.rUnlock()
  172. return
  173. }
  174. // Returns the index of the first piece containing data for the file.
  175. func (f *File) BeginPieceIndex() int {
  176. if f.t.usualPieceSize() == 0 {
  177. return 0
  178. }
  179. return pieceIndex(f.offset / int64(f.t.usualPieceSize()))
  180. }
  181. // Returns the index of the piece after the last one containing data for the file.
  182. func (f *File) EndPieceIndex() int {
  183. if f.t.usualPieceSize() == 0 {
  184. return 0
  185. }
  186. return pieceIndex((f.offset + f.length + int64(f.t.usualPieceSize()) - 1) / int64(f.t.usualPieceSize()))
  187. }
  188. func (f *File) numPieces() int {
  189. return f.EndPieceIndex() - f.BeginPieceIndex()
  190. }