diff options
Diffstat (limited to 'src/DefaultBtProgressInfoFile.cc')
| -rw-r--r-- | src/DefaultBtProgressInfoFile.cc | 354 |
1 files changed, 188 insertions, 166 deletions
diff --git a/src/DefaultBtProgressInfoFile.cc b/src/DefaultBtProgressInfoFile.cc index 05357da2..2787b664 100644 --- a/src/DefaultBtProgressInfoFile.cc +++ b/src/DefaultBtProgressInfoFile.cc @@ -55,17 +55,18 @@ #include "array_fun.h" #include "DownloadContext.h" #include "BufferedFile.h" +#include "SHA1IOFile.h" #ifdef ENABLE_BITTORRENT -# include "PeerStorage.h" -# include "BtRuntime.h" -# include "bittorrent_helper.h" +#include "PeerStorage.h" +#include "BtRuntime.h" +#include "bittorrent_helper.h" #endif // ENABLE_BITTORRENT namespace aria2 { namespace { -std::string createFilename -(const std::shared_ptr<DownloadContext>& dctx, const std::string& suffix) +std::string createFilename(const std::shared_ptr<DownloadContext>& dctx, + const std::string& suffix) { std::string t = dctx->getBasePath(); t += suffix; @@ -73,15 +74,15 @@ std::string createFilename } } // namespace -DefaultBtProgressInfoFile::DefaultBtProgressInfoFile -(const std::shared_ptr<DownloadContext>& dctx, - const std::shared_ptr<PieceStorage>& pieceStorage, - const Option* option) - : dctx_(dctx), - pieceStorage_(pieceStorage), - option_(option), - filename_(createFilename(dctx_, getSuffix())) -{} +DefaultBtProgressInfoFile::DefaultBtProgressInfoFile( + const std::shared_ptr<DownloadContext>& dctx, + const std::shared_ptr<PieceStorage>& pieceStorage, const Option* option) + : dctx_(dctx), + pieceStorage_(pieceStorage), + option_(option), + filename_(createFilename(dctx_, getSuffix())) +{ +} DefaultBtProgressInfoFile::~DefaultBtProgressInfoFile() {} @@ -94,113 +95,135 @@ bool DefaultBtProgressInfoFile::isTorrentDownload() { #ifdef ENABLE_BITTORRENT return btRuntime_.get(); -#else // !ENABLE_BITTORRENT +#else // !ENABLE_BITTORRENT return false; #endif // !ENABLE_BITTORRENT } -#define WRITE_CHECK(fp, ptr, count) \ - if(fp.write((ptr), (count)) != (count)) { \ - throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_WRITE, filename_.c_str())); \ +#define WRITE_CHECK(fp, ptr, count) \ + if (fp.write((ptr), (count)) != (count)) { \ + throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_WRITE, filename_.c_str())); \ } // Since version 0001, Integers are saved in binary form, network byte order. -void DefaultBtProgressInfoFile::save() +void DefaultBtProgressInfoFile::save(IOFile& fp) { - A2_LOG_INFO(fmt(MSG_SAVING_SEGMENT_FILE, filename_.c_str())); - std::string filenameTemp = filename_; - filenameTemp += "__temp"; - { - BufferedFile fp(filenameTemp.c_str(), BufferedFile::WRITE); - if(!fp) { - throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_WRITE, filename_.c_str())); - } #ifdef ENABLE_BITTORRENT - bool torrentDownload = isTorrentDownload(); -#else // !ENABLE_BITTORRENT - bool torrentDownload = false; + bool torrentDownload = isTorrentDownload(); +#else // !ENABLE_BITTORRENT + bool torrentDownload = false; #endif // !ENABLE_BITTORRENT - // file version: 16 bits - // values: '1' - char version[] = { 0x00u, 0x01u }; - WRITE_CHECK(fp, version, sizeof(version)); - // extension: 32 bits - // If this is BitTorrent download, then 0x00000001 - // Otherwise, 0x00000000 - char extension[4]; - memset(extension, 0, sizeof(extension)); - if(torrentDownload) { - extension[3] = 1; - } - WRITE_CHECK(fp, extension, sizeof(extension)); - if(torrentDownload) { + // file version: 16 bits + // values: '1' + char version[] = {0x00u, 0x01u}; + WRITE_CHECK(fp, version, sizeof(version)); + // extension: 32 bits + // If this is BitTorrent download, then 0x00000001 + // Otherwise, 0x00000000 + char extension[4]; + memset(extension, 0, sizeof(extension)); + if (torrentDownload) { + extension[3] = 1; + } + WRITE_CHECK(fp, extension, sizeof(extension)); + if (torrentDownload) { #ifdef ENABLE_BITTORRENT - // infoHashLength: - // length: 32 bits - const unsigned char* infoHash = bittorrent::getInfoHash(dctx_); - uint32_t infoHashLengthNL = htonl(INFO_HASH_LENGTH); - WRITE_CHECK(fp, &infoHashLengthNL, sizeof(infoHashLengthNL)); - // infoHash: - WRITE_CHECK(fp, infoHash, INFO_HASH_LENGTH); + // infoHashLength: + // length: 32 bits + const unsigned char* infoHash = bittorrent::getInfoHash(dctx_); + uint32_t infoHashLengthNL = htonl(INFO_HASH_LENGTH); + WRITE_CHECK(fp, &infoHashLengthNL, sizeof(infoHashLengthNL)); + // infoHash: + WRITE_CHECK(fp, infoHash, INFO_HASH_LENGTH); #endif // ENABLE_BITTORRENT - } else { - // infoHashLength: - // length: 32 bits - uint32_t infoHashLength = 0; - WRITE_CHECK(fp, &infoHashLength, sizeof(infoHashLength)); - } - // pieceLength: 32 bits - uint32_t pieceLengthNL = htonl(dctx_->getPieceLength()); - WRITE_CHECK(fp, &pieceLengthNL, sizeof(pieceLengthNL)); - // totalLength: 64 bits - uint64_t totalLengthNL = hton64(dctx_->getTotalLength()); - WRITE_CHECK(fp, &totalLengthNL, sizeof(totalLengthNL)); - // uploadLength: 64 bits - uint64_t uploadLengthNL = 0; + } + else { + // infoHashLength: + // length: 32 bits + uint32_t infoHashLength = 0; + WRITE_CHECK(fp, &infoHashLength, sizeof(infoHashLength)); + } + // pieceLength: 32 bits + uint32_t pieceLengthNL = htonl(dctx_->getPieceLength()); + WRITE_CHECK(fp, &pieceLengthNL, sizeof(pieceLengthNL)); + // totalLength: 64 bits + uint64_t totalLengthNL = hton64(dctx_->getTotalLength()); + WRITE_CHECK(fp, &totalLengthNL, sizeof(totalLengthNL)); + // uploadLength: 64 bits + uint64_t uploadLengthNL = 0; #ifdef ENABLE_BITTORRENT - if(torrentDownload) { - uploadLengthNL = hton64(btRuntime_->getUploadLengthAtStartup()+ - dctx_->getNetStat().getSessionUploadLength()); - } + if (torrentDownload) { + uploadLengthNL = hton64(btRuntime_->getUploadLengthAtStartup() + + dctx_->getNetStat().getSessionUploadLength()); + } #endif // ENABLE_BITTORRENT - WRITE_CHECK(fp, &uploadLengthNL, sizeof(uploadLengthNL)); - // bitfieldLength: 32 bits - uint32_t bitfieldLengthNL = htonl(pieceStorage_->getBitfieldLength()); + WRITE_CHECK(fp, &uploadLengthNL, sizeof(uploadLengthNL)); + // bitfieldLength: 32 bits + uint32_t bitfieldLengthNL = htonl(pieceStorage_->getBitfieldLength()); + WRITE_CHECK(fp, &bitfieldLengthNL, sizeof(bitfieldLengthNL)); + // bitfield + WRITE_CHECK(fp, pieceStorage_->getBitfield(), + pieceStorage_->getBitfieldLength()); + // the number of in-flight piece: 32 bits + // TODO implement this + uint32_t numInFlightPieceNL = htonl(pieceStorage_->countInFlightPiece()); + WRITE_CHECK(fp, &numInFlightPieceNL, sizeof(numInFlightPieceNL)); + std::vector<std::shared_ptr<Piece>> inFlightPieces; + inFlightPieces.reserve(pieceStorage_->countInFlightPiece()); + pieceStorage_->getInFlightPieces(inFlightPieces); + for (std::vector<std::shared_ptr<Piece>>::const_iterator + itr = inFlightPieces.begin(), + eoi = inFlightPieces.end(); + itr != eoi; ++itr) { + uint32_t indexNL = htonl((*itr)->getIndex()); + WRITE_CHECK(fp, &indexNL, sizeof(indexNL)); + uint32_t lengthNL = htonl((*itr)->getLength()); + WRITE_CHECK(fp, &lengthNL, sizeof(lengthNL)); + uint32_t bitfieldLengthNL = htonl((*itr)->getBitfieldLength()); WRITE_CHECK(fp, &bitfieldLengthNL, sizeof(bitfieldLengthNL)); - // bitfield - WRITE_CHECK(fp, pieceStorage_->getBitfield(), - pieceStorage_->getBitfieldLength()); - // the number of in-flight piece: 32 bits - // TODO implement this - uint32_t numInFlightPieceNL = htonl(pieceStorage_->countInFlightPiece()); - WRITE_CHECK(fp, &numInFlightPieceNL, sizeof(numInFlightPieceNL)); - std::vector<std::shared_ptr<Piece> > inFlightPieces; - inFlightPieces.reserve(pieceStorage_->countInFlightPiece()); - pieceStorage_->getInFlightPieces(inFlightPieces); - for(std::vector<std::shared_ptr<Piece> >::const_iterator itr = - inFlightPieces.begin(), eoi = inFlightPieces.end(); - itr != eoi; ++itr) { - uint32_t indexNL = htonl((*itr)->getIndex()); - WRITE_CHECK(fp, &indexNL, sizeof(indexNL)); - uint32_t lengthNL = htonl((*itr)->getLength()); - WRITE_CHECK(fp, &lengthNL, sizeof(lengthNL)); - uint32_t bitfieldLengthNL = htonl((*itr)->getBitfieldLength()); - WRITE_CHECK(fp, &bitfieldLengthNL, sizeof(bitfieldLengthNL)); - WRITE_CHECK(fp, (*itr)->getBitfield(), (*itr)->getBitfieldLength()); - } - if(fp.close() == EOF) { + WRITE_CHECK(fp, (*itr)->getBitfield(), (*itr)->getBitfieldLength()); + } + if (fp.close() == EOF) { + throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_WRITE, filename_.c_str())); + } +} + +void DefaultBtProgressInfoFile::save() +{ + SHA1IOFile sha1io; + + save(sha1io); + + auto digest = sha1io.digest(); + if (digest == lastDigest_) { + // We don't write control file if the content is not changed. + return; + } + + lastDigest_ = std::move(digest); + + A2_LOG_INFO(fmt(MSG_SAVING_SEGMENT_FILE, filename_.c_str())); + std::string filenameTemp = filename_; + filenameTemp += "__temp"; + { + BufferedFile fp(filenameTemp.c_str(), BufferedFile::WRITE); + if (!fp) { throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_WRITE, filename_.c_str())); } - A2_LOG_INFO(MSG_SAVED_SEGMENT_FILE); + + save(fp); } - if(!File(filenameTemp).renameTo(filename_)) { + + A2_LOG_INFO(MSG_SAVED_SEGMENT_FILE); + + if (!File(filenameTemp).renameTo(filename_)) { throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_WRITE, filename_.c_str())); } } -#define READ_CHECK(fp, ptr, count) \ - if(fp.read((ptr), (count)) != (count)) { \ - throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_READ, filename_.c_str())); \ +#define READ_CHECK(fp, ptr, count) \ + if (fp.read((ptr), (count)) != (count)) { \ + throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_READ, filename_.c_str())); \ } // It is assumed that integers are saved as: @@ -210,50 +233,51 @@ void DefaultBtProgressInfoFile::load() { A2_LOG_INFO(fmt(MSG_LOADING_SEGMENT_FILE, filename_.c_str())); BufferedFile fp(filename_.c_str(), BufferedFile::READ); - if(!fp) { + if (!fp) { throw DL_ABORT_EX(fmt(EX_SEGMENT_FILE_READ, filename_.c_str())); } unsigned char versionBuf[2]; READ_CHECK(fp, versionBuf, sizeof(versionBuf)); std::string versionHex = util::toHex(versionBuf, sizeof(versionBuf)); int version; - if("0000" == versionHex) { + if ("0000" == versionHex) { version = 0; - } else if("0001" == versionHex) { + } + else if ("0001" == versionHex) { version = 1; - } else { - throw DL_ABORT_EX - (fmt("Unsupported ctrl file version: %s", versionHex.c_str())); + } + else { + throw DL_ABORT_EX( + fmt("Unsupported ctrl file version: %s", versionHex.c_str())); } unsigned char extension[4]; READ_CHECK(fp, extension, sizeof(extension)); bool infoHashCheckEnabled = false; - if(extension[3]&1 && isTorrentDownload()) { + if (extension[3] & 1 && isTorrentDownload()) { infoHashCheckEnabled = true; A2_LOG_DEBUG("InfoHash checking enabled."); } uint32_t infoHashLength; READ_CHECK(fp, &infoHashLength, sizeof(infoHashLength)); - if(version >= 1) { + if (version >= 1) { infoHashLength = ntohl(infoHashLength); } - if(infoHashLength == 0 && infoHashCheckEnabled) { + if (infoHashLength == 0 && infoHashCheckEnabled) { throw DL_ABORT_EX(fmt("Invalid info hash length: %d", infoHashLength)); } - if(infoHashLength > 0) { + if (infoHashLength > 0) { auto savedInfoHash = make_unique<unsigned char[]>((size_t)infoHashLength); READ_CHECK(fp, savedInfoHash.get(), infoHashLength); #ifdef ENABLE_BITTORRENT - if(infoHashCheckEnabled) { + if (infoHashCheckEnabled) { const unsigned char* infoHash = bittorrent::getInfoHash(dctx_); - if(infoHashLength != INFO_HASH_LENGTH || - memcmp(savedInfoHash.get(), infoHash, INFO_HASH_LENGTH) != 0) { - throw DL_ABORT_EX - (fmt("info hash mismatch. expected: %s, actual: %s", - util::toHex(infoHash, INFO_HASH_LENGTH).c_str(), - util::toHex(savedInfoHash.get(), infoHashLength).c_str() - )); + if (infoHashLength != INFO_HASH_LENGTH || + memcmp(savedInfoHash.get(), infoHash, INFO_HASH_LENGTH) != 0) { + throw DL_ABORT_EX( + fmt("info hash mismatch. expected: %s, actual: %s", + util::toHex(infoHash, INFO_HASH_LENGTH).c_str(), + util::toHex(savedInfoHash.get(), infoHashLength).c_str())); } } #endif // ENABLE_BITTORRENT @@ -261,90 +285,86 @@ void DefaultBtProgressInfoFile::load() uint32_t pieceLength; READ_CHECK(fp, &pieceLength, sizeof(pieceLength)); - if(version >= 1) { + if (version >= 1) { pieceLength = ntohl(pieceLength); } uint64_t totalLength; READ_CHECK(fp, &totalLength, sizeof(totalLength)); - if(version >= 1) { + if (version >= 1) { totalLength = ntoh64(totalLength); } - if(totalLength != static_cast<uint64_t>(dctx_->getTotalLength())) { - throw DL_ABORT_EX - (fmt("total length mismatch. expected: %" PRId64 ", actual: %" PRId64 "", - dctx_->getTotalLength(), - static_cast<int64_t>(totalLength))); + if (totalLength != static_cast<uint64_t>(dctx_->getTotalLength())) { + throw DL_ABORT_EX( + fmt("total length mismatch. expected: %" PRId64 ", actual: %" PRId64 "", + dctx_->getTotalLength(), static_cast<int64_t>(totalLength))); } uint64_t uploadLength; READ_CHECK(fp, &uploadLength, sizeof(uploadLength)); - if(version >= 1) { + if (version >= 1) { uploadLength = ntoh64(uploadLength); } #ifdef ENABLE_BITTORRENT - if(isTorrentDownload()) { + if (isTorrentDownload()) { btRuntime_->setUploadLengthAtStartup(uploadLength); } #endif // ENABLE_BITTORRENT // TODO implement the conversion mechanism between different piece length. uint32_t bitfieldLength; READ_CHECK(fp, &bitfieldLength, sizeof(bitfieldLength)); - if(version >= 1) { + if (version >= 1) { bitfieldLength = ntohl(bitfieldLength); } uint32_t expectedBitfieldLength = - ((totalLength+pieceLength-1)/pieceLength+7)/8; - if(expectedBitfieldLength != bitfieldLength) { - throw DL_ABORT_EX - (fmt("bitfield length mismatch. expected: %d, actual: %d", - expectedBitfieldLength, - bitfieldLength)); + ((totalLength + pieceLength - 1) / pieceLength + 7) / 8; + if (expectedBitfieldLength != bitfieldLength) { + throw DL_ABORT_EX(fmt("bitfield length mismatch. expected: %d, actual: %d", + expectedBitfieldLength, bitfieldLength)); } auto savedBitfield = make_unique<unsigned char[]>((size_t)bitfieldLength); READ_CHECK(fp, savedBitfield.get(), bitfieldLength); - if(pieceLength == static_cast<uint32_t>(dctx_->getPieceLength())) { + if (pieceLength == static_cast<uint32_t>(dctx_->getPieceLength())) { pieceStorage_->setBitfield(savedBitfield.get(), bitfieldLength); uint32_t numInFlightPiece; READ_CHECK(fp, &numInFlightPiece, sizeof(numInFlightPiece)); - if(version >= 1) { + if (version >= 1) { numInFlightPiece = ntohl(numInFlightPiece); } - std::vector<std::shared_ptr<Piece> > inFlightPieces; + std::vector<std::shared_ptr<Piece>> inFlightPieces; inFlightPieces.reserve(numInFlightPiece); - while(numInFlightPiece--) { + while (numInFlightPiece--) { uint32_t index; READ_CHECK(fp, &index, sizeof(index)); - if(version >= 1) { + if (version >= 1) { index = ntohl(index); } - if(!(index < dctx_->getNumPieces())) { + if (!(index < dctx_->getNumPieces())) { throw DL_ABORT_EX(fmt("piece index out of range: %u", index)); } uint32_t length; READ_CHECK(fp, &length, sizeof(length)); - if(version >= 1) { + if (version >= 1) { length = ntohl(length); } - if(!(length <= static_cast<uint32_t>(dctx_->getPieceLength()))) { + if (!(length <= static_cast<uint32_t>(dctx_->getPieceLength()))) { throw DL_ABORT_EX(fmt("piece length out of range: %u", length)); } auto piece = std::make_shared<Piece>(index, length); uint32_t bitfieldLength; READ_CHECK(fp, &bitfieldLength, sizeof(bitfieldLength)); - if(version >= 1) { + if (version >= 1) { bitfieldLength = ntohl(bitfieldLength); } - if(piece->getBitfieldLength() != bitfieldLength) { - throw DL_ABORT_EX - (fmt("piece bitfield length mismatch." - " expected: %lu actual: %u", - static_cast<unsigned long>(piece->getBitfieldLength()), - bitfieldLength)); + if (piece->getBitfieldLength() != bitfieldLength) { + throw DL_ABORT_EX( + fmt("piece bitfield length mismatch." + " expected: %lu actual: %u", + static_cast<unsigned long>(piece->getBitfieldLength()), + bitfieldLength)); } - auto pieceBitfield = make_unique<unsigned char[]> - ((size_t)bitfieldLength); + auto pieceBitfield = make_unique<unsigned char[]>((size_t)bitfieldLength); READ_CHECK(fp, pieceBitfield.get(), bitfieldLength); piece->setBitfield(pieceBitfield.get(), bitfieldLength); piece->setHashType(dctx_->getPieceHashType()); @@ -352,21 +372,22 @@ void DefaultBtProgressInfoFile::load() inFlightPieces.push_back(piece); } pieceStorage_->addInFlightPiece(inFlightPieces); - } else { + } + else { uint32_t numInFlightPiece; READ_CHECK(fp, &numInFlightPiece, sizeof(numInFlightPiece)); - if(version >= 1) { + if (version >= 1) { numInFlightPiece = ntohl(numInFlightPiece); } BitfieldMan src(pieceLength, totalLength); src.setBitfield(savedBitfield.get(), bitfieldLength); - if((src.getCompletedLength() || numInFlightPiece) && - !option_->getAsBool(PREF_ALLOW_PIECE_LENGTH_CHANGE)) { - throw DOWNLOAD_FAILURE_EXCEPTION2 - ("WARNING: Detected a change in piece length. You can proceed with" - " --allow-piece-length-change=true, but you may lose some download" - " progress.", - error_code::PIECE_LENGTH_CHANGED); + if ((src.getCompletedLength() || numInFlightPiece) && + !option_->getAsBool(PREF_ALLOW_PIECE_LENGTH_CHANGE)) { + throw DOWNLOAD_FAILURE_EXCEPTION2( + "WARNING: Detected a change in piece length. You can proceed with" + " --allow-piece-length-change=true, but you may lose some download" + " progress.", + error_code::PIECE_LENGTH_CHANGED); } BitfieldMan dest(dctx_->getPieceLength(), totalLength); util::convertBitfield(&dest, &src); @@ -377,7 +398,7 @@ void DefaultBtProgressInfoFile::load() void DefaultBtProgressInfoFile::removeFile() { - if(exists()) { + if (exists()) { File f(filename_); f.remove(); } @@ -386,24 +407,25 @@ void DefaultBtProgressInfoFile::removeFile() bool DefaultBtProgressInfoFile::exists() { File f(filename_); - if(f.isFile()) { + if (f.isFile()) { A2_LOG_INFO(fmt(MSG_SEGMENT_FILE_EXISTS, filename_.c_str())); return true; - } else { + } + else { A2_LOG_INFO(fmt(MSG_SEGMENT_FILE_DOES_NOT_EXIST, filename_.c_str())); return false; } } #ifdef ENABLE_BITTORRENT -void DefaultBtProgressInfoFile::setPeerStorage -(const std::shared_ptr<PeerStorage>& peerStorage) +void DefaultBtProgressInfoFile::setPeerStorage( + const std::shared_ptr<PeerStorage>& peerStorage) { peerStorage_ = peerStorage; } -void DefaultBtProgressInfoFile::setBtRuntime -(const std::shared_ptr<BtRuntime>& btRuntime) +void DefaultBtProgressInfoFile::setBtRuntime( + const std::shared_ptr<BtRuntime>& btRuntime) { btRuntime_ = btRuntime; } |
