mirror of https://github.com/aria2/aria2
2006-04-12 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
To add the ability to download multi torrent into respective files directly: * src/DiskWriter.h (openFile): New function. (seek): Removed. * src/MultiDiskWriter.h: New class. * src/MultiDiskWriter.cc: New class. * src/AbstractDiskWriter.h (seek): Changed its scope from public to protected. (openFile): New function. * src/AbstractDiskWriter.cc (openFile): New function. * src/prefs.h (V_FALSE): New definition. (PREF_DIRECT_FILE_MAPPING): New definition. * src/TorrentMan.h (setupDiskWriter): New function. (setAllMultiFileRequestedState): New function. (onDownloadComplete): New function. * src/TorrentMan.cc : Included MultiDiskWriter.h (setupDiskWriter): New function. (getFilePath): Updated. (getTempFilePath): Updated. (getSegmentFilePath): Updated. (fixFilename): Updated. (deleteTempFile): Updated. (setAllMultiFileRequestedState): New function. (setFileEntriesToDownload): Use setAllMultiFileRequestedState(). (finishPartialDownloadingMode): Reset requested flags. (onDownloadComplete): New function. * src/main.cc: Added --direct-file-mapping option. Use TorretMan::setupDiskWriter(). * src/TorrentDownloadEngine.cc (afterEachIteration): Use TorrentMan:: onDownloadComplete(). To fix ETA bug: * src/Util.h (difftvsec): New function. * src/Util.cc (difftvsec): New function. * src/TorrentConsoleDownloadEngine.cc (calculateSpeed): Use int for the type of "elapsed" instead of long long int. (calculateStatistics): Use Util::difftvsec instead of Util::difftv. The updates of statistics takes place every 1 seconds. * src/TorrentConsoleDownloadEngine.h (lastElapsed): Changed its type. (calculateSpeed): Changed its argument signature. * src/PeerMessage.cc (toString): Fixed message.pull/1/head
parent
305aad8690
commit
2f4b3f7d02
48
ChangeLog
48
ChangeLog
|
@ -1,3 +1,51 @@
|
|||
2006-04-12 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||
|
||||
To add the ability to download multi torrent into respective files
|
||||
directly:
|
||||
|
||||
* src/DiskWriter.h (openFile): New function.
|
||||
(seek): Removed.
|
||||
* src/MultiDiskWriter.h: New class.
|
||||
* src/MultiDiskWriter.cc: New class.
|
||||
* src/AbstractDiskWriter.h (seek): Changed its scope from public to
|
||||
protected.
|
||||
(openFile): New function.
|
||||
* src/AbstractDiskWriter.cc (openFile): New function.
|
||||
* src/prefs.h (V_FALSE): New definition.
|
||||
(PREF_DIRECT_FILE_MAPPING): New definition.
|
||||
* src/TorrentMan.h (setupDiskWriter): New function.
|
||||
(setAllMultiFileRequestedState): New function.
|
||||
(onDownloadComplete): New function.
|
||||
* src/TorrentMan.cc : Included MultiDiskWriter.h
|
||||
(setupDiskWriter): New function.
|
||||
(getFilePath): Updated.
|
||||
(getTempFilePath): Updated.
|
||||
(getSegmentFilePath): Updated.
|
||||
(fixFilename): Updated.
|
||||
(deleteTempFile): Updated.
|
||||
(setAllMultiFileRequestedState): New function.
|
||||
(setFileEntriesToDownload): Use setAllMultiFileRequestedState().
|
||||
(finishPartialDownloadingMode): Reset requested flags.
|
||||
(onDownloadComplete): New function.
|
||||
* src/main.cc: Added --direct-file-mapping option.
|
||||
Use TorretMan::setupDiskWriter().
|
||||
* src/TorrentDownloadEngine.cc (afterEachIteration): Use TorrentMan::
|
||||
onDownloadComplete().
|
||||
|
||||
|
||||
To fix ETA bug:
|
||||
|
||||
* src/Util.h (difftvsec): New function.
|
||||
* src/Util.cc (difftvsec): New function.
|
||||
* src/TorrentConsoleDownloadEngine.cc (calculateSpeed): Use int for the
|
||||
type of "elapsed" instead of long long int.
|
||||
(calculateStatistics): Use Util::difftvsec instead of Util::difftv.
|
||||
The updates of statistics takes place every 1 seconds.
|
||||
* src/TorrentConsoleDownloadEngine.h (lastElapsed): Changed its type.
|
||||
(calculateSpeed): Changed its argument signature.
|
||||
|
||||
* src/PeerMessage.cc (toString): Fixed message.
|
||||
|
||||
2006-04-06 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||
|
||||
To print ETA:
|
||||
|
|
1
TODO
1
TODO
|
@ -13,3 +13,4 @@
|
|||
* Distinguish seeder from leecher
|
||||
* file selection in multi-file mode
|
||||
* try to use ftruncate to allocate file.
|
||||
* fix TorrentMan::getFilePath()
|
|
@ -44,6 +44,12 @@ AbstractDiskWriter::~AbstractDiskWriter() {
|
|||
#endif // ENABLE_SHA1DIGEST
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractDiskWriter::closeFile() {
|
||||
if(fd != 0) {
|
||||
close(fd);
|
||||
|
|
|
@ -39,18 +39,21 @@ protected:
|
|||
|
||||
void writeDataInternal(const char* data, int len);
|
||||
int readDataInternal(char* data, int len);
|
||||
|
||||
void seek(long long int offset);
|
||||
|
||||
public:
|
||||
AbstractDiskWriter();
|
||||
virtual ~AbstractDiskWriter();
|
||||
|
||||
void openFile(const string& filename);
|
||||
|
||||
void closeFile();
|
||||
|
||||
void openExistingFile(string filename);
|
||||
|
||||
string sha1Sum(long long int offset, long long int length);
|
||||
|
||||
void seek(long long int offset);
|
||||
|
||||
void writeData(const char* data, int len, long long int offset);
|
||||
|
||||
int readData(char* data, int len, long long int offset);
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
*/
|
||||
virtual void initAndOpenFile(string filename) = 0;
|
||||
|
||||
virtual void openFile(const string& filename) = 0;
|
||||
|
||||
/**
|
||||
* Closes this output stream.
|
||||
*/
|
||||
|
@ -69,7 +71,6 @@ public:
|
|||
|
||||
virtual string sha1Sum(long long int offset, long long int length) = 0;
|
||||
|
||||
virtual void seek(long long int offset) = 0;
|
||||
};
|
||||
|
||||
#endif // _D_DISK_WRITER_H_
|
||||
|
|
|
@ -78,7 +78,8 @@ SRCS = Socket.cc Socket.h\
|
|||
Directory.cc Directory.h\
|
||||
TrackerWatcherCommand.cc TrackerWatcherCommand.h\
|
||||
messageDigest.h\
|
||||
SendMessageQueue.cc SendMessageQueue.h
|
||||
SendMessageQueue.cc SendMessageQueue.h\
|
||||
MultiDiskWriter.cc MultiDiskWriter.h
|
||||
noinst_LIBRARIES = libaria2c.a
|
||||
libaria2c_a_SOURCES = $(SRCS)
|
||||
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
|
||||
|
|
|
@ -98,7 +98,7 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \
|
|||
PeerMessage.$(OBJEXT) Piece.$(OBJEXT) RequestSlot.$(OBJEXT) \
|
||||
RequestSlotMan.$(OBJEXT) TorrentAutoSaveCommand.$(OBJEXT) \
|
||||
Directory.$(OBJEXT) TrackerWatcherCommand.$(OBJEXT) \
|
||||
SendMessageQueue.$(OBJEXT)
|
||||
SendMessageQueue.$(OBJEXT) MultiDiskWriter.$(OBJEXT)
|
||||
am_libaria2c_a_OBJECTS = $(am__objects_1)
|
||||
libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
|
||||
am__installdirs = "$(DESTDIR)$(bindir)"
|
||||
|
@ -326,7 +326,8 @@ SRCS = Socket.cc Socket.h\
|
|||
Directory.cc Directory.h\
|
||||
TrackerWatcherCommand.cc TrackerWatcherCommand.h\
|
||||
messageDigest.h\
|
||||
SendMessageQueue.cc SendMessageQueue.h
|
||||
SendMessageQueue.cc SendMessageQueue.h\
|
||||
MultiDiskWriter.cc MultiDiskWriter.h
|
||||
|
||||
noinst_LIBRARIES = libaria2c.a
|
||||
libaria2c_a_SOURCES = $(SRCS)
|
||||
|
@ -443,6 +444,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)/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@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerAbstractCommand.Po@am__quote@
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/* <!-- 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 --> */
|
||||
#include "MultiDiskWriter.h"
|
||||
#include "DlAbortEx.h"
|
||||
#include "Util.h"
|
||||
#include <errno.h>
|
||||
|
||||
MultiDiskWriter::MultiDiskWriter() {
|
||||
#ifdef ENABLE_SHA1DIGEST
|
||||
sha1DigestInit(ctx);
|
||||
#endif // ENABLE_SHA1DIGEST
|
||||
}
|
||||
|
||||
MultiDiskWriter::~MultiDiskWriter() {
|
||||
clearEntries();
|
||||
#ifdef ENABLE_SHA1DIGEST
|
||||
sha1DigestFree(ctx);
|
||||
#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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
long long int offset = position;
|
||||
long long int fileOffset = offset;
|
||||
bool writing = false;
|
||||
int rem = len;
|
||||
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;
|
||||
writing = true;
|
||||
fileOffset = 0;
|
||||
} else {
|
||||
fileOffset -= (*itr)->fileEntry.length;
|
||||
}
|
||||
}
|
||||
if(!writing) {
|
||||
throw new DlAbortEx("offset out of range");
|
||||
}
|
||||
}
|
||||
|
||||
bool MultiDiskWriter::isInRange(const DiskWriterEntry* entry, long long int offset) const {
|
||||
return entry->fileEntry.offset <= offset &&
|
||||
offset < entry->fileEntry.offset+entry->fileEntry.length;
|
||||
}
|
||||
|
||||
int MultiDiskWriter::calculateLength(const DiskWriterEntry* entry, long long int fileOffset, int rem) const {
|
||||
int length;
|
||||
if(entry->fileEntry.length < fileOffset+rem) {
|
||||
length = entry->fileEntry.length-fileOffset;
|
||||
} else {
|
||||
length = rem;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int MultiDiskWriter::readData(char* data, int len, long long int position) {
|
||||
long long int offset = position;
|
||||
long long int fileOffset = offset;
|
||||
bool reading = false;
|
||||
int rem = len;
|
||||
int totalReadLength = 0;
|
||||
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;
|
||||
reading = true;
|
||||
fileOffset = 0;
|
||||
} else {
|
||||
fileOffset -= (*itr)->fileEntry.length;
|
||||
}
|
||||
}
|
||||
if(!reading) {
|
||||
throw new DlAbortEx("offset out of range");
|
||||
}
|
||||
return totalReadLength;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SHA1DIGEST
|
||||
void MultiDiskWriter::hashUpdate(const DiskWriterEntry* entry, long long int offset, long long int length) const {
|
||||
int BUFSIZE = 16*1024;
|
||||
char buf[BUFSIZE];
|
||||
for(int i = 0; i < length/BUFSIZE; i++) {
|
||||
if(BUFSIZE != entry->diskWriter->readData(buf, BUFSIZE, offset)) {
|
||||
throw "error";
|
||||
}
|
||||
sha1DigestUpdate(ctx, buf, BUFSIZE);
|
||||
offset += BUFSIZE;
|
||||
}
|
||||
int r = length%BUFSIZE;
|
||||
if(r > 0) {
|
||||
if(r != entry->diskWriter->readData(buf, r, offset)) {
|
||||
throw "error";
|
||||
}
|
||||
sha1DigestUpdate(ctx, buf, r);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_SHA1DIGEST
|
||||
|
||||
string MultiDiskWriter::sha1Sum(long long int offset, long long int length) {
|
||||
#ifdef ENABLE_SHA1DIGEST
|
||||
long long int fileOffset = offset;
|
||||
bool reading = false;
|
||||
int rem = length;
|
||||
sha1DigestReset(ctx);
|
||||
try {
|
||||
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;
|
||||
reading = true;
|
||||
fileOffset = 0;
|
||||
} else {
|
||||
fileOffset -= (*itr)->fileEntry.length;
|
||||
}
|
||||
}
|
||||
if(!reading) {
|
||||
throw new DlAbortEx("offset out of range");
|
||||
}
|
||||
unsigned char hashValue[20];
|
||||
sha1DigestFinal(ctx, hashValue);
|
||||
return Util::toHex(hashValue, 20);
|
||||
} catch(string ex) {
|
||||
throw new DlAbortEx(strerror(errno));
|
||||
}
|
||||
#else
|
||||
return "";
|
||||
#endif // ENABLE_SHA1DIGEST
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/* <!-- 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_MULTI_DISK_WRITER_H_
|
||||
#define _D_MULTI_DISK_WRITER_H_
|
||||
|
||||
#include "DefaultDiskWriter.h"
|
||||
#include "TorrentMan.h"
|
||||
#include "messageDigest.h"
|
||||
|
||||
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() {
|
||||
if(enabled) {
|
||||
delete diskWriter;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef deque<DiskWriterEntry*> DiskWriterEntries;
|
||||
|
||||
class MultiDiskWriter : public DiskWriter {
|
||||
private:
|
||||
DiskWriterEntries diskWriterEntries;
|
||||
|
||||
bool isInRange(const DiskWriterEntry* entry, long long int offset) const;
|
||||
int calculateLength(const DiskWriterEntry* entry, long long int fileOffset, int rem) const;
|
||||
void clearEntries();
|
||||
#ifdef ENABLE_SHA1DIGEST
|
||||
MessageDigestContext ctx;
|
||||
void hashUpdate(const DiskWriterEntry* entry, long long int offset, long long int length) const;
|
||||
#endif // ENABLE_SHA1DIGEST
|
||||
|
||||
public:
|
||||
MultiDiskWriter();
|
||||
virtual ~MultiDiskWriter();
|
||||
|
||||
void setMultiFileEntries(const MultiFileEntries& multiFileEntries, int pieceLength);
|
||||
|
||||
virtual void openFile(const string& filename);
|
||||
virtual void initAndOpenFile(string filename);
|
||||
virtual void closeFile();
|
||||
virtual void openExistingFile(string filename);
|
||||
virtual void writeData(const char* data, int len, long long int position = 0);
|
||||
virtual int readData(char* data, int len, long long int position);
|
||||
virtual string sha1Sum(long long int offset, long long int length);
|
||||
};
|
||||
|
||||
#endif // _D_MULTI_DISK_WRITER_H_
|
|
@ -61,7 +61,7 @@ string PeerMessage::toString() const {
|
|||
return "piece index="+Util::itos(index)+", begin="+Util::itos(begin)+
|
||||
", length="+Util::itos(blockLength);
|
||||
case CANCEL:
|
||||
return "calcel index="+Util::itos(index)+", begin="+Util::itos(begin)+
|
||||
return "cancel index="+Util::itos(index)+", begin="+Util::itos(begin)+
|
||||
", length="+Util::itos(length);
|
||||
case KEEP_ALIVE:
|
||||
return "keep alive";
|
||||
|
|
|
@ -74,15 +74,15 @@ void TorrentConsoleDownloadEngine::initStatistics() {
|
|||
}
|
||||
}
|
||||
|
||||
int TorrentConsoleDownloadEngine::calculateSpeed(long long int sessionLength, long long int elapsed) {
|
||||
int nowSpeed = (int)(sessionLength/(elapsed/1000000.0));
|
||||
int TorrentConsoleDownloadEngine::calculateSpeed(long long int sessionLength, int elapsed) {
|
||||
int nowSpeed = (int)(sessionLength/(elapsed*1.0));
|
||||
return nowSpeed;
|
||||
}
|
||||
|
||||
void TorrentConsoleDownloadEngine::calculateStatistics() {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
long long int elapsed = Util::difftv(now, cp[currentCp]);
|
||||
int elapsed = Util::difftvsec(now, cp[currentCp]);
|
||||
|
||||
sessionDownloadLengthArray[0] += torrentMan->getDeltaDownloadLength();
|
||||
sessionUploadLengthArray[0] += torrentMan->getDeltaUploadLength();
|
||||
|
@ -91,8 +91,6 @@ void TorrentConsoleDownloadEngine::calculateStatistics() {
|
|||
|
||||
sessionDownloadLength += torrentMan->getDeltaDownloadLength();
|
||||
|
||||
downloadSpeed = calculateSpeed(sessionDownloadLengthArray[currentCp], elapsed);
|
||||
uploadSpeed = calculateSpeed(sessionUploadLengthArray[currentCp], elapsed);
|
||||
|
||||
torrentMan->resetDeltaDownloadLength();
|
||||
torrentMan->resetDeltaUploadLength();
|
||||
|
@ -105,18 +103,23 @@ void TorrentConsoleDownloadEngine::calculateStatistics() {
|
|||
totalLength = torrentMan->getTotalLength();
|
||||
}
|
||||
|
||||
|
||||
if(elapsed-lastElapsed >= 1) {
|
||||
downloadSpeed = calculateSpeed(sessionDownloadLengthArray[currentCp], elapsed);
|
||||
uploadSpeed = calculateSpeed(sessionUploadLengthArray[currentCp], elapsed);
|
||||
avgSpeed = calculateSpeed(sessionDownloadLength,
|
||||
Util::difftv(now, startup));
|
||||
if(avgSpeed != 0) {
|
||||
Util::difftvsec(now, startup));
|
||||
if(avgSpeed < 0) {
|
||||
avgSpeed = 0;
|
||||
} else if(avgSpeed != 0) {
|
||||
eta = (totalLength-downloadLength)/avgSpeed;
|
||||
}
|
||||
|
||||
if(elapsed-lastElapsed >= 1000000) {
|
||||
printStatistics();
|
||||
lastElapsed = elapsed;
|
||||
}
|
||||
|
||||
if(elapsed > 15*1000000) {
|
||||
if(elapsed > 15) {
|
||||
sessionDownloadLengthArray[currentCp] = 0;
|
||||
sessionUploadLengthArray[currentCp] = 0;
|
||||
cp[currentCp] = now;
|
||||
|
|
|
@ -38,7 +38,7 @@ private:
|
|||
|
||||
int downloadSpeed;
|
||||
int uploadSpeed;
|
||||
long long int lastElapsed;
|
||||
int lastElapsed;
|
||||
long long int partialDownloadLengthDiff;
|
||||
long long int partialTotalLength;
|
||||
struct timeval startup;
|
||||
|
@ -49,7 +49,7 @@ private:
|
|||
long long int totalLength;
|
||||
|
||||
void printStatistics();
|
||||
int calculateSpeed(long long int sessionLength, long long int elapsed);
|
||||
int calculateSpeed(long long int sessionLength, int elapsed);
|
||||
protected:
|
||||
void initStatistics();
|
||||
void calculateStatistics();
|
||||
|
|
|
@ -32,18 +32,12 @@ void TorrentDownloadEngine::onEndOfRun() {
|
|||
|
||||
void TorrentDownloadEngine::afterEachIteration() {
|
||||
if(!filenameFixed && torrentMan->downloadComplete()) {
|
||||
torrentMan->diskWriter->closeFile();
|
||||
torrentMan->save();
|
||||
torrentMan->fixFilename();
|
||||
if(torrentMan->isPartialDownloadingMode()) {
|
||||
torrentMan->finishPartialDownloadingMode();
|
||||
onPartialDownloadingCompletes();
|
||||
}
|
||||
torrentMan->onDownloadComplete();
|
||||
if(torrentMan->downloadComplete()) {
|
||||
filenameFixed = true;
|
||||
}
|
||||
} else {
|
||||
filenameFixed = true;
|
||||
}
|
||||
torrentMan->diskWriter->openExistingFile(torrentMan->getTempFilePath());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "message.h"
|
||||
#include "PreAllocationDiskWriter.h"
|
||||
#include "DefaultDiskWriter.h"
|
||||
#include "MultiDiskWriter.h"
|
||||
#include "prefs.h"
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
|
@ -379,7 +380,22 @@ 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();
|
||||
} else {
|
||||
diskWriter = new MultiDiskWriter();
|
||||
((MultiDiskWriter*)diskWriter)->setMultiFileEntries(multiFileEntries, pieceLength);
|
||||
multiFileTopDir->createDir(storeDir, true);
|
||||
}
|
||||
diskWriter->openFile(getFilePath());
|
||||
} else {
|
||||
if(option->get(PREF_NO_PREALLOCATION) == V_TRUE) {
|
||||
diskWriter = new DefaultDiskWriter();
|
||||
} else {
|
||||
|
@ -391,6 +407,7 @@ void TorrentMan::setup(string metaInfoFile) {
|
|||
} else {
|
||||
diskWriter->initAndOpenFile(getTempFilePath());
|
||||
}
|
||||
}
|
||||
setupComplete = true;
|
||||
}
|
||||
|
||||
|
@ -417,15 +434,27 @@ string TorrentMan::getPieceHash(int index) const {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -518,11 +547,15 @@ 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 {
|
||||
|
@ -547,7 +580,11 @@ void TorrentMan::splitMultiFile() {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -567,10 +604,7 @@ void TorrentMan::setFileEntriesToDownload(const Strings& filePaths) {
|
|||
throw new DlAbortEx("only multi-mode supports partial downloading mode.");
|
||||
}
|
||||
// clear all requested flags in multiFileEntries.
|
||||
for(MultiFileEntries::iterator itr = multiFileEntries.begin();
|
||||
itr != multiFileEntries.end(); itr++) {
|
||||
itr->requested = false;
|
||||
}
|
||||
setAllMultiFileRequestedState(false);
|
||||
for(Strings::const_iterator pitr = filePaths.begin();
|
||||
pitr != filePaths.end(); pitr++) {
|
||||
bool found = false;
|
||||
|
@ -594,8 +628,19 @@ bool TorrentMan::isPartialDownloadingMode() 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() {
|
||||
bitfield->clearFilter();
|
||||
setAllMultiFileRequestedState(true);
|
||||
if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE && fileMode == MULTI) {
|
||||
((MultiDiskWriter*)diskWriter)->setMultiFileEntries(multiFileEntries, pieceLength);
|
||||
}
|
||||
}
|
||||
|
||||
long long int TorrentMan::getCompletedLength() const {
|
||||
|
@ -605,3 +650,13 @@ long long int TorrentMan::getCompletedLength() const {
|
|||
long long int TorrentMan::getPartialTotalLength() const {
|
||||
return bitfield->getFilteredTotalLength();
|
||||
}
|
||||
|
||||
void TorrentMan::onDownloadComplete() {
|
||||
diskWriter->closeFile();
|
||||
save();
|
||||
fixFilename();
|
||||
if(isPartialDownloadingMode()) {
|
||||
finishPartialDownloadingMode();
|
||||
}
|
||||
diskWriter->openFile(getTempFilePath());
|
||||
}
|
||||
|
|
|
@ -151,6 +151,7 @@ public:
|
|||
}
|
||||
|
||||
void setup(string metaInfoFile);
|
||||
void setupDiskWriter();
|
||||
|
||||
string getPieceHash(int index) const;
|
||||
|
||||
|
@ -238,6 +239,7 @@ public:
|
|||
|
||||
//bool unextractedFileEntryExists() const;
|
||||
|
||||
void setAllMultiFileRequestedState(bool state);
|
||||
void finishPartialDownloadingMode();
|
||||
bool isPartialDownloadingMode() const;
|
||||
|
||||
|
@ -246,6 +248,8 @@ public:
|
|||
long long int getCompletedLength() const;
|
||||
long long int getPartialTotalLength() const;
|
||||
|
||||
void onDownloadComplete();
|
||||
|
||||
enum FILE_MODE {
|
||||
SINGLE,
|
||||
MULTI
|
||||
|
|
|
@ -90,6 +90,13 @@ long long int Util::difftv(struct timeval tv1, struct timeval tv2) {
|
|||
tv1.tv_usec-tv2.tv_usec);
|
||||
}
|
||||
|
||||
int Util::difftvsec(struct timeval tv1, struct timeval tv2) {
|
||||
if(tv1.tv_sec < tv2.tv_sec) {
|
||||
return 0;
|
||||
}
|
||||
return tv1.tv_sec-tv2.tv_sec;
|
||||
}
|
||||
|
||||
void Util::slice(Strings& result, const string& src, char delim) {
|
||||
string::size_type p = 0;
|
||||
while(1) {
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
* If tv1 is older than tv2, then this method returns 0.
|
||||
*/
|
||||
static long long int difftv(struct timeval tv1, struct timeval tv2);
|
||||
static int difftvsec(struct timeval tv1, struct timeval tv2);
|
||||
/**
|
||||
* Take a string src which is a deliminated list and add its elements
|
||||
* into result. result is not cleared before conversion begins.
|
||||
|
|
13
src/main.cc
13
src/main.cc
|
@ -252,6 +252,7 @@ int main(int argc, char* argv[]) {
|
|||
op->put(PREF_FTP_TYPE, V_BINARY);
|
||||
op->put(PREF_FTP_VIA_HTTP_PROXY, V_TUNNEL);
|
||||
op->put(PREF_AUTO_SAVE_INTERVAL, "60");
|
||||
op->put(PREF_DIRECT_FILE_MAPPING, V_TRUE);
|
||||
|
||||
while(1) {
|
||||
int optIndex = 0;
|
||||
|
@ -284,6 +285,7 @@ int main(int argc, char* argv[]) {
|
|||
{ "follow-torrent", required_argument, &lopt, 16 },
|
||||
{ "torrent-show-files", no_argument, &lopt, 17 },
|
||||
{ "no-preallocation", no_argument, &lopt, 18 },
|
||||
{ "direct-file-mapping", required_argument, &lopt, 19 },
|
||||
#endif // ENABLE_BITTORRENT
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
|
@ -417,6 +419,16 @@ int main(int argc, char* argv[]) {
|
|||
case 18:
|
||||
op->put(PREF_NO_PREALLOCATION, V_TRUE);
|
||||
break;
|
||||
case 19:
|
||||
if(string(optarg) == "true") {
|
||||
op->put(PREF_DIRECT_FILE_MAPPING, V_TRUE);
|
||||
} else if(string(optarg) == "false") {
|
||||
op->put(PREF_DIRECT_FILE_MAPPING, V_FALSE);
|
||||
} else {
|
||||
cerr << "direct-file-mapping must be either 'true' or 'false'." << endl;
|
||||
showUsage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -621,6 +633,7 @@ int main(int argc, char* argv[]) {
|
|||
te->torrentMan->getFileMode() == TorrentMan::MULTI) {
|
||||
te->torrentMan->setFileEntriesToDownload(args);
|
||||
}
|
||||
te->torrentMan->setupDiskWriter();
|
||||
}
|
||||
PeerListenCommand* listenCommand =
|
||||
new PeerListenCommand(te->torrentMan->getNewCuid(), te);
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* Constants
|
||||
*/
|
||||
#define V_TRUE "true"
|
||||
//#define V_FALSE "false"
|
||||
#define V_FALSE "false"
|
||||
|
||||
/**
|
||||
* General preferences
|
||||
|
@ -92,4 +92,7 @@
|
|||
#define PREF_TORRENT_SHOW_FILES "torrent_show_files"
|
||||
// values: true | false
|
||||
#define PREF_NO_PREALLOCATION "no_preallocation"
|
||||
// values: true | false
|
||||
#define PREF_DIRECT_FILE_MAPPING "direct_file_mapping"
|
||||
|
||||
#endif // _D_PREFS_H_
|
||||
|
|
|
@ -16,7 +16,8 @@ aria2c_SOURCES = AllTest.cc\
|
|||
TorrentManTest.cc\
|
||||
PeerMessageUtilTest.cc\
|
||||
BitfieldManTest.cc\
|
||||
DefaultDiskWriterTest.cc
|
||||
DefaultDiskWriterTest.cc\
|
||||
MultiDiskWriterTest.cc
|
||||
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
||||
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
||||
|
||||
|
|
|
@ -63,7 +63,8 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \
|
|||
DictionaryTest.$(OBJEXT) ListTest.$(OBJEXT) \
|
||||
MetaFileUtilTest.$(OBJEXT) ShaVisitorTest.$(OBJEXT) \
|
||||
TorrentManTest.$(OBJEXT) PeerMessageUtilTest.$(OBJEXT) \
|
||||
BitfieldManTest.$(OBJEXT) DefaultDiskWriterTest.$(OBJEXT)
|
||||
BitfieldManTest.$(OBJEXT) DefaultDiskWriterTest.$(OBJEXT) \
|
||||
MultiDiskWriterTest.$(OBJEXT)
|
||||
aria2c_OBJECTS = $(am_aria2c_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
|
||||
|
@ -220,7 +221,8 @@ aria2c_SOURCES = AllTest.cc\
|
|||
TorrentManTest.cc\
|
||||
PeerMessageUtilTest.cc\
|
||||
BitfieldManTest.cc\
|
||||
DefaultDiskWriterTest.cc
|
||||
DefaultDiskWriterTest.cc\
|
||||
MultiDiskWriterTest.cc
|
||||
|
||||
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
||||
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
||||
|
@ -292,6 +294,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ListTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetaFileUtilTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskWriterTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerMessageUtilTest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestTest.Po@am__quote@
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
#include "MultiDiskWriter.h"
|
||||
#include <string>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MultiDiskWriterTest:public CppUnit::TestFixture {
|
||||
|
||||
CPPUNIT_TEST_SUITE(MultiDiskWriterTest);
|
||||
CPPUNIT_TEST(testWriteData);
|
||||
CPPUNIT_TEST(testReadData);
|
||||
CPPUNIT_TEST(testSha1Sum);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
private:
|
||||
|
||||
public:
|
||||
void setUp() {
|
||||
}
|
||||
|
||||
void testWriteData();
|
||||
void testReadData();
|
||||
void testSha1Sum();
|
||||
};
|
||||
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION( MultiDiskWriterTest );
|
||||
|
||||
MultiFileEntries 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;
|
||||
entries.push_back(entry1);
|
||||
entries.push_back(entry2);
|
||||
entries.push_back(entry3);
|
||||
return entries;
|
||||
}
|
||||
|
||||
void readFile(const string& filename, char* buf, int bufLength) {
|
||||
FILE* f = fopen(filename.c_str(), "r");
|
||||
if(f == NULL) {
|
||||
abort();
|
||||
}
|
||||
int retval = fread(buf, bufLength, 1, f);
|
||||
fclose(f);
|
||||
if(retval != 1) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void MultiDiskWriterTest::testWriteData() {
|
||||
MultiDiskWriter dw;
|
||||
dw.setMultiFileEntries(createEntries(), 2);
|
||||
|
||||
dw.openFile(".");
|
||||
string msg = "12345";
|
||||
dw.writeData(msg.c_str(), msg.size(), 0);
|
||||
dw.closeFile();
|
||||
|
||||
char buf[128];
|
||||
readFile("file1.txt", buf, 5);
|
||||
buf[5] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(msg, string(buf));
|
||||
|
||||
dw.openFile(".");
|
||||
string msg2 = "67890ABCDEF";
|
||||
dw.writeData(msg2.c_str(), msg2.size(), 5);
|
||||
dw.closeFile();
|
||||
|
||||
readFile("file1.txt", buf, 15);
|
||||
buf[15] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("1234567890ABCDE"), string(buf));
|
||||
readFile("file2.txt", buf, 1);
|
||||
buf[1] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("F"), string(buf));
|
||||
|
||||
dw.openFile(".");
|
||||
string msg3 = "12345123456712";
|
||||
dw.writeData(msg3.c_str(), msg3.size(), 10);
|
||||
dw.closeFile();
|
||||
|
||||
readFile("file1.txt", buf, 15);
|
||||
buf[15] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("123456789012345"), string(buf));
|
||||
readFile("file2.txt", buf, 7);
|
||||
buf[7] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("1234567"), string(buf));
|
||||
readFile("file3.txt", buf, 2);
|
||||
buf[2] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("12"), string(buf));
|
||||
}
|
||||
|
||||
void MultiDiskWriterTest::testReadData() {
|
||||
FileEntry entry1("file1r.txt", 15, 0);
|
||||
FileEntry entry2("file2r.txt", 7, 15);
|
||||
FileEntry entry3("file3r.txt", 3, 22);
|
||||
MultiFileEntries entries;
|
||||
entries.push_back(entry1);
|
||||
entries.push_back(entry2);
|
||||
entries.push_back(entry3);
|
||||
MultiDiskWriter dw;
|
||||
dw.setMultiFileEntries(entries, 2);
|
||||
|
||||
dw.openFile(".");
|
||||
char buf[128];
|
||||
dw.readData(buf, 15, 0);
|
||||
buf[15] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("1234567890ABCDE"), string(buf));
|
||||
dw.readData(buf, 10, 6);
|
||||
buf[10] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("7890ABCDEF"), string(buf));
|
||||
dw.readData(buf, 4, 20);
|
||||
buf[4] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("KLMN"), string(buf));
|
||||
dw.readData(buf, 25, 0);
|
||||
buf[25] = '\0';
|
||||
CPPUNIT_ASSERT_EQUAL(string("1234567890ABCDEFGHIJKLMNO"), string(buf));
|
||||
}
|
||||
|
||||
void MultiDiskWriterTest::testSha1Sum() {
|
||||
FileEntry entry1("file1r.txt", 15, 0);
|
||||
FileEntry entry2("file2r.txt", 7, 15);
|
||||
FileEntry entry3("file3r.txt", 3, 22);
|
||||
MultiFileEntries entries;
|
||||
entries.push_back(entry1);
|
||||
entries.push_back(entry2);
|
||||
entries.push_back(entry3);
|
||||
MultiDiskWriter dw;
|
||||
dw.setMultiFileEntries(entries, 2);
|
||||
|
||||
dw.openFile(".");
|
||||
string sha1sum = dw.sha1Sum(0, 25);
|
||||
CPPUNIT_ASSERT_EQUAL(string("76495faf71ca63df66dce99547d2c58da7266d9e"), sha1sum);
|
||||
sha1sum = dw.sha1Sum(15, 7);
|
||||
CPPUNIT_ASSERT_EQUAL(string("737660d816fb23c2d5bc74f62d9b01b852b2aaca"), sha1sum);
|
||||
sha1sum = dw.sha1Sum(10, 14);
|
||||
CPPUNIT_ASSERT_EQUAL(string("6238bf61dd8df8f77156b2378e9e39cd3939680c"), sha1sum);
|
||||
dw.closeFile();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
1234567890ABCDE
|
|
@ -0,0 +1 @@
|
|||
FGHIJKL
|
|
@ -0,0 +1 @@
|
|||
MNO
|
Loading…
Reference in New Issue