/* */ #include "IteratableChunkChecksumValidator.h" #include #include #include "util.h" #include "message.h" #include "DiskAdaptor.h" #include "FileEntry.h" #include "RecoverableException.h" #include "DownloadContext.h" #include "PieceStorage.h" #include "BitfieldMan.h" #include "LogFactory.h" #include "Logger.h" #include "MessageDigest.h" #include "fmt.h" #include "DlAbortEx.h" namespace aria2 { IteratableChunkChecksumValidator::IteratableChunkChecksumValidator (const SharedHandle& dctx, const PieceStorageHandle& pieceStorage) : dctx_(dctx), pieceStorage_(pieceStorage), bitfield_(new BitfieldMan(dctx_->getPieceLength(), dctx_->getTotalLength())), currentIndex_(0) {} IteratableChunkChecksumValidator::~IteratableChunkChecksumValidator() {} void IteratableChunkChecksumValidator::validateChunk() { if(!finished()) { std::string actualChecksum; try { actualChecksum = calculateActualChecksum(); if(actualChecksum == dctx_->getPieceHashes()[currentIndex_]) { bitfield_->setBit(currentIndex_); } else { A2_LOG_INFO (fmt(EX_INVALID_CHUNK_CHECKSUM, static_cast(currentIndex_), util::itos(getCurrentOffset(), true).c_str(), util::toHex(dctx_->getPieceHashes()[currentIndex_]).c_str(), util::toHex(actualChecksum).c_str())); bitfield_->unsetBit(currentIndex_); } } catch(RecoverableException& ex) { A2_LOG_DEBUG_EX(fmt("Caught exception while validating piece index=%lu." " Some part of file may be missing." " Continue operation.", static_cast(currentIndex_)), ex); bitfield_->unsetBit(currentIndex_); } ++currentIndex_; if(finished()) { pieceStorage_->setBitfield(bitfield_->getBitfield(), bitfield_->getBitfieldLength()); } } } std::string IteratableChunkChecksumValidator::calculateActualChecksum() { off_t offset = getCurrentOffset(); size_t length; // When validating last piece if(currentIndex_+1 == dctx_->getNumPieces()) { length = dctx_->getTotalLength()-offset; } else { length = dctx_->getPieceLength(); } return digest(offset, length); } void IteratableChunkChecksumValidator::init() { ctx_ = MessageDigest::create(dctx_->getPieceHashType()); bitfield_->clearAllBit(); currentIndex_ = 0; } std::string IteratableChunkChecksumValidator::digest(off_t offset, size_t length) { unsigned char buf[4096]; ctx_->reset(); off_t max = offset+length; while(offset < max) { size_t r = pieceStorage_->getDiskAdaptor()->readData (buf, std::min(static_cast(sizeof(buf)), max-offset), offset); if(r == 0) { throw DL_ABORT_EX (fmt(EX_FILE_READ, dctx_->getBasePath().c_str(), "data is too short")); } ctx_->update(buf, r); offset += r; } return ctx_->digest(); } bool IteratableChunkChecksumValidator::finished() const { if(currentIndex_ >= dctx_->getNumPieces()) { return true; } else { return false; } } off_t IteratableChunkChecksumValidator::getCurrentOffset() const { return (off_t)currentIndex_*dctx_->getPieceLength(); } uint64_t IteratableChunkChecksumValidator::getTotalLength() const { return dctx_->getTotalLength(); } } // namespace aria2