]> Sergey Matveev's repositories - btrtrc.git/blob - storage/piece_file.go
Rework storage interfaces to make them simpler to implement
[btrtrc.git] / storage / piece_file.go
1 package storage
2
3 import (
4         "io"
5         "os"
6         "path"
7
8         "github.com/anacrolix/missinggo"
9
10         "github.com/anacrolix/torrent/metainfo"
11 )
12
13 type pieceFileStorage struct {
14         fs missinggo.FileStore
15 }
16
17 func NewFileStorePieces(fs missinggo.FileStore) ClientImpl {
18         return &pieceFileStorage{
19                 fs: fs,
20         }
21 }
22
23 type pieceFileTorrentStorage struct {
24         s *pieceFileStorage
25 }
26
27 func (s *pieceFileStorage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (TorrentImpl, error) {
28         return &pieceFileTorrentStorage{s}, nil
29 }
30
31 func (s *pieceFileTorrentStorage) Close() error {
32         return nil
33 }
34
35 func (s *pieceFileTorrentStorage) Piece(p metainfo.Piece) PieceImpl {
36         return pieceFileTorrentStoragePiece{s, p, s.s.fs}
37 }
38
39 type pieceFileTorrentStoragePiece struct {
40         ts *pieceFileTorrentStorage
41         p  metainfo.Piece
42         fs missinggo.FileStore
43 }
44
45 func (s pieceFileTorrentStoragePiece) completedPath() string {
46         return path.Join("completed", s.p.Hash().HexString())
47 }
48
49 func (s pieceFileTorrentStoragePiece) incompletePath() string {
50         return path.Join("incomplete", s.p.Hash().HexString())
51 }
52
53 func (s pieceFileTorrentStoragePiece) GetIsComplete() bool {
54         fi, err := s.fs.Stat(s.completedPath())
55         return err == nil && fi.Size() == s.p.Length()
56 }
57
58 func (s pieceFileTorrentStoragePiece) MarkComplete() error {
59         return s.fs.Rename(s.incompletePath(), s.completedPath())
60 }
61
62 func (s pieceFileTorrentStoragePiece) MarkNotComplete() error {
63         return s.fs.Remove(s.completedPath())
64 }
65
66 func (s pieceFileTorrentStoragePiece) openFile() (f missinggo.File, err error) {
67         f, err = s.fs.OpenFile(s.completedPath(), os.O_RDONLY)
68         if err == nil {
69                 var fi os.FileInfo
70                 fi, err = f.Stat()
71                 if err == nil && fi.Size() == s.p.Length() {
72                         return
73                 }
74                 f.Close()
75         } else if !os.IsNotExist(err) {
76                 return
77         }
78         f, err = s.fs.OpenFile(s.incompletePath(), os.O_RDONLY)
79         if os.IsNotExist(err) {
80                 err = io.ErrUnexpectedEOF
81         }
82         return
83 }
84
85 func (s pieceFileTorrentStoragePiece) ReadAt(b []byte, off int64) (n int, err error) {
86         f, err := s.openFile()
87         if err != nil {
88                 return
89         }
90         defer f.Close()
91         return f.ReadAt(b, off)
92 }
93
94 func (s pieceFileTorrentStoragePiece) WriteAt(b []byte, off int64) (n int, err error) {
95         f, err := s.fs.OpenFile(s.incompletePath(), os.O_WRONLY|os.O_CREATE)
96         if err != nil {
97                 return
98         }
99         defer f.Close()
100         return f.WriteAt(b, off)
101 }