]> Sergey Matveev's repositories - btrtrc.git/blob - data/blob/blob.go
Add piece blob torrent.Data storage, and move testutil to internal/, add basic transf...
[btrtrc.git] / data / blob / blob.go
1 package blob
2
3 import (
4         "encoding/hex"
5         "errors"
6         "io"
7         "os"
8
9         "github.com/anacrolix/libtorgo/metainfo"
10 )
11
12 type data struct {
13         info    *metainfo.Info
14         baseDir string
15 }
16
17 func TorrentData(info *metainfo.Info, baseDir string) *data {
18         return &data{info, baseDir}
19 }
20
21 func (me *data) pieceHashHex(i int) string {
22         return hex.EncodeToString(me.info.Pieces[i*20 : (i+1)*20])
23 }
24
25 func (me *data) Close() {}
26
27 func (me *data) ReadAt(p []byte, off int64) (n int, err error) {
28         hash := me.pieceHashHex(int(off / me.info.PieceLength))
29         f, err := os.Open(me.baseDir + "/complete/" + hash)
30         if os.IsNotExist(err) {
31                 f, err = os.Open(me.baseDir + "/incomplete/" + hash)
32                 if os.IsNotExist(err) {
33                         err = io.EOF
34                         return
35                 }
36                 if err != nil {
37                         return
38                 }
39         } else if err != nil {
40                 return
41         }
42         defer f.Close()
43         off %= me.info.PieceLength
44         return f.ReadAt(p, off)
45 }
46
47 func (me *data) openComplete(piece int) (f *os.File, err error) {
48         return os.OpenFile(me.baseDir+"/complete/"+me.pieceHashHex(piece), os.O_RDWR, 0660)
49 }
50
51 func (me *data) WriteAt(p []byte, off int64) (n int, err error) {
52         i := int(off / me.info.PieceLength)
53         off %= me.info.PieceLength
54         for len(p) != 0 {
55                 _, err = os.Stat(me.baseDir + "/complete/" + me.pieceHashHex(i))
56                 if err == nil {
57                         err = errors.New("can't write to completed piece")
58                         return
59                 }
60                 os.MkdirAll(me.baseDir+"/incomplete", 0750)
61                 var f *os.File
62                 f, err = os.OpenFile(me.baseDir+"/incomplete/"+me.pieceHashHex(i), os.O_WRONLY|os.O_CREATE, 0640)
63                 if err != nil {
64                         return
65                 }
66                 p1 := p
67                 maxN := me.info.Piece(i).Length() - off
68                 if int64(len(p1)) > maxN {
69                         p1 = p1[:maxN]
70                 }
71                 var n1 int
72                 n1, err = f.WriteAt(p1, off)
73                 f.Close()
74                 n += n1
75                 if err != nil {
76                         return
77                 }
78                 p = p[n1:]
79                 off = 0
80         }
81         return
82 }
83
84 func (me *data) pieceReader(piece int, off int64) (ret io.ReadCloser, err error) {
85         hash := me.pieceHashHex(piece)
86         f, err := os.Open(me.baseDir + "/complete/" + hash)
87         if os.IsNotExist(err) {
88                 f, err = os.Open(me.baseDir + "/incomplete/" + hash)
89                 if os.IsNotExist(err) {
90                         err = io.EOF
91                         return
92                 }
93                 if err != nil {
94                         return
95                 }
96         } else if err != nil {
97                 return
98         }
99         return struct {
100                 io.Reader
101                 io.Closer
102         }{io.NewSectionReader(f, off, me.info.Piece(piece).Length()-off), f}, nil
103 }
104
105 func (me *data) WriteSectionTo(w io.Writer, off, n int64) (written int64, err error) {
106         i := int(off / me.info.PieceLength)
107         off %= me.info.PieceLength
108         for n != 0 {
109                 var pr io.ReadCloser
110                 pr, err = me.pieceReader(i, off)
111                 if err != nil {
112                         if err == io.EOF {
113                                 err = nil
114                         }
115                         return
116                 }
117                 var n1 int64
118                 n1, err = io.CopyN(w, pr, n)
119                 written += n1
120                 n -= n1
121                 if err != nil {
122                         return
123                 }
124                 off = 0
125         }
126         return
127 }