Parcourir la source

2006-04-16 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	* src/TorrentConsoleDownloadEngine.cc
	(onPartialDownloadingCompletes): Renamed as
	onSelectiveDownloadingCompletes.
	(onSelectiveDownloadingCompletes): Updated message.

	To add DiskAdaptor which abstract DiskWriter family:

	* src/PeerConnection.cc: Use diskAdaptor instead of diskWriter.
	* src/PeerInteractionCommand.cc: Use diskAdaptor instead of 
diskWriter.
	* src/BitfieldMan.cc (isAllBitSet): bug fix.
	* src/TorrentMan.cc : Included CopyDiskAdaptor.h, 
DirectDiskAdaptor.h,
	MultiDiskAdaptor.h.
	(readFileEntry): Changed its arguments.
	(setup): setupDiskWriter is merged into this function.
	(setupDiskWriter): Removed.
	(setFileFilter): New function.
	(readFileEntryFromMetaInfoFile): Updated according to the 
changes
	made in readFileEntry.
	(getFilePath): Removed.
	(getTempFilePath): Removed.
	(getSegmentFilePath): Updated due to the removal of getFilePath.
	(fixFilename): Removed.
	(copySingleFile): Removed.
	(splitMultiFile): Removed.
	(deleteTempFile): Removed.
	(setFileEntriesToDownload): Removed.
	(isPartialDownloadingMode): Renamed as 
isSelectiveDownloadingMode.
	(isSelectiveDownloadingMode): New function.
	(setAllMultiFileRequestedState): Removed.
	(finishPartialDownloadingMode): Renamed as
	finishSelectiveDownloadingMode.
	(finishSelectiveDownloadingMode): New function.
	(getPartialTotalLength): Renamed as getSelectedTotalLength.
	(getSelectedTotalLength): New function.
	(onDownloadComplete): Use diskAdaptor.
	* src/MultiDiskWriter.cc (Constructor): Added the argument 
pieceLength
	(Range): Removed.
	(setMultiFileEntries): Renamed as setFileEntries.
	(setFileEntries): New function.
	* src/MultiDiskWriter.h [DiskWriterEntry](enabled): Removed.
	(pieceLength): New variable.
	* src/main.cc (printDownloadCompeleteMessage): New function.
	(torrentHandler): Use diskAdaptor instead of diskWriter.
	(main): Renamed torrent-show-files to show-files.
	Rewritten file contents listing.
	* src/TorrentMan.h (FileEntry): Removed.
	(multiFileTopDir): Removed.
	(multiFileEntries): Removed.
	(diskWriter): Removed.
	(diskAdaptor): New variable.
	* src/DefaultDiskWriter.h (totalLength): New variable.
	* src/DefaultDiskWriter.cc (initAndOpenFile): Added ftruncate.
	* src/TorrentDownloadEngine.cc (onEndOfRun): Use diskAdaptor 
instead of
	diskWriter.
	* src/TorrentConsoleDownloadEngine.h
	(partialDownloadLengthDiff): Renamed as 
selectedDownloadLengthDiff.
	(partialTotalLength): Renamed as selectedTotalLength.
	* src/AbstractDiskWriter.cc (openFile): If file exists, call
	openExistingFile, otherwise call initAndOpenFile.
	(closeFile): fd > 0, not fd != 0.
	
	* src/prefs.h (PREF_TORRENT_SHOW_FILES): Renamed as 
PREF_SHOW_FILES
	(PREF_SHOW_FILES): New definition.
Tatsuhiro Tsujikawa il y a 19 ans
Parent
commit
2a84b9de43

+ 68 - 0
ChangeLog

@@ -1,3 +1,71 @@
+2006-04-16  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	* src/TorrentConsoleDownloadEngine.cc
+	(onPartialDownloadingCompletes): Renamed as
+	onSelectiveDownloadingCompletes.
+	(onSelectiveDownloadingCompletes): Updated message.
+
+	To add DiskAdaptor which abstract DiskWriter family:
+
+	* src/PeerConnection.cc: Use diskAdaptor instead of diskWriter.
+	* src/PeerInteractionCommand.cc: Use diskAdaptor instead of diskWriter.
+	* src/BitfieldMan.cc (isAllBitSet): bug fix.
+	* src/TorrentMan.cc : Included CopyDiskAdaptor.h, DirectDiskAdaptor.h,
+	MultiDiskAdaptor.h.
+	(readFileEntry): Changed its arguments.
+	(setup): setupDiskWriter is merged into this function.
+	(setupDiskWriter): Removed.
+	(setFileFilter): New function.
+	(readFileEntryFromMetaInfoFile): Updated according to the changes
+	made in readFileEntry.
+	(getFilePath): Removed.
+	(getTempFilePath): Removed.
+	(getSegmentFilePath): Updated due to the removal of getFilePath.
+	(fixFilename): Removed.
+	(copySingleFile): Removed.
+	(splitMultiFile): Removed.
+	(deleteTempFile): Removed.
+	(setFileEntriesToDownload): Removed.
+	(isPartialDownloadingMode): Renamed as isSelectiveDownloadingMode.
+	(isSelectiveDownloadingMode): New function.
+	(setAllMultiFileRequestedState): Removed.
+	(finishPartialDownloadingMode): Renamed as
+	finishSelectiveDownloadingMode.
+	(finishSelectiveDownloadingMode): New function.
+	(getPartialTotalLength): Renamed as getSelectedTotalLength.
+	(getSelectedTotalLength): New function.
+	(onDownloadComplete): Use diskAdaptor.
+	* src/MultiDiskWriter.cc (Constructor): Added the argument pieceLength
+	(Range): Removed.
+	(setMultiFileEntries): Renamed as setFileEntries.
+	(setFileEntries): New function.
+	* src/MultiDiskWriter.h [DiskWriterEntry](enabled): Removed.
+	(pieceLength): New variable.
+	* src/main.cc (printDownloadCompeleteMessage): New function.
+	(torrentHandler): Use diskAdaptor instead of diskWriter.
+	(main): Renamed torrent-show-files to show-files.
+	Rewritten file contents listing.
+	* src/TorrentMan.h (FileEntry): Removed.
+	(multiFileTopDir): Removed.
+	(multiFileEntries): Removed.
+	(diskWriter): Removed.
+	(diskAdaptor): New variable.
+	* src/DefaultDiskWriter.h (totalLength): New variable.
+	* src/DefaultDiskWriter.cc (initAndOpenFile): Added ftruncate.
+	* src/TorrentDownloadEngine.cc (onEndOfRun): Use diskAdaptor instead of
+	diskWriter.
+	* src/TorrentConsoleDownloadEngine.h
+	(partialDownloadLengthDiff): Renamed as selectedDownloadLengthDiff.
+	(partialTotalLength): Renamed as selectedTotalLength.
+	* src/AbstractDiskWriter.cc (openFile): If file exists, call
+	openExistingFile, otherwise call initAndOpenFile.
+	(closeFile): fd > 0, not fd != 0.
+	
+	* src/prefs.h (PREF_TORRENT_SHOW_FILES): Renamed as PREF_SHOW_FILES
+	(PREF_SHOW_FILES): New definition.
+	
+	
+
 2006-04-12  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	To add the ability to download multi torrent into respective files

+ 10 - 2
TODO

@@ -11,6 +11,14 @@
 * Add port range command-line option
 * Add max peers command-line option
 * Distinguish seeder from leecher
-* file selection in multi-file mode
+
+0.4.0 release
+* Add selective downloading mode
 * try to use ftruncate to allocate file.
-* fix TorrentMan::getFilePath()
+* test all download mode
+* Add loggerfactory
+* Add SIGTERM signal handler
+
+0.4.1 release
+* Add port command-line option
+* Add estimated remaining time to normal HTTP/FTP downloading status ouput

+ 8 - 5
src/AbstractDiskWriter.cc

@@ -36,7 +36,7 @@ AbstractDiskWriter::AbstractDiskWriter():fd(0) {
 }
 
 AbstractDiskWriter::~AbstractDiskWriter() {
-  if(fd != 0) {
+  if(fd > 0) {
     close(fd);
   }
 #ifdef ENABLE_SHA1DIGEST
@@ -45,13 +45,16 @@ AbstractDiskWriter::~AbstractDiskWriter() {
 }
 
 void AbstractDiskWriter::openFile(const string& filename) {
-  if((fd = open(filename.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
-    throw new DlAbortEx(strerror(errno));
-  }  
+  File f(filename);
+  if(f.exists()) {
+    openExistingFile(filename);
+  } else {
+    initAndOpenFile(filename);
+  }
 }
 
 void AbstractDiskWriter::closeFile() {
-  if(fd != 0) {
+  if(fd > 0) {
     close(fd);
     fd = 0;
   }

+ 1 - 1
src/BitfieldMan.cc

@@ -261,7 +261,7 @@ bool BitfieldMan::unsetBit(int index) {
 
 bool BitfieldMan::isAllBitSet() const {
   if(filterEnabled) {
-    for(int i = 0; i < bitfieldLength-1; i++) {
+    for(int i = 0; i < bitfieldLength; i++) {
       if((bitfield[i]&filterBitfield[i]) != filterBitfield[i]) {
 	return false;
       }

+ 6 - 1
src/DefaultDiskWriter.cc

@@ -23,10 +23,15 @@
 #include "DlAbortEx.h"
 #include <errno.h>
 
-DefaultDiskWriter::DefaultDiskWriter():AbstractDiskWriter() {}
+DefaultDiskWriter::DefaultDiskWriter():AbstractDiskWriter(), totalLength(0) {}
+
+DefaultDiskWriter::DefaultDiskWriter(long long int totalLength):AbstractDiskWriter(), totalLength(totalLength) {}
 
 DefaultDiskWriter::~DefaultDiskWriter() {}
 
 void DefaultDiskWriter::initAndOpenFile(string filename) {
   createFile(filename);
+  if(totalLength > 0) {
+    ftruncate(fd, totalLength);
+  }
 }

+ 3 - 0
src/DefaultDiskWriter.h

@@ -25,8 +25,11 @@
 #include "AbstractDiskWriter.h"
 
 class DefaultDiskWriter:public AbstractDiskWriter {
+private:
+  long long int totalLength;
 public:
   DefaultDiskWriter();
+  DefaultDiskWriter(long long int totalLength);
   ~DefaultDiskWriter();
 
   void initAndOpenFile(string filename);

+ 42 - 0
src/FileEntry.h

@@ -0,0 +1,42 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* copyright --> */
+#ifndef _D_FILE_ENTRY_H_
+#define _D_FILE_ENTRY_H_
+
+#include "common.h"
+
+class FileEntry {
+public:
+  string path;
+  long long int length;
+  long long int offset;
+  bool extracted;
+  bool requested;
+  FileEntry(string path, long long int length, long long int offset):
+    path(path), length(length), offset(offset),
+    extracted(false), requested(true) {}
+  ~FileEntry() {}
+};
+
+typedef deque<FileEntry> FileEntries;
+
+#endif // _D_FILE_ENTRY_H_

+ 6 - 1
src/Makefile.am

@@ -79,7 +79,12 @@ SRCS =  Socket.cc Socket.h\
 	TrackerWatcherCommand.cc TrackerWatcherCommand.h\
 	messageDigest.h\
 	SendMessageQueue.cc SendMessageQueue.h\
-	MultiDiskWriter.cc MultiDiskWriter.h
+	MultiDiskWriter.cc MultiDiskWriter.h\
+	DiskAdaptor.cc DiskAdaptor.h\
+	CopyDiskAdaptor.cc CopyDiskAdaptor.h\
+	DirectDiskAdaptor.cc DirectDiskAdaptor.h\
+	MultiDiskAdaptor.cc MultiDiskAdaptor.h\
+	FileEntry.h
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\

+ 13 - 2
src/Makefile.in

@@ -98,7 +98,9 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \
 	PeerMessage.$(OBJEXT) Piece.$(OBJEXT) RequestSlot.$(OBJEXT) \
 	RequestSlotMan.$(OBJEXT) TorrentAutoSaveCommand.$(OBJEXT) \
 	Directory.$(OBJEXT) TrackerWatcherCommand.$(OBJEXT) \
-	SendMessageQueue.$(OBJEXT) MultiDiskWriter.$(OBJEXT)
+	SendMessageQueue.$(OBJEXT) MultiDiskWriter.$(OBJEXT) \
+	DiskAdaptor.$(OBJEXT) CopyDiskAdaptor.$(OBJEXT) \
+	DirectDiskAdaptor.$(OBJEXT) MultiDiskAdaptor.$(OBJEXT)
 am_libaria2c_a_OBJECTS = $(am__objects_1)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -327,7 +329,12 @@ SRCS = Socket.cc Socket.h\
 	TrackerWatcherCommand.cc TrackerWatcherCommand.h\
 	messageDigest.h\
 	SendMessageQueue.cc SendMessageQueue.h\
-	MultiDiskWriter.cc MultiDiskWriter.h
+	MultiDiskWriter.cc MultiDiskWriter.h\
+	DiskAdaptor.cc DiskAdaptor.h\
+	CopyDiskAdaptor.cc CopyDiskAdaptor.h\
+	DirectDiskAdaptor.cc DirectDiskAdaptor.h\
+	MultiDiskAdaptor.cc MultiDiskAdaptor.h\
+	FileEntry.h
 
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
@@ -420,10 +427,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncoding.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleDownloadEngine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBox.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CopyDiskAdaptor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Data.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Dictionary.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DirectDiskAdaptor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Directory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DiskAdaptor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadEngine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/File.Po@am__quote@
@@ -444,6 +454,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InitiateConnectionCommandFactory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/List.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetaFileUtil.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskAdaptor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Option.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Peer.Po@am__quote@

+ 9 - 61
src/MultiDiskWriter.cc

@@ -24,7 +24,7 @@
 #include "Util.h"
 #include <errno.h>
 
-MultiDiskWriter::MultiDiskWriter() {
+MultiDiskWriter::MultiDiskWriter(int pieceLength):pieceLength(pieceLength) {
 #ifdef ENABLE_SHA1DIGEST
   sha1DigestInit(ctx);
 #endif // ENABLE_SHA1DIGEST
@@ -37,63 +37,26 @@ MultiDiskWriter::~MultiDiskWriter() {
 #endif // ENABLE_SHA1DIGEST
 }
 
-typedef struct {
-  long long int blockOffset;
-  long long int length;
-} Range;
-
-typedef deque<Range> Ranges;
-
 void MultiDiskWriter::clearEntries() {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end(); itr++) {
-    if((*itr)->enabled) {
-      (*itr)->diskWriter->closeFile();
-    }
     delete *itr;
   }
   diskWriterEntries.clear();
 }
 
-void MultiDiskWriter::setMultiFileEntries(const MultiFileEntries& multiFileEntries, int pieceLength) {
+void MultiDiskWriter::setFileEntries(const FileEntries& fileEntries) {
   clearEntries();
-  Ranges ranges;
-  for(MultiFileEntries::const_iterator itr = multiFileEntries.begin();
-      itr != multiFileEntries.end(); itr++) {
-    if(itr->requested) {
-      Range range;
-      range.blockOffset = (itr->offset/pieceLength)*pieceLength;
-      range.length = ((itr->offset+itr->length)/pieceLength+
-	((itr->offset+itr->length)%pieceLength ? 1 : 0))*pieceLength-range.blockOffset;
-      ranges.push_back(range);
-    }		
-  }
-  Ranges::const_iterator ritr = ranges.begin();
-  for(MultiFileEntries::const_iterator itr = multiFileEntries.begin();
-      itr != multiFileEntries.end(); itr++) {
-    DiskWriterEntry* entry;
-    if(ritr != ranges.end() &&
-       //       !(ritr->blockOffset+ritr->length-1 < itr->offset ||
-       //	 itr->offset+itr->length-1 < ritr->blockOffset)) {
-       itr->offset < ritr->blockOffset+ritr->length &&
-       ritr->blockOffset < itr->offset+itr->length) {
-
-      entry = new DiskWriterEntry(*itr, true);
-      for(;ritr->blockOffset+ritr->length <= itr->offset+itr->length &&
-	    ritr != ranges.end(); ritr++);
-    } else {
-      entry = new DiskWriterEntry(*itr, false);
-    }
-    diskWriterEntries.push_back(entry);
+  for(FileEntries::const_iterator itr = fileEntries.begin();
+      itr != fileEntries.end(); itr++) {
+    diskWriterEntries.push_back(new DiskWriterEntry(*itr));
   }
 }
 
 void MultiDiskWriter::openFile(const string& filename) {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end(); itr++) {
-    if((*itr)->enabled) {
-      (*itr)->diskWriter->openFile(filename+"/"+(*itr)->fileEntry.path);
-    }
+    (*itr)->diskWriter->openFile(filename+"/"+(*itr)->fileEntry.path);
   }
 }
 
@@ -101,27 +64,21 @@ void MultiDiskWriter::openFile(const string& filename) {
 void MultiDiskWriter::initAndOpenFile(string filename) {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end(); itr++) {
-    if((*itr)->enabled) {
-      (*itr)->diskWriter->initAndOpenFile(filename+"/"+(*itr)->fileEntry.path);
-    }
+    (*itr)->diskWriter->initAndOpenFile(filename+"/"+(*itr)->fileEntry.path);
   }
 }
 
 void MultiDiskWriter::closeFile() {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end(); itr++) {
-    if((*itr)->enabled) {
-      (*itr)->diskWriter->closeFile();
-    }
+    (*itr)->diskWriter->closeFile();
   }
 }
 
 void MultiDiskWriter::openExistingFile(string filename) {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end(); itr++) {
-    if((*itr)->enabled) {
-      (*itr)->diskWriter->openExistingFile(filename+"/"+(*itr)->fileEntry.path);
-    }
+    (*itr)->diskWriter->openExistingFile(filename+"/"+(*itr)->fileEntry.path);
   }
 }
 
@@ -133,9 +90,6 @@ void MultiDiskWriter::writeData(const char* data, int len, long long int positio
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end() && rem != 0; itr++) {
     if(isInRange(*itr, offset) || writing) {
-      if(!(*itr)->enabled) {
-	throw new DlAbortEx("invalid offset or length. offset = %lld", offset);
-      }
       int writeLength = calculateLength(*itr, fileOffset, rem);
       (*itr)->diskWriter->writeData(data+(len-rem), writeLength, fileOffset);
       rem -= writeLength;
@@ -174,9 +128,6 @@ int MultiDiskWriter::readData(char* data, int len, long long int position) {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end() && rem != 0; itr++) {
     if(isInRange(*itr, offset) || reading) {
-      if(!(*itr)->enabled) {
-	throw new DlAbortEx("invalid offset or length. offset = %lld", offset);
-      }
       int readLength = calculateLength((*itr), fileOffset, rem);
       totalReadLength += (*itr)->diskWriter->readData(data+(len-rem), readLength, fileOffset);
       rem -= readLength;
@@ -223,9 +174,6 @@ string MultiDiskWriter::sha1Sum(long long int offset, long long int length) {
     for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
 	itr != diskWriterEntries.end() && rem != 0; itr++) {
       if(isInRange(*itr, offset) || reading) {
-	if(!(*itr)->enabled) {
-	  throw new DlAbortEx("invalid offset or length. offset = %lld", offset);
-	}
 	int readLength = calculateLength((*itr), fileOffset, rem);
 	hashUpdate(*itr, fileOffset, readLength);
 	rem -= readLength;

+ 6 - 11
src/MultiDiskWriter.h

@@ -30,17 +30,12 @@ class DiskWriterEntry {
 public:
   FileEntry fileEntry;
   DiskWriter* diskWriter;
-  bool enabled;
 public:
-  DiskWriterEntry(const FileEntry& fileEntry, bool enabled):fileEntry(fileEntry), enabled(enabled) {
-    if(enabled) {
-      diskWriter = new DefaultDiskWriter();
-    }
+  DiskWriterEntry(const FileEntry& fileEntry):fileEntry(fileEntry) {
+    diskWriter = new DefaultDiskWriter(this->fileEntry.length);
   }
   ~DiskWriterEntry() {
-    if(enabled) {
-      delete diskWriter;
-    }
+    delete diskWriter;
   }
 };
 
@@ -49,7 +44,7 @@ typedef deque<DiskWriterEntry*> DiskWriterEntries;
 class MultiDiskWriter : public DiskWriter {
 private:
   DiskWriterEntries diskWriterEntries;
-
+  int pieceLength;
   bool isInRange(const DiskWriterEntry* entry, long long int offset) const;
   int calculateLength(const DiskWriterEntry* entry, long long int fileOffset, int rem) const;
   void clearEntries();
@@ -59,10 +54,10 @@ private:
 #endif // ENABLE_SHA1DIGEST
 
 public:
-  MultiDiskWriter();
+  MultiDiskWriter(int pieceLength);
   virtual ~MultiDiskWriter();
 
-  void setMultiFileEntries(const MultiFileEntries& multiFileEntries, int pieceLength);
+  void setFileEntries(const FileEntries& fileEntries);
 
   virtual void openFile(const string& filename);
   virtual void initAndOpenFile(string filename);

+ 4 - 4
src/PeerConnection.cc

@@ -216,14 +216,14 @@ void PeerConnection::sendPiece(int index, int begin, int length) const {
   int iteration = length/BUF_SIZE;
   long long int pieceOffset = ((long long int)index*torrentMan->pieceLength)+begin;
   for(int i = 0; i < iteration; i++) {
-    if(torrentMan->diskWriter->readData(buf, BUF_SIZE, pieceOffset+i*BUF_SIZE) < BUF_SIZE) {
+    if(torrentMan->diskAdaptor->readData(buf, BUF_SIZE, pieceOffset+i*BUF_SIZE) < BUF_SIZE) {
       throw new DlAbortEx("piece reading failed.");
     }
     socket->writeData(buf, BUF_SIZE);
   }
   int rem = length%BUF_SIZE;
   if(rem > 0) {
-    if(torrentMan->diskWriter->readData(buf, rem, pieceOffset+iteration*BUF_SIZE) < rem) {
+    if(torrentMan->diskAdaptor->readData(buf, rem, pieceOffset+iteration*BUF_SIZE) < rem) {
       throw new DlAbortEx("piece reading failed.");
     }
     socket->writeData(buf, rem);
@@ -259,7 +259,7 @@ int PeerConnection::sendPieceData(long long int offset, int length) const {
     if(!isWritable) {
       return writtenLength;
     }
-    if(torrentMan->diskWriter->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) {
+    if(torrentMan->diskAdaptor->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) {
       throw new DlAbortEx("piece reading failed.");
     }
     socket->writeData(buf, BUF_SIZE);
@@ -268,7 +268,7 @@ int PeerConnection::sendPieceData(long long int offset, int length) const {
   if(socket->isWritable(0)) {
     int rem = length%BUF_SIZE;
     if(rem > 0) {
-      if(torrentMan->diskWriter->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) {
+      if(torrentMan->diskAdaptor->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) {
 	throw new DlAbortEx("piece reading failed.");
       }
       socket->writeData(buf, rem);

+ 6 - 6
src/PeerInteractionCommand.cc

@@ -274,9 +274,9 @@ void PeerInteractionCommand::receiveMessage() {
 	  ((long long int)message->getIndex())*e->torrentMan->pieceLength+message->getBegin();
 	e->logger->debug("CUID#%d - write block length = %d, offset=%lld",
 			 cuid, message->getBlockLength(), offset);      
-	e->torrentMan->diskWriter->writeData(message->getBlock(),
-					     message->getBlockLength(),
-					     offset);
+	e->torrentMan->diskAdaptor->writeData(message->getBlock(),
+					      message->getBlockLength(),
+					      offset);
 	piece.completeBlock(slot.getBlockIndex());
 	sendMessageQueue->deleteRequestSlot(slot);
 	e->torrentMan->updatePiece(piece);
@@ -444,7 +444,7 @@ void PeerInteractionCommand::beforeSocketCheck() {
 
 bool PeerInteractionCommand::checkPieceHash(const Piece& piece) {
   long long int offset = ((long long int)piece.getIndex())*e->torrentMan->pieceLength;
-  return e->torrentMan->diskWriter->sha1Sum(offset, piece.getLength()) ==
+  return e->torrentMan->diskAdaptor->sha1Sum(offset, piece.getLength()) ==
     e->torrentMan->getPieceHash(piece.getIndex());
 }
 
@@ -454,11 +454,11 @@ void PeerInteractionCommand::erasePieceOnDisk(const Piece& piece) {
   memset(buf, 0, BUFSIZE);
   long long int offset = ((long long int)piece.getIndex())*e->torrentMan->pieceLength;
   for(int i = 0; i < piece.getLength()/BUFSIZE; i++) {
-    e->torrentMan->diskWriter->writeData(buf, BUFSIZE, offset);
+    e->torrentMan->diskAdaptor->writeData(buf, BUFSIZE, offset);
     offset += BUFSIZE;
   }
   int r = piece.getLength()%BUFSIZE;
   if(r > 0) {
-    e->torrentMan->diskWriter->writeData(buf, r, offset);
+    e->torrentMan->diskAdaptor->writeData(buf, r, offset);
   }
 }

+ 0 - 1
src/PreAllocationDiskWriter.cc

@@ -35,7 +35,6 @@ PreAllocationDiskWriter::~PreAllocationDiskWriter() {}
 
 void PreAllocationDiskWriter::initAndOpenFile(string filename) {
   createFile(filename);
-  
   int bufSize = 4096;
   char buf[4096];
 

+ 9 - 8
src/TorrentConsoleDownloadEngine.cc

@@ -26,8 +26,9 @@ TorrentConsoleDownloadEngine::TorrentConsoleDownloadEngine() {}
 
 TorrentConsoleDownloadEngine::~TorrentConsoleDownloadEngine() {}
 
-void TorrentConsoleDownloadEngine::onPartialDownloadingCompletes() {
-  printf("Download of specified files has completed. Continue normal download operation.\n");
+void TorrentConsoleDownloadEngine::onSelectiveDownloadingCompletes() {
+  printf("\nDownload of selected files has completed.\n");
+  fflush(stdout);
 }
 
 void TorrentConsoleDownloadEngine::printStatistics() {
@@ -68,9 +69,9 @@ void TorrentConsoleDownloadEngine::initStatistics() {
   sessionDownloadLength = 0;
   downloadLength = 0;
   totalLength = 0;
-  if(torrentMan->isPartialDownloadingMode()) {
-    partialDownloadLengthDiff = torrentMan->getDownloadLength()-torrentMan->getCompletedLength();
-    partialTotalLength = torrentMan->getPartialTotalLength();
+  if(torrentMan->isSelectiveDownloadingMode()) {
+    selectedDownloadLengthDiff = torrentMan->getDownloadLength()-torrentMan->getCompletedLength();
+    selectedTotalLength = torrentMan->getSelectedTotalLength();
   }
 }
 
@@ -95,9 +96,9 @@ void TorrentConsoleDownloadEngine::calculateStatistics() {
   torrentMan->resetDeltaDownloadLength();
   torrentMan->resetDeltaUploadLength();
 
-  if(torrentMan->isPartialDownloadingMode()) {
-    downloadLength = torrentMan->getDownloadLength()-partialDownloadLengthDiff;
-    totalLength = partialTotalLength;
+  if(torrentMan->isSelectiveDownloadingMode()) {
+    downloadLength = torrentMan->getDownloadLength()-selectedDownloadLengthDiff;
+    totalLength = selectedTotalLength;
   } else {
     downloadLength = torrentMan->getDownloadLength();
     totalLength = torrentMan->getTotalLength();

+ 7 - 8
src/TorrentConsoleDownloadEngine.h

@@ -26,11 +26,6 @@
 
 class TorrentConsoleDownloadEngine : public TorrentDownloadEngine {
 private:
-  /*
-  struct timeval cp;
-  long long int sessionDownloadSize;
-  long long int sessionUploadSize;
-  */
   struct timeval cp[2];
   long long int sessionDownloadLengthArray[2];
   long long int sessionUploadLengthArray[2];
@@ -39,11 +34,15 @@ private:
   int downloadSpeed;
   int uploadSpeed;
   int lastElapsed;
-  long long int partialDownloadLengthDiff;
-  long long int partialTotalLength;
+  long long int selectedDownloadLengthDiff;
+  long long int selectedTotalLength;
+  // The time when startup
   struct timeval startup;
+  // The number of bytes downloaded since startup
   long long int sessionDownloadLength;
+  // The average speed(bytes per second) since startup
   int avgSpeed;
+  // The estimated remaining time to complete the download.
   int eta;
   long long int downloadLength;
   long long int totalLength;
@@ -53,7 +52,7 @@ private:
 protected:
   void initStatistics();
   void calculateStatistics();
-  void onPartialDownloadingCompletes();
+  void onSelectiveDownloadingCompletes();
 public:
   TorrentConsoleDownloadEngine();
   ~TorrentConsoleDownloadEngine();

+ 3 - 3
src/TorrentDownloadEngine.cc

@@ -22,7 +22,7 @@
 #include "TorrentDownloadEngine.h"
 
 void TorrentDownloadEngine::onEndOfRun() {
-  torrentMan->diskWriter->closeFile();
+  torrentMan->diskAdaptor->closeFile();
   if(filenameFixed && torrentMan->downloadComplete()) {
     torrentMan->remove();
   } else {
@@ -32,8 +32,8 @@ void TorrentDownloadEngine::onEndOfRun() {
 
 void TorrentDownloadEngine::afterEachIteration() {
   if(!filenameFixed && torrentMan->downloadComplete()) {
-    if(torrentMan->isPartialDownloadingMode()) {
-      onPartialDownloadingCompletes();
+    if(torrentMan->isSelectiveDownloadingMode()) {
+      onSelectiveDownloadingCompletes();
     }
     torrentMan->onDownloadComplete();
     if(torrentMan->downloadComplete()) {

+ 1 - 1
src/TorrentDownloadEngine.h

@@ -31,7 +31,7 @@ private:
 protected:
   void onEndOfRun();
   void afterEachIteration();
-  virtual void onPartialDownloadingCompletes() = 0;
+  virtual void onSelectiveDownloadingCompletes() = 0;
 public:
   TorrentDownloadEngine():filenameFixed(false) {}
   virtual ~TorrentDownloadEngine() {}

+ 58 - 156
src/TorrentMan.cc

@@ -32,6 +32,9 @@
 #include "DefaultDiskWriter.h"
 #include "MultiDiskWriter.h"
 #include "prefs.h"
+#include "CopyDiskAdaptor.h"
+#include "DirectDiskAdaptor.h"
+#include "MultiDiskAdaptor.h"
 #include <errno.h>
 #include <libgen.h>
 #include <string.h>
@@ -42,25 +45,21 @@ TorrentMan::TorrentMan():bitfield(NULL),
 			 preDownloadLength(0), preUploadLength(0),
 			 deltaDownloadLength(0), deltaUploadLength(0),
 			 storeDir("."),
-			 multiFileTopDir(NULL),
 			 setupComplete(false),
 			 interval(DEFAULT_ANNOUNCE_INTERVAL),
 			 minInterval(DEFAULT_ANNOUNCE_MIN_INTERVAL),
 			 complete(0), incomplete(0),
-			 connections(0), diskWriter(NULL) {}
+			 connections(0), diskAdaptor(NULL) {}
 
 TorrentMan::~TorrentMan() {
   if(bitfield != NULL) {
     delete bitfield;
   }
-  if(multiFileTopDir != NULL) {
-    delete multiFileTopDir;
-  }
   for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
     delete *itr;
   }
-  if(diskWriter != NULL) {
-    delete diskWriter;
+  if(diskAdaptor != NULL) {
+    delete diskAdaptor;
   }
 }
 
@@ -298,7 +297,7 @@ bool TorrentMan::downloadComplete() const {
   return bitfield->isAllBitSet();
 }
 
-void TorrentMan::readFileEntry(const Dictionary* infoDic, const string& defaultName) {
+void TorrentMan::readFileEntry(FileEntries& fileEntries, Directory** pTopDir, const Dictionary* infoDic, const string& defaultName) {
   Data* topName = (Data*)infoDic->get("name");
   if(topName != NULL) {
     name = topName->toString();
@@ -313,12 +312,14 @@ void TorrentMan::readFileEntry(const Dictionary* infoDic, const string& defaultN
     setFileMode(SINGLE);
     Data* length = (Data*)infoDic->get("length");
     totalLength = length->toLLInt();
+    FileEntry fileEntry(name, totalLength, 0);
+    fileEntries.push_back(fileEntry);
   } else {
     long long int length = 0;
     long long int offset = 0;
     // multi-file mode
     setFileMode(MULTI);
-    multiFileTopDir = new Directory(name);
+    *pTopDir = new Directory(name);
     const MetaList& metaList = files->getList();
     for(MetaList::const_iterator itr = metaList.begin(); itr != metaList.end();
 	itr++) {
@@ -327,7 +328,7 @@ void TorrentMan::readFileEntry(const Dictionary* infoDic, const string& defaultN
       length += lengthData->toLLInt();
       List* path = (List*)fileDic->get("path");
       const MetaList& paths = path->getList();
-      Directory* parentDir = multiFileTopDir;
+      Directory* parentDir = *pTopDir;
       string filePath = name;
       for(int i = 0; i < (int)paths.size()-1; i++) {
 	Data* subpath = (Data*)paths.at(i);
@@ -339,14 +340,14 @@ void TorrentMan::readFileEntry(const Dictionary* infoDic, const string& defaultN
       Data* lastpath = (Data*)paths.back();
       filePath.append("/").append(lastpath->toString());
       FileEntry fileEntry(filePath, lengthData->toLLInt(), offset);
-      multiFileEntries.push_back(fileEntry);
+      fileEntries.push_back(fileEntry);
       offset += fileEntry.length;
     }
     totalLength = length;
   }
 }
 
-void TorrentMan::setup(string metaInfoFile) {
+void TorrentMan::setup(string metaInfoFile, const Strings& targetFilePaths) {
   peerId = "-A2****-";
   for(int i = 0; i < 12; i++) {
     peerId += Util::itos((int)(((double)10)*random()/(RAND_MAX+1.0)));
@@ -363,7 +364,9 @@ void TorrentMan::setup(string metaInfoFile) {
   v.getHash(md, len);
   setInfoHash(md);
 
-  readFileEntry(infoDic, metaInfoFile);
+  FileEntries fileEntries;
+  Directory* topDir = NULL;
+  readFileEntry(fileEntries, &topDir, infoDic, metaInfoFile);
 
   announce = ((Data*)topDic->get("announce"))->toString();
   pieceLength = ((Data*)infoDic->get("piece length"))->toInt();
@@ -380,45 +383,54 @@ void TorrentMan::setup(string metaInfoFile) {
 
   initBitfield();
   delete topDic;
-}
 
-void TorrentMan::setupDiskWriter() {
   if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) {
-    if(segmentFileExists()) {
-      load();
-    }
     if(fileMode == SINGLE) {
-      diskWriter = new DefaultDiskWriter();
+      diskAdaptor = new DirectDiskAdaptor(new DefaultDiskWriter(totalLength));
     } else {
-      diskWriter = new MultiDiskWriter();
-      ((MultiDiskWriter*)diskWriter)->setMultiFileEntries(multiFileEntries, pieceLength);
-      multiFileTopDir->createDir(storeDir, true);
+      diskAdaptor = new MultiDiskAdaptor(new MultiDiskWriter(pieceLength));
     }
-    diskWriter->openFile(getFilePath());
   } else {
-    if(option->get(PREF_NO_PREALLOCATION) == V_TRUE) {
-      diskWriter = new DefaultDiskWriter();
-    } else {
-      diskWriter = new PreAllocationDiskWriter(totalLength);
-    }
-    if(segmentFileExists()) {
-      load();
-      diskWriter->openExistingFile(getTempFilePath());
-    } else {
-      diskWriter->initAndOpenFile(getTempFilePath());
-    }
+    diskAdaptor = new CopyDiskAdaptor(new DefaultDiskWriter(totalLength));
+    ((CopyDiskAdaptor*)diskAdaptor)->setTempFilename(name+".a2tmp");
+  }
+  diskAdaptor->setStoreDir(storeDir);
+  diskAdaptor->setTopDir(topDir);
+  diskAdaptor->setFileEntries(fileEntries);
+  setFileFilter(targetFilePaths);
+  if(segmentFileExists()) {
+    load();
+    diskAdaptor->openExistingFile();
+  } else {
+    diskAdaptor->initAndOpenFile();
   }
   setupComplete = true;
 }
 
-const MultiFileEntries& TorrentMan::getMultiFileEntries() const {
-  return multiFileEntries;
+void TorrentMan::setFileFilter(const Strings& filePaths) {
+  if(fileMode != MULTI || filePaths.empty()) {
+    return;
+  }
+  diskAdaptor->removeAllDownloadEntry();
+  for(Strings::const_iterator pitr = filePaths.begin();
+      pitr != filePaths.end(); pitr++) {
+    if(!diskAdaptor->addDownloadEntry(*pitr)) {
+      throw new DlAbortEx("no such file entry <%s>", (*pitr).c_str());
+    }
+    FileEntry fileEntry = diskAdaptor->getFileEntryFromPath(*pitr);
+    bitfield->addFilter(fileEntry.offset, fileEntry.length);
+  }
+  bitfield->enableFilter();
 }
 
-void TorrentMan::readFileEntryFromMetaInfoFile(const string& metaInfoFile) {
+FileEntries TorrentMan::readFileEntryFromMetaInfoFile(const string& metaInfoFile) {
   Dictionary* topDic = (Dictionary*)MetaFileUtil::parseMetaFile(metaInfoFile);
   const Dictionary* infoDic = (const Dictionary*)topDic->get("info");
-  readFileEntry(infoDic, metaInfoFile);
+  FileEntries fileEntries;
+  Directory* topDir;
+  readFileEntry(fileEntries, &topDir, infoDic, metaInfoFile);
+  delete topDir;
+  return fileEntries;
 }
 
 string TorrentMan::getName() const {
@@ -433,28 +445,8 @@ string TorrentMan::getPieceHash(int index) const {
   return pieceHashes.at(index);
 }
 
-string TorrentMan::getFilePath() const {
-  if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE && fileMode == MULTI) {
-    return storeDir;
-  } else {
-    return storeDir+"/"+name;
-  }
-}
-
-string TorrentMan::getTempFilePath() const {
-  if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) {
-    return getFilePath();
-  } else {
-    return getFilePath()+".a2tmp";
-  }
-}
-
 string TorrentMan::getSegmentFilePath() const {
-  if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE && fileMode == MULTI) {
-    return storeDir+"/"+name+".aria2";
-  } else {
-    return getFilePath()+".aria2";
-  }
+  return storeDir+"/"+name+".aria2";
 }
 
 bool TorrentMan::segmentFileExists() const {
@@ -546,117 +538,27 @@ void TorrentMan::remove() const {
   }
 }
 
-void TorrentMan::fixFilename() {
-  if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) {
-    // nothing to do here
-  } else {
-    if(fileMode == SINGLE) {
-      copySingleFile();
-    } else {
-      splitMultiFile();
-    }
-  }
-}
-
-void TorrentMan::copySingleFile() const {
-  logger->info("writing file %s", getFilePath().c_str());
-  Util::fileCopy(getFilePath(), getTempFilePath());
-}
-
-void TorrentMan::splitMultiFile() {
-  logger->info("creating directories");
-  multiFileTopDir->createDir(storeDir, true);
-  long long int offset = 0;
-  for(MultiFileEntries::iterator itr = multiFileEntries.begin();
-      itr != multiFileEntries.end(); itr++) {
-    if(!itr->extracted && itr->requested) {
-      string dest = storeDir+"/"+itr->path;
-      logger->info("writing file %s", dest.c_str());
-      Util::rangedFileCopy(dest, getTempFilePath(), offset, itr->length);
-      itr->extracted = true;
-    }
-    offset += itr->length;
-  }
-}
-
-void TorrentMan::deleteTempFile() const {
-  if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) {
-    // nothing to do here
-  } else {
-    unlink(getTempFilePath().c_str());
-  }
-}
-
-// bool TorrentMan::unextractedFileEntryExists() const {
-//   if(fileMode == SINGLE) {
-//     return false;
-//   }
-//   for(MultiFileEntries::const_iterator itr = multiFileEntries.begin();
-//       itr != multiFileEntries.end(); itr++) {
-//     if(!itr->extracted) {
-//       return true;
-//     }
-//   }
-// }
-
-void TorrentMan::setFileEntriesToDownload(const Strings& filePaths) {
-  if(fileMode != MULTI) {
-    throw new DlAbortEx("only multi-mode supports partial downloading mode.");
-  }
-  // clear all requested flags in multiFileEntries.
-  setAllMultiFileRequestedState(false);
-  for(Strings::const_iterator pitr = filePaths.begin();
-      pitr != filePaths.end(); pitr++) {
-    bool found = false;
-    for(MultiFileEntries::iterator itr = multiFileEntries.begin();
-	itr != multiFileEntries.end(); itr++) {
-      if(*pitr == itr->path) {
-	itr->requested = true;
-	found = true;
-	bitfield->addFilter(itr->offset, itr->length);
-	break;
-      }
-    }
-    if(!found) {
-      throw new DlAbortEx("no such file entry <%s>", (*pitr).c_str());
-    }
-  }
-  bitfield->enableFilter();
-}
-
-bool TorrentMan::isPartialDownloadingMode() const {
+bool TorrentMan::isSelectiveDownloadingMode() const {
   return bitfield->isFilterEnabled();
 }
 
-void TorrentMan::setAllMultiFileRequestedState(bool state) {
-  for(MultiFileEntries::iterator itr = multiFileEntries.begin();
-      itr != multiFileEntries.end(); itr++) {
-    itr->requested = state;
-  }  
-}
-
-void TorrentMan::finishPartialDownloadingMode() {
+void TorrentMan::finishSelectiveDownloadingMode() {
   bitfield->clearFilter();
-  setAllMultiFileRequestedState(true);
-  if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE && fileMode == MULTI) {
-    ((MultiDiskWriter*)diskWriter)->setMultiFileEntries(multiFileEntries, pieceLength);
-  }
+  diskAdaptor->addAllDownloadEntry();
 }
 
 long long int TorrentMan::getCompletedLength() const {
   return bitfield->getCompletedLength();
 }
 
-long long int TorrentMan::getPartialTotalLength() const {
+long long int TorrentMan::getSelectedTotalLength() const {
   return bitfield->getFilteredTotalLength();
 }
 
 void TorrentMan::onDownloadComplete() {
-  diskWriter->closeFile();
   save();
-  fixFilename();
-  if(isPartialDownloadingMode()) {
-    finishPartialDownloadingMode();
+  diskAdaptor->onDownloadComplete();
+  if(isSelectiveDownloadingMode()) {
+    finishSelectiveDownloadingMode();
   }
-  diskWriter->openFile(getTempFilePath());
 }

+ 10 - 33
src/TorrentMan.h

@@ -28,9 +28,10 @@
 #include "BitfieldMan.h"
 #include "DiskWriter.h"
 #include "Piece.h"
-#include "Directory.h"
 #include "Dictionary.h"
 #include "Option.h"
+#include "FileEntry.h"
+#include "DiskAdaptor.h"
 #include <deque>
 #include <map>
 #include <string>
@@ -46,22 +47,8 @@ using namespace std;
 #define END_GAME_PIECE_NUM 20
 #define MAX_PEER_ERROR 5
 
-class FileEntry {
-public:
-  string path;
-  long long int length;
-  long long int offset;
-  bool extracted;
-  bool requested;
-  FileEntry(string path, long long int length, long long int offset):
-    path(path), length(length), offset(offset),
-    extracted(false), requested(true) {}
-  ~FileEntry() {}
-};
-
 typedef deque<Peer*> Peers;
 typedef multimap<int, int> Haves;
-typedef deque<FileEntry> MultiFileEntries;
 typedef deque<Piece> UsedPieces;
 typedef deque<int> PieceIndexes;
 
@@ -85,8 +72,6 @@ private:
   int port;
   Haves haves;
   UsedPieces usedPieces;
-  Directory* multiFileTopDir;
-  MultiFileEntries multiFileEntries;
   bool setupComplete;
 
   FILE* openSegFile(string segFilename, string mode) const;
@@ -97,7 +82,8 @@ private:
   void deleteUsedPiece(const Piece& piece);
   int deleteUsedPiecesByFillRate(int fillRate, int toDelete);
   void reduceUsedPieces(int max);
-  void readFileEntry(const Dictionary* infoDic, const string& defaultName);
+  void readFileEntry(FileEntries& fileEntries, Directory** pTopDir, const Dictionary* infoDic, const string& defaultName);
+  void setFileFilter(const Strings& filePaths);
 public:
   int pieceLength;
   int pieces;
@@ -115,7 +101,7 @@ public:
   ~TorrentMan();
 
   const Logger* logger;
-  DiskWriter* diskWriter;
+  DiskAdaptor* diskAdaptor;
   const Option* option;
 
   int getNewCuid() { return ++cuidCounter; }
@@ -150,8 +136,7 @@ public:
     return infoHash;
   }
 
-  void setup(string metaInfoFile);
-  void setupDiskWriter();
+  void setup(string metaInfoFile, const Strings& targetFilePaths);
 
   string getPieceHash(int index) const;
 
@@ -213,8 +198,6 @@ public:
   string getStoreDir() const { return storeDir; }
   void setStoreDir(string dir) { storeDir = dir; }
 
-  string getFilePath() const;
-  string getTempFilePath() const;
   string getSegmentFilePath() const;
 
   bool segmentFileExists() const;  
@@ -233,20 +216,14 @@ public:
   int countUsedPiece() const { return usedPieces.size(); }
   int countAdvertisedPiece() const { return haves.size(); }
 
-  void readFileEntryFromMetaInfoFile(const string& metaInfoFile);
-  const MultiFileEntries& getMultiFileEntries() const;
+  FileEntries readFileEntryFromMetaInfoFile(const string& metaInfoFile);
   string getName() const;
 
-  //bool unextractedFileEntryExists() const;
-  
-  void setAllMultiFileRequestedState(bool state);
-  void finishPartialDownloadingMode();
-  bool isPartialDownloadingMode() const;
-
-  void setFileEntriesToDownload(const Strings& filePaths);
+  void finishSelectiveDownloadingMode();
+  bool isSelectiveDownloadingMode() const;
 
   long long int getCompletedLength() const;
-  long long int getPartialTotalLength() const;
+  long long int getSelectedTotalLength() const;
 
   void onDownloadComplete();
 

+ 21 - 28
src/main.cc

@@ -63,6 +63,10 @@ void printDownloadCompeleteMessage(string filename) {
   printf(_("\nThe download was complete. <%s>\n"), filename.c_str());
 }
 
+void printDownloadCompeleteMessage() {
+  printf("\nThe download was complete.\n");
+}
+
 void printDownloadAbortMessage() {
   printf(_("\nThe download was not complete because of errors. Check the log.\n"));
 }
@@ -85,13 +89,13 @@ void handler(int signal) {
 
 void torrentHandler(int signal) {
   cout << _("\nSIGINT signal received.") << endl;
-  if(te->torrentMan->diskWriter != NULL) {
-    te->torrentMan->diskWriter->closeFile();
+  if(te->torrentMan->diskAdaptor != NULL) {
+    te->torrentMan->diskAdaptor->closeFile();
   }
   if(te->torrentMan->downloadComplete() && te->isFilenameFixed()) {
     te->torrentMan->remove();
-    te->torrentMan->deleteTempFile();
-    printDownloadCompeleteMessage(te->torrentMan->getFilePath());
+    //te->torrentMan->deleteTempFile();
+    printDownloadCompeleteMessage();
   } else {
     te->torrentMan->save();
   }
@@ -283,7 +287,7 @@ int main(int argc, char* argv[]) {
 #ifdef ENABLE_BITTORRENT
       { "torrent-file", required_argument, &lopt, 15 },
       { "follow-torrent", required_argument, &lopt, 16 },
-      { "torrent-show-files", no_argument, &lopt, 17 },
+      { "show-files", no_argument, &lopt, 17 },
       { "no-preallocation", no_argument, &lopt, 18 },
       { "direct-file-mapping", required_argument, &lopt, 19 },
 #endif // ENABLE_BITTORRENT
@@ -414,7 +418,7 @@ int main(int argc, char* argv[]) {
 	}
 	break;
       case 17:
-	op->put(PREF_TORRENT_SHOW_FILES, V_TRUE);
+	op->put(PREF_SHOW_FILES, V_TRUE);
 	break;
       case 18:
 	op->put(PREF_NO_PREALLOCATION, V_TRUE);
@@ -608,32 +612,21 @@ int main(int argc, char* argv[]) {
       te->torrentMan->option = op;
       string targetTorrentFile = torrentFile.empty() ?
 	downloadedTorrentFile : torrentFile;
-      if(op->get(PREF_TORRENT_SHOW_FILES) == V_TRUE) {
-	te->torrentMan->readFileEntryFromMetaInfoFile(targetTorrentFile);
+      if(op->get(PREF_SHOW_FILES) == V_TRUE) {
+	FileEntries fileEntries = te->torrentMan->readFileEntryFromMetaInfoFile(targetTorrentFile);
 	cout << "Files:" << endl;
-	switch(te->torrentMan->getFileMode()) {
-	case TorrentMan::SINGLE:
-	  printf("%s %s Bytes\n", te->torrentMan->getName().c_str(),
-		 Util::llitos(te->torrentMan->getTotalLength(), true).c_str());
-	  break;
-	case TorrentMan::MULTI: {
-	  const MultiFileEntries& entries = te->torrentMan->getMultiFileEntries();
-	  for(MultiFileEntries::const_iterator itr = entries.begin();
-	      itr != entries.end(); itr++) {
-	    printf("%s %s Bytes\n", itr->path.c_str(),
-		   Util::llitos(itr->length, true).c_str());
-	  }
-	  break;
-	}
+	for(FileEntries::const_iterator itr = fileEntries.begin();
+	    itr != fileEntries.end(); itr++) {
+	  printf("%s %s Bytes\n", itr->path.c_str(),
+		 Util::llitos(itr->length, true).c_str());
 	}
 	exit(0);
       } else {
-	te->torrentMan->setup(targetTorrentFile);
-	if(!torrentFile.empty() && !args.empty() &&
-	   te->torrentMan->getFileMode() == TorrentMan::MULTI) {
-	  te->torrentMan->setFileEntriesToDownload(args);
+	Strings targetFiles;
+	if(!torrentFile.empty() && !args.empty()) {
+	  targetFiles = args;
 	}
-	te->torrentMan->setupDiskWriter();
+	te->torrentMan->setup(targetTorrentFile, targetFiles);
       }
       PeerListenCommand* listenCommand =
 	new PeerListenCommand(te->torrentMan->getNewCuid(), te);
@@ -652,7 +645,7 @@ int main(int argc, char* argv[]) {
       te->run();
       
       if(te->torrentMan->downloadComplete()) {
-	printDownloadCompeleteMessage(te->torrentMan->getFilePath());
+	printDownloadCompeleteMessage();
       } else {
 	printDownloadAbortMessage();
       }

+ 1 - 1
src/prefs.h

@@ -89,7 +89,7 @@
 // values: 1*digit
 #define PREF_PEER_CONNECTION_TIMEOUT "peer_connection_timeout"
 // values: true | false
-#define PREF_TORRENT_SHOW_FILES "torrent_show_files"
+#define PREF_SHOW_FILES "show_files"
 // values: true | false
 #define PREF_NO_PREALLOCATION "no_preallocation"
 // values: true | false

+ 10 - 10
test/MultiDiskWriterTest.cc

@@ -25,14 +25,14 @@ public:
 
 CPPUNIT_TEST_SUITE_REGISTRATION( MultiDiskWriterTest );
 
-MultiFileEntries createEntries() {
+FileEntries createEntries() {
   FileEntry entry1("file1.txt", 15, 0);
   FileEntry entry2("file2.txt", 7, 15);
   FileEntry entry3("file3.txt", 3, 22);
   unlink("file1.txt");
   unlink("file2.txt");
   unlink("file3.txt");
-  MultiFileEntries entries;
+  FileEntries entries;
   entries.push_back(entry1);
   entries.push_back(entry2);
   entries.push_back(entry3);
@@ -52,8 +52,8 @@ void readFile(const string& filename, char* buf, int bufLength) {
 }
 
 void MultiDiskWriterTest::testWriteData() {
-  MultiDiskWriter dw;
-  dw.setMultiFileEntries(createEntries(), 2);
+  MultiDiskWriter dw(2);
+  dw.setFileEntries(createEntries());
 
   dw.openFile(".");
   string msg = "12345";
@@ -97,12 +97,12 @@ void MultiDiskWriterTest::testReadData() {
   FileEntry entry1("file1r.txt", 15, 0);
   FileEntry entry2("file2r.txt", 7, 15);
   FileEntry entry3("file3r.txt", 3, 22);
-  MultiFileEntries entries;
+  FileEntries entries;
   entries.push_back(entry1);
   entries.push_back(entry2);
   entries.push_back(entry3);
-  MultiDiskWriter dw;
-  dw.setMultiFileEntries(entries, 2);
+  MultiDiskWriter dw(2);
+  dw.setFileEntries(entries);
 
   dw.openFile(".");
   char buf[128];
@@ -124,12 +124,12 @@ void MultiDiskWriterTest::testSha1Sum() {
   FileEntry entry1("file1r.txt", 15, 0);
   FileEntry entry2("file2r.txt", 7, 15);
   FileEntry entry3("file3r.txt", 3, 22);
-  MultiFileEntries entries;
+  FileEntries entries;
   entries.push_back(entry1);
   entries.push_back(entry2);
   entries.push_back(entry3);
-  MultiDiskWriter dw;
-  dw.setMultiFileEntries(entries, 2);
+  MultiDiskWriter dw(2);
+  dw.setFileEntries(entries);
 
   dw.openFile(".");
   string sha1sum = dw.sha1Sum(0, 25);