Browse Source

2009-02-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	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
Tatsuhiro Tsujikawa 16 years ago
parent
commit
2dfee3dc49

+ 16 - 0
ChangeLog

@@ -1,3 +1,19 @@
+2009-02-23  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	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  <t-tujikawa@users.sourceforge.net>
 
 	Added --http-auth-challenge option.  If it is set to true(by

+ 19 - 1
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

+ 7 - 1
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

+ 10 - 0
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) {

+ 7 - 1
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>& diskWriter);

+ 17 - 5
src/BtCheckIntegrityEntry.cc

@@ -49,17 +49,28 @@ BtCheckIntegrityEntry::BtCheckIntegrityEntry(RequestGroup* requestGroup):
 
 BtCheckIntegrityEntry::~BtCheckIntegrityEntry() {}
 
-void BtCheckIntegrityEntry::onDownloadIncomplete(std::deque<Command*>& commands,
-						 DownloadEngine* e)
+static void proceedFileAllocation
+(std::deque<Command*>& 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<Command*>& 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<Command*>& commands,
 					       DownloadEngine* e)
 {
@@ -69,8 +80,9 @@ void BtCheckIntegrityEntry::onDownloadFinished(std::deque<Command*>& 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

+ 4 - 0
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.

+ 10 - 0
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<DiskWriter> DiskWriterHandle;

+ 15 - 1
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<SharedHandle<DiskWriterEntry> >::const_iterator i =

+ 6 - 0
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;
   }

+ 3 - 0
src/RequestGroup.cc

@@ -266,6 +266,9 @@ void RequestGroup::createInitialCommand(std::deque<Command*>& 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.