mirror of https://github.com/aria2/aria2
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.pull/1/head
parent
58633887e9
commit
2a84b9de43
68
ChangeLog
68
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
|
||||
|
|
12
TODO
12
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_
|
|
@ -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@\
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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,92 +37,49 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// filename is a directory which is specified by the user in the option.
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiDiskWriter::closeFile() {
|
||||
for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
|
||||
itr != diskWriterEntries.end(); itr++) {
|
||||
if((*itr)->enabled) {
|
||||
(*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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiDiskWriter::writeData(const char* data, int len, long long int position) {
|
||||
|
@ -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;
|
||||
|
|
|
@ -30,18 +30,13 @@ 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef deque<DiskWriterEntry*> DiskWriterEntries;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -274,7 +274,7 @@ 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(),
|
||||
e->torrentMan->diskAdaptor->writeData(message->getBlock(),
|
||||
message->getBlockLength(),
|
||||
offset);
|
||||
piece.completeBlock(slot.getBlockIndex());
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ PreAllocationDiskWriter::~PreAllocationDiskWriter() {}
|
|||
|
||||
void PreAllocationDiskWriter::initAndOpenFile(string filename) {
|
||||
createFile(filename);
|
||||
|
||||
int bufSize = 4096;
|
||||
char buf[4096];
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -31,7 +31,7 @@ private:
|
|||
protected:
|
||||
void onEndOfRun();
|
||||
void afterEachIteration();
|
||||
virtual void onPartialDownloadingCompletes() = 0;
|
||||
virtual void onSelectiveDownloadingCompletes() = 0;
|
||||
public:
|
||||
TorrentDownloadEngine():filenameFixed(false) {}
|
||||
virtual ~TorrentDownloadEngine() {}
|
||||
|
|
|
@ -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);
|
||||
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();
|
||||
diskWriter->openExistingFile(getTempFilePath());
|
||||
diskAdaptor->openExistingFile();
|
||||
} else {
|
||||
diskWriter->initAndOpenFile(getTempFilePath());
|
||||
}
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
45
src/main.cc
45
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++) {
|
||||
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());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue