func (me *store) PieceCompleted(p metainfo.Piece) (err error) { err = me.makeSpace(p.Length()) if err != nil { return } var ( incompletePiecePath = me.path(p, false) completedPiecePath = me.path(p, true) ) fSrc, err := os.Open(incompletePiecePath) if err != nil { return } defer fSrc.Close() os.MkdirAll(filepath.Dir(completedPiecePath), dirPerm) fDst, err := os.OpenFile(completedPiecePath, os.O_EXCL|os.O_CREATE|os.O_WRONLY, filePerm) if err != nil { return } defer fDst.Close() hasher := sha1.New() r := io.TeeReader(io.LimitReader(fSrc, p.Length()), hasher) _, err = io.Copy(fDst, r) if err != nil { return } if !bytes.Equal(hasher.Sum(nil), p.Hash()) { err = errors.New("piece incomplete") os.Remove(completedPiecePath) return } os.Remove(incompletePiecePath) me.completed[sliceToPieceHashArray(p.Hash())] = struct{}{} return }
func (me *store) pieceComplete(p metainfo.Piece) bool { if me.completionKnown(p) { return me.isComplete(p) } // Prevent a errors from stalling the caller. if !me.lastError.IsZero() && time.Since(me.lastError) < time.Second { return false } length, err := me.db.GetLength(me.completedPiecePath(p)) if err == dataBackend.ErrNotFound { me.setCompletion(p, false) return false } if err != nil { me.lastError = time.Now() log.Printf("%+v", err) return false } complete := length == p.Length() if !complete { log.Printf("completed piece %x has wrong length: %d", p.Hash(), length) } me.setCompletion(p, complete) return complete }
func (me *store) path(p metainfo.Piece, completed bool) string { return filepath.Join(me.baseDir, func() string { if completed { return "complete" } else { return "incomplete" } }(), fmt.Sprintf("%x", p.Hash())) }
func (me *store) PieceCompleted(p metainfo.Piece) (err error) { hash, err := me.hashCopyFile(me.incompletePiecePath(p), me.completedPiecePath(p), p.Length()) if err == nil && !bytes.Equal(hash, p.Hash()) { err = errors.New("piece incomplete") } if err != nil { me.deleteCompleted(p) return } me.removePath(me.incompletePiecePath(p)) me.setCompletion(p, true) return }
func (s *piecePerResource) Piece(p metainfo.Piece) Piece { completed, err := s.p.NewInstance(path.Join("completed", p.Hash().HexString())) if err != nil { panic(err) } incomplete, err := s.p.NewInstance(path.Join("incomplete", p.Hash().HexString())) if err != nil { panic(err) } return piecePerResourcePiece{ p: p, c: completed, i: incomplete, } }
// Returns the file for the given piece, if it exists. It could be completed, // or incomplete. func (me *store) pieceRead(p metainfo.Piece) (f *os.File) { f, err := os.Open(me.path(p, true)) if err == nil { return } if !os.IsNotExist(err) { panic(err) } // Mark the file not completed, in case we thought it was. TODO: Trigger // an asynchronous initCompleted to reinitialize the entire completed map // as there are likely other files missing. me.mu.Lock() delete(me.completed, sliceToPieceHashArray(p.Hash())) me.mu.Unlock() f, err = os.Open(me.path(p, false)) if err == nil { return } if !os.IsNotExist(err) { panic(err) } return }
func pieceHashArray(p metainfo.Piece) [20]byte { return sliceToPieceHashArray(p.Hash()) }
func (me *store) incompletePiecePath(p metainfo.Piece) string { return path.Join( "incomplete", strconv.FormatInt(int64(os.Getpid()), 10), hex.EncodeToString(p.Hash())) }
func (me *store) completedPiecePath(p metainfo.Piece) string { return path.Join("completed", hex.EncodeToString(p.Hash())) }
func (me *store) pieceComplete(p metainfo.Piece) bool { me.mu.Lock() defer me.mu.Unlock() _, ok := me.completed[sliceToPieceHashArray(p.Hash())] return ok }
func (me *store) pieceComplete(p metainfo.Piece) bool { _, ok := me.completed[sliceToPieceHashArray(p.Hash())] return ok }