diff --git a/ChangeLog b/ChangeLog index 770a7ade..15c7dfbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2009-02-23 Tatsuhiro Tsujikawa + + In BitTorrent, Open files in read-only mode for hash check. After + that, re-open file in read/write mode only when the download is + not finished. + * src/AbstractDiskWriter.cc + * src/AbstractDiskWriter.h + * src/AbstractSingleDiskAdaptor.cc + * src/AbstractSingleDiskAdaptor.h + * src/BtCheckIntegrityEntry.cc + * src/DiskAdaptor.h + * src/DiskWriter.h + * src/MultiDiskAdaptor.cc + * src/MultiDiskAdaptor.h + * src/RequestGroup.cc + 2009-02-19 Tatsuhiro Tsujikawa Added --http-auth-challenge option. If it is set to true(by diff --git a/src/AbstractDiskWriter.cc b/src/AbstractDiskWriter.cc index d3a31f5a..cec3bdaf 100644 --- a/src/AbstractDiskWriter.cc +++ b/src/AbstractDiskWriter.cc @@ -58,6 +58,7 @@ namespace aria2 { AbstractDiskWriter::AbstractDiskWriter(): fd(-1), + _readOnly(false), logger(LogFactory::getInstance()) {} AbstractDiskWriter::~AbstractDiskWriter() @@ -93,7 +94,14 @@ void AbstractDiskWriter::openExistingFile(const std::string& filename, (StringFormat(EX_FILE_OPEN, filename.c_str(), MSG_FILE_NOT_FOUND).str()); } - if((fd = open(filename.c_str(), O_RDWR|O_BINARY, OPEN_MODE)) < 0) { + int flags = O_BINARY; + if(_readOnly) { + flags |= O_RDONLY; + } else { + flags |= O_RDWR; + } + + if((fd = open(filename.c_str(), flags, OPEN_MODE)) < 0) { throw DlAbortEx (StringFormat(EX_FILE_OPEN, filename.c_str(), strerror(errno)).str()); } @@ -217,4 +225,14 @@ void AbstractDiskWriter::disableDirectIO() #endif // ENABLE_DIRECT_IO } +void AbstractDiskWriter::enableReadOnly() +{ + _readOnly = true; +} + +void AbstractDiskWriter::disableReadOnly() +{ + _readOnly = false; +} + } // namespace aria2 diff --git a/src/AbstractDiskWriter.h b/src/AbstractDiskWriter.h index d459ee48..ef967687 100644 --- a/src/AbstractDiskWriter.h +++ b/src/AbstractDiskWriter.h @@ -46,6 +46,9 @@ class AbstractDiskWriter : public DiskWriter { protected: std::string filename; int fd; + + bool _readOnly; + Logger* logger; void createFile(const std::string& filename, int addFlags = 0); @@ -55,7 +58,6 @@ private: ssize_t readDataInternal(unsigned char* data, size_t len); void seek(off_t offset); - public: AbstractDiskWriter(); virtual ~AbstractDiskWriter(); @@ -77,6 +79,10 @@ public: virtual void enableDirectIO(); virtual void disableDirectIO(); + + virtual void enableReadOnly(); + + virtual void disableReadOnly(); }; } // namespace aria2 diff --git a/src/AbstractSingleDiskAdaptor.cc b/src/AbstractSingleDiskAdaptor.cc index ca21b1c6..d1c4d8a5 100644 --- a/src/AbstractSingleDiskAdaptor.cc +++ b/src/AbstractSingleDiskAdaptor.cc @@ -111,6 +111,16 @@ bool AbstractSingleDiskAdaptor::directIOAllowed() const return diskWriter->directIOAllowed(); } +void AbstractSingleDiskAdaptor::enableReadOnly() +{ + diskWriter->enableReadOnly(); +} + +void AbstractSingleDiskAdaptor::disableReadOnly() +{ + diskWriter->disableReadOnly(); +} + void AbstractSingleDiskAdaptor::cutTrailingGarbage() { if(File(getFilePath()).size() > totalLength) { diff --git a/src/AbstractSingleDiskAdaptor.h b/src/AbstractSingleDiskAdaptor.h index 36a2ede9..fd16d585 100644 --- a/src/AbstractSingleDiskAdaptor.h +++ b/src/AbstractSingleDiskAdaptor.h @@ -77,7 +77,13 @@ public: virtual void disableDirectIO(); virtual bool directIOAllowed() const; - + + // Make sure that DiskWriter is set before calling this function. + virtual void enableReadOnly(); + + // Make sure that DiskWriter is set before calling this function. + virtual void disableReadOnly(); + virtual void cutTrailingGarbage(); void setDiskWriter(const SharedHandle& diskWriter); diff --git a/src/BtCheckIntegrityEntry.cc b/src/BtCheckIntegrityEntry.cc index feeb924e..bed582c5 100644 --- a/src/BtCheckIntegrityEntry.cc +++ b/src/BtCheckIntegrityEntry.cc @@ -49,17 +49,28 @@ BtCheckIntegrityEntry::BtCheckIntegrityEntry(RequestGroup* requestGroup): BtCheckIntegrityEntry::~BtCheckIntegrityEntry() {} -void BtCheckIntegrityEntry::onDownloadIncomplete(std::deque& commands, - DownloadEngine* e) +static void proceedFileAllocation +(std::deque& commands, DownloadEngine* e, RequestGroup* requestGroup) { - FileAllocationEntryHandle entry(new BtFileAllocationEntry(_requestGroup)); - if(_requestGroup->needsFileAllocation()) { + FileAllocationEntryHandle entry(new BtFileAllocationEntry(requestGroup)); + if(requestGroup->needsFileAllocation()) { e->_fileAllocationMan->pushEntry(entry); } else { entry->prepareForNextAction(commands, e); } } +void BtCheckIntegrityEntry::onDownloadIncomplete(std::deque& commands, + DownloadEngine* e) +{ + // Now reopen DiskAdaptor with read only disabled. + _requestGroup->getPieceStorage()->getDiskAdaptor()->closeFile(); + _requestGroup->getPieceStorage()->getDiskAdaptor()->disableReadOnly(); + _requestGroup->getPieceStorage()->getDiskAdaptor()->openFile(); + + proceedFileAllocation(commands, e, _requestGroup); +} + void BtCheckIntegrityEntry::onDownloadFinished(std::deque& commands, DownloadEngine* e) { @@ -69,8 +80,9 @@ void BtCheckIntegrityEntry::onDownloadFinished(std::deque& commands, // to exit rather than doing seeding. So, it would be good to toggle this // behavior. if(e->option->getAsBool(PREF_BT_HASH_CHECK_SEED)) { - onDownloadIncomplete(commands, e); + proceedFileAllocation(commands, e, _requestGroup); } } + } // namespace aria2 diff --git a/src/DiskAdaptor.h b/src/DiskAdaptor.h index 012eb48b..9b4fb1a7 100644 --- a/src/DiskAdaptor.h +++ b/src/DiskAdaptor.h @@ -98,6 +98,10 @@ public: virtual void disableDirectIO() {} + virtual void enableReadOnly() {} + + virtual void disableReadOnly() {} + // Assumed each file length is stored in fileEntries or DiskAdaptor knows it. // If each actual file's length is larger than that, truncate file to that // length. diff --git a/src/DiskWriter.h b/src/DiskWriter.h index 2084826e..dfd9fd97 100644 --- a/src/DiskWriter.h +++ b/src/DiskWriter.h @@ -92,6 +92,16 @@ public: { _directIOAllowed = f; } + + // Enables read-only mode. After this call, openExistingFile() opens + // file in read-only mode. This is an optional functionality. The + // default implementation is do nothing. + virtual void enableReadOnly() {} + + // Disables read-only mode. After this call, openExistingFile() + // opens file in read/write mode. This is an optional + // functionality. The default implementation is do noting. + virtual void disableReadOnly() {} }; typedef SharedHandle DiskWriterHandle; diff --git a/src/MultiDiskAdaptor.cc b/src/MultiDiskAdaptor.cc index 1b1ebb53..bf586345 100644 --- a/src/MultiDiskAdaptor.cc +++ b/src/MultiDiskAdaptor.cc @@ -169,7 +169,8 @@ void DiskWriterEntry::needsFileAllocation(bool f) MultiDiskAdaptor::MultiDiskAdaptor(): pieceLength(0), _maxOpenFiles(DEFAULT_MAX_OPEN_FILES), - _directIOAllowed(false) {} + _directIOAllowed(false), + _readOnly(false) {} MultiDiskAdaptor::~MultiDiskAdaptor() {} @@ -273,6 +274,9 @@ void MultiDiskAdaptor::resetDiskWriterEntries() (*i)->getFilePath(getTopDirPath()).c_str()); (*i)->setDiskWriter(dwFactory.newDiskWriter()); (*i)->getDiskWriter()->setDirectIOAllowed(_directIOAllowed); + if(_readOnly) { + (*i)->getDiskWriter()->enableReadOnly(); + } } } } @@ -518,6 +522,16 @@ void MultiDiskAdaptor::disableDirectIO() } } +void MultiDiskAdaptor::enableReadOnly() +{ + _readOnly = true; +} + +void MultiDiskAdaptor::disableReadOnly() +{ + _readOnly = false; +} + void MultiDiskAdaptor::cutTrailingGarbage() { for(std::deque >::const_iterator i = diff --git a/src/MultiDiskAdaptor.h b/src/MultiDiskAdaptor.h index 51ea1094..a52e8b1e 100644 --- a/src/MultiDiskAdaptor.h +++ b/src/MultiDiskAdaptor.h @@ -113,6 +113,8 @@ private: bool _directIOAllowed; + bool _readOnly; + void resetDiskWriterEntries(); void mkdir(const std::string& topDirPath) const; @@ -160,6 +162,10 @@ public: virtual void disableDirectIO(); + virtual void enableReadOnly(); + + virtual void disableReadOnly(); + void setTopDir(const std::string& topDir) { this->topDir = topDir; } diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index c0252032..a82ae865 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -266,6 +266,9 @@ void RequestGroup::createInitialCommand(std::deque& commands, progressInfoFile->getFilename().c_str(), _pieceStorage->getDiskAdaptor()->getFilePath().c_str()); } + // First, make DiskAdaptor read-only mode. + _pieceStorage->getDiskAdaptor()->enableReadOnly(); + // Call Load, Save and file allocation command here if(progressInfoFile->exists()) { // load .aria2 file if it exists.