mirror of https://github.com/aria2/aria2
2009-03-07 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added --index-out option to specify each file path for torrent. Here index shown in --show-files option is used to specify which file path should be altered. For example, to change the file path with index=2, use --index-out=2=aria2.tar.bz2. You can use this option multiple times: --index-out=1=aria2.tar.bz2 --index-out=2=aria2-opt.tar.bz2. The short hand form -O is also available. This option can be specified in -i list. * src/DefaultBtContext.cc * src/DefaultBtContext.h * src/MultiDiskAdaptor.cc * src/MultiDiskAdaptor.h * src/MultiFileAllocationIterator.cc * src/OptionHandlerFactory.cc * src/OptionHandlerImpl.h * src/Util.cc * src/Util.h * src/download_helper.cc * src/prefs.cc * src/prefs.h * src/usage_text.h * test/DefaultBtContextTest.cc * test/MultiDiskAdaptorTest.cc * test/MultiFileAllocationIteratorTest.cc * test/UtilTest.ccpull/1/head
parent
4aae48c9b2
commit
f44554a634
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
||||||
|
2009-03-07 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
|
Added --index-out option to specify each file path for torrent.
|
||||||
|
Here index shown in --show-files option is used to specify which
|
||||||
|
file path should be altered. For example, to change the file path
|
||||||
|
with index=2, use --index-out=2=aria2.tar.bz2. You can use this
|
||||||
|
option multiple times: --index-out=1=aria2.tar.bz2
|
||||||
|
--index-out=2=aria2-opt.tar.bz2. The short hand form -O is also
|
||||||
|
available. This option can be specified in -i list.
|
||||||
|
* src/DefaultBtContext.cc
|
||||||
|
* src/DefaultBtContext.h
|
||||||
|
* src/MultiDiskAdaptor.cc
|
||||||
|
* src/MultiDiskAdaptor.h
|
||||||
|
* src/MultiFileAllocationIterator.cc
|
||||||
|
* src/OptionHandlerFactory.cc
|
||||||
|
* src/OptionHandlerImpl.h
|
||||||
|
* src/Util.cc
|
||||||
|
* src/Util.h
|
||||||
|
* src/download_helper.cc
|
||||||
|
* src/prefs.cc
|
||||||
|
* src/prefs.h
|
||||||
|
* src/usage_text.h
|
||||||
|
* test/DefaultBtContextTest.cc
|
||||||
|
* test/MultiDiskAdaptorTest.cc
|
||||||
|
* test/MultiFileAllocationIteratorTest.cc
|
||||||
|
* test/UtilTest.cc
|
||||||
|
|
||||||
2009-03-05 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
2009-03-05 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
Use Util::pathJoin()
|
Use Util::pathJoin()
|
||||||
|
|
|
@ -151,14 +151,20 @@ void DefaultBtContext::extractFileEntries(const bencode::BDE& infoDict,
|
||||||
throw DlAbortEx("Path is empty.");
|
throw DlAbortEx("Path is empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> elements(pathList.size());
|
std::vector<std::string> pathelem(pathList.size());
|
||||||
std::transform(pathList.listBegin(), pathList.listEnd(), elements.begin(),
|
std::transform(pathList.listBegin(), pathList.listEnd(), pathelem.begin(),
|
||||||
std::mem_fun_ref(&bencode::BDE::s));
|
std::mem_fun_ref(&bencode::BDE::s));
|
||||||
std::string path = Util::joinPath(elements.begin(), elements.end());
|
std::string path = Util::joinPath(pathelem.begin(), pathelem.end());
|
||||||
|
// Split path with '/' again because each pathList element can
|
||||||
|
// contain "/" inside.
|
||||||
|
std::deque<std::string> elements;
|
||||||
|
Util::slice(elements, path, '/');
|
||||||
|
elements.push_front(name);
|
||||||
|
path = Util::joinPath(elements.begin(), elements.end());
|
||||||
|
|
||||||
std::deque<std::string> uris;
|
std::deque<std::string> uris;
|
||||||
std::transform(urlList.begin(), urlList.end(), std::back_inserter(uris),
|
std::transform(urlList.begin(), urlList.end(), std::back_inserter(uris),
|
||||||
std::bind2nd(std::plus<std::string>(), "/"+name+"/"+path));
|
std::bind2nd(std::plus<std::string>(), "/"+path));
|
||||||
FileEntryHandle fileEntry(new FileEntry(path, fileLengthData.i(),
|
FileEntryHandle fileEntry(new FileEntry(path, fileLengthData.i(),
|
||||||
offset, uris));
|
offset, uris));
|
||||||
fileEntries.push_back(fileEntry);
|
fileEntries.push_back(fileEntry);
|
||||||
|
@ -475,4 +481,15 @@ void DefaultBtContext::setInfoHash(const unsigned char* infoHash)
|
||||||
memcpy(this->infoHash, infoHash, sizeof(this->infoHash));
|
memcpy(this->infoHash, infoHash, sizeof(this->infoHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DefaultBtContext::setFilePathWithIndex
|
||||||
|
(size_t index, const std::string& path)
|
||||||
|
{
|
||||||
|
if(0 < index && index <= fileEntries.size()) {
|
||||||
|
fileEntries[index-1]->setPath(path);
|
||||||
|
} else {
|
||||||
|
throw DlAbortEx(StringFormat("No such file with index=%u",
|
||||||
|
static_cast<unsigned int>(index)).str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -182,6 +182,12 @@ private:
|
||||||
|
|
||||||
void setRandomizer(const SharedHandle<Randomizer>& randomizer);
|
void setRandomizer(const SharedHandle<Randomizer>& randomizer);
|
||||||
|
|
||||||
|
// Sets file path for spcified index. index starts from 1. The index
|
||||||
|
// is the same used in BtContext::setFileFilter(). Please note that
|
||||||
|
// path is not the actual file path. The actual file path is
|
||||||
|
// getDir()+"/"+path.
|
||||||
|
void setFilePathWithIndex(size_t index, const std::string& path);
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& o, const DefaultBtContext& ctx);
|
friend std::ostream& operator<<(std::ostream& o, const DefaultBtContext& ctx);
|
||||||
|
|
||||||
static const std::string DEFAULT_PEER_ID_PREFIX;
|
static const std::string DEFAULT_PEER_ID_PREFIX;
|
||||||
|
|
|
@ -58,15 +58,15 @@ DiskWriterEntry::DiskWriterEntry(const SharedHandle<FileEntry>& fileEntry):
|
||||||
|
|
||||||
DiskWriterEntry::~DiskWriterEntry() {}
|
DiskWriterEntry::~DiskWriterEntry() {}
|
||||||
|
|
||||||
std::string DiskWriterEntry::getFilePath(const std::string& topDir) const
|
std::string DiskWriterEntry::getFilePath(const std::string& storeDir) const
|
||||||
{
|
{
|
||||||
return topDir+"/"+fileEntry->getPath();
|
return storeDir+"/"+fileEntry->getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskWriterEntry::initAndOpenFile(const std::string& topDir)
|
void DiskWriterEntry::initAndOpenFile(const std::string& storeDir)
|
||||||
{
|
{
|
||||||
if(!diskWriter.isNull()) {
|
if(!diskWriter.isNull()) {
|
||||||
diskWriter->initAndOpenFile(getFilePath(topDir), fileEntry->getLength());
|
diskWriter->initAndOpenFile(getFilePath(storeDir), fileEntry->getLength());
|
||||||
if(_directIO) {
|
if(_directIO) {
|
||||||
diskWriter->enableDirectIO();
|
diskWriter->enableDirectIO();
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,10 @@ void DiskWriterEntry::initAndOpenFile(const std::string& topDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskWriterEntry::openFile(const std::string& topDir)
|
void DiskWriterEntry::openFile(const std::string& storeDir)
|
||||||
{
|
{
|
||||||
if(!diskWriter.isNull()) {
|
if(!diskWriter.isNull()) {
|
||||||
diskWriter->openFile(getFilePath(topDir), fileEntry->getLength());
|
diskWriter->openFile(getFilePath(storeDir), fileEntry->getLength());
|
||||||
if(_directIO) {
|
if(_directIO) {
|
||||||
diskWriter->enableDirectIO();
|
diskWriter->enableDirectIO();
|
||||||
}
|
}
|
||||||
|
@ -85,10 +85,10 @@ void DiskWriterEntry::openFile(const std::string& topDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskWriterEntry::openExistingFile(const std::string& topDir)
|
void DiskWriterEntry::openExistingFile(const std::string& storeDir)
|
||||||
{
|
{
|
||||||
if(!diskWriter.isNull()) {
|
if(!diskWriter.isNull()) {
|
||||||
diskWriter->openExistingFile(getFilePath(topDir), fileEntry->getLength());
|
diskWriter->openExistingFile(getFilePath(storeDir), fileEntry->getLength());
|
||||||
if(_directIO) {
|
if(_directIO) {
|
||||||
diskWriter->enableDirectIO();
|
diskWriter->enableDirectIO();
|
||||||
}
|
}
|
||||||
|
@ -109,9 +109,9 @@ void DiskWriterEntry::closeFile()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiskWriterEntry::fileExists(const std::string& topDir)
|
bool DiskWriterEntry::fileExists(const std::string& storeDir)
|
||||||
{
|
{
|
||||||
return File(getFilePath(topDir)).exists();
|
return File(getFilePath(storeDir)).exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t DiskWriterEntry::size() const
|
uint64_t DiskWriterEntry::size() const
|
||||||
|
@ -270,9 +270,9 @@ void MultiDiskAdaptor::resetDiskWriterEntries()
|
||||||
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
|
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
|
||||||
if((*i)->needsFileAllocation() ||
|
if((*i)->needsFileAllocation() ||
|
||||||
dwreq.find((*i)->getFileEntry()->getPath()) != dwreq.end() ||
|
dwreq.find((*i)->getFileEntry()->getPath()) != dwreq.end() ||
|
||||||
(*i)->fileExists(getTopDirPath())) {
|
(*i)->fileExists(storeDir)) {
|
||||||
logger->debug("Creating DiskWriter for filename=%s",
|
logger->debug("Creating DiskWriter for filename=%s",
|
||||||
(*i)->getFilePath(getTopDirPath()).c_str());
|
(*i)->getFilePath(storeDir).c_str());
|
||||||
(*i)->setDiskWriter(dwFactory.newDiskWriter());
|
(*i)->setDiskWriter(dwFactory.newDiskWriter());
|
||||||
(*i)->getDiskWriter()->setDirectIOAllowed(_directIOAllowed);
|
(*i)->getDiskWriter()->setDirectIOAllowed(_directIOAllowed);
|
||||||
if(_readOnly) {
|
if(_readOnly) {
|
||||||
|
@ -287,25 +287,25 @@ std::string MultiDiskAdaptor::getTopDirPath() const
|
||||||
return storeDir+"/"+topDir;
|
return storeDir+"/"+topDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiDiskAdaptor::mkdir(const std::string& topDirPath) const
|
void MultiDiskAdaptor::mkdir(const std::string& storeDir) const
|
||||||
{
|
{
|
||||||
for(std::deque<SharedHandle<DiskWriterEntry> >::const_iterator i =
|
for(std::deque<SharedHandle<DiskWriterEntry> >::const_iterator i =
|
||||||
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
|
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
|
||||||
(*i)->getFileEntry()->setupDir(topDirPath);
|
(*i)->getFileEntry()->setupDir(storeDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiDiskAdaptor::openIfNot
|
void MultiDiskAdaptor::openIfNot
|
||||||
(const SharedHandle<DiskWriterEntry>& entry,
|
(const SharedHandle<DiskWriterEntry>& entry,
|
||||||
void (DiskWriterEntry::*open)(const std::string&),
|
void (DiskWriterEntry::*open)(const std::string&),
|
||||||
const std::string& topDirPath)
|
const std::string& storeDir)
|
||||||
{
|
{
|
||||||
if(!entry->isOpen()) {
|
if(!entry->isOpen()) {
|
||||||
// logger->debug("DiskWriterEntry: Cache MISS. offset=%s",
|
// logger->debug("DiskWriterEntry: Cache MISS. offset=%s",
|
||||||
// Util::itos(entry->getFileEntry()->getOffset()).c_str());
|
// Util::itos(entry->getFileEntry()->getOffset()).c_str());
|
||||||
|
|
||||||
size_t numOpened = _openedDiskWriterEntries.size();
|
size_t numOpened = _openedDiskWriterEntries.size();
|
||||||
(entry.get()->*open)(topDirPath);
|
(entry.get()->*open)(storeDir);
|
||||||
if(numOpened >= _maxOpenFiles) {
|
if(numOpened >= _maxOpenFiles) {
|
||||||
// Cache is full.
|
// Cache is full.
|
||||||
// Choose one DiskWriterEntry randomly and close it.
|
// Choose one DiskWriterEntry randomly and close it.
|
||||||
|
@ -326,32 +326,29 @@ void MultiDiskAdaptor::openIfNot
|
||||||
|
|
||||||
void MultiDiskAdaptor::openFile()
|
void MultiDiskAdaptor::openFile()
|
||||||
{
|
{
|
||||||
_cachedTopDirPath = getTopDirPath();
|
|
||||||
resetDiskWriterEntries();
|
resetDiskWriterEntries();
|
||||||
mkdir(_cachedTopDirPath);
|
mkdir(storeDir);
|
||||||
// Call DiskWriterEntry::openFile to make sure that zero-length files are
|
// Call DiskWriterEntry::openFile to make sure that zero-length files are
|
||||||
// created.
|
// created.
|
||||||
for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
|
for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
|
||||||
itr != diskWriterEntries.end(); ++itr) {
|
itr != diskWriterEntries.end(); ++itr) {
|
||||||
openIfNot(*itr, &DiskWriterEntry::openFile, _cachedTopDirPath);
|
openIfNot(*itr, &DiskWriterEntry::openFile, storeDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiDiskAdaptor::initAndOpenFile()
|
void MultiDiskAdaptor::initAndOpenFile()
|
||||||
{
|
{
|
||||||
_cachedTopDirPath = getTopDirPath();
|
|
||||||
resetDiskWriterEntries();
|
resetDiskWriterEntries();
|
||||||
mkdir(_cachedTopDirPath);
|
mkdir(storeDir);
|
||||||
// Call DiskWriterEntry::initAndOpenFile to make files truncated.
|
// Call DiskWriterEntry::initAndOpenFile to make files truncated.
|
||||||
for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
|
for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
|
||||||
itr != diskWriterEntries.end(); ++itr) {
|
itr != diskWriterEntries.end(); ++itr) {
|
||||||
openIfNot(*itr, &DiskWriterEntry::initAndOpenFile, _cachedTopDirPath);
|
openIfNot(*itr, &DiskWriterEntry::initAndOpenFile, storeDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiDiskAdaptor::openExistingFile()
|
void MultiDiskAdaptor::openExistingFile()
|
||||||
{
|
{
|
||||||
_cachedTopDirPath = getTopDirPath();
|
|
||||||
resetDiskWriterEntries();
|
resetDiskWriterEntries();
|
||||||
// Not need to call openIfNot here.
|
// Not need to call openIfNot here.
|
||||||
}
|
}
|
||||||
|
@ -416,12 +413,12 @@ findFirstDiskWriterEntry(const DiskWriterEntries& diskWriterEntries, off_t offse
|
||||||
|
|
||||||
static void throwOnDiskWriterNotOpened(const SharedHandle<DiskWriterEntry>& e,
|
static void throwOnDiskWriterNotOpened(const SharedHandle<DiskWriterEntry>& e,
|
||||||
off_t offset,
|
off_t offset,
|
||||||
const std::string& topDirPath)
|
const std::string& storeDir)
|
||||||
{
|
{
|
||||||
throw DlAbortEx
|
throw DlAbortEx
|
||||||
(StringFormat("DiskWriter for offset=%s, filename=%s is not opened.",
|
(StringFormat("DiskWriter for offset=%s, filename=%s is not opened.",
|
||||||
Util::itos(offset).c_str(),
|
Util::itos(offset).c_str(),
|
||||||
e->getFilePath(topDirPath).c_str()).str());
|
e->getFilePath(storeDir).c_str()).str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiDiskAdaptor::writeData(const unsigned char* data, size_t len,
|
void MultiDiskAdaptor::writeData(const unsigned char* data, size_t len,
|
||||||
|
@ -434,10 +431,10 @@ void MultiDiskAdaptor::writeData(const unsigned char* data, size_t len,
|
||||||
for(DiskWriterEntries::const_iterator i = first; i != diskWriterEntries.end(); ++i) {
|
for(DiskWriterEntries::const_iterator i = first; i != diskWriterEntries.end(); ++i) {
|
||||||
size_t writeLength = calculateLength(*i, fileOffset, rem);
|
size_t writeLength = calculateLength(*i, fileOffset, rem);
|
||||||
|
|
||||||
openIfNot(*i, &DiskWriterEntry::openFile, _cachedTopDirPath);
|
openIfNot(*i, &DiskWriterEntry::openFile, storeDir);
|
||||||
|
|
||||||
if(!(*i)->isOpen()) {
|
if(!(*i)->isOpen()) {
|
||||||
throwOnDiskWriterNotOpened(*i, offset+(len-rem), _cachedTopDirPath);
|
throwOnDiskWriterNotOpened(*i, offset+(len-rem), storeDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*i)->getDiskWriter()->writeData(data+(len-rem), writeLength, fileOffset);
|
(*i)->getDiskWriter()->writeData(data+(len-rem), writeLength, fileOffset);
|
||||||
|
@ -459,10 +456,10 @@ ssize_t MultiDiskAdaptor::readData(unsigned char* data, size_t len, off_t offset
|
||||||
for(DiskWriterEntries::const_iterator i = first; i != diskWriterEntries.end(); ++i) {
|
for(DiskWriterEntries::const_iterator i = first; i != diskWriterEntries.end(); ++i) {
|
||||||
size_t readLength = calculateLength(*i, fileOffset, rem);
|
size_t readLength = calculateLength(*i, fileOffset, rem);
|
||||||
|
|
||||||
openIfNot(*i, &DiskWriterEntry::openFile, _cachedTopDirPath);
|
openIfNot(*i, &DiskWriterEntry::openFile, storeDir);
|
||||||
|
|
||||||
if(!(*i)->isOpen()) {
|
if(!(*i)->isOpen()) {
|
||||||
throwOnDiskWriterNotOpened(*i, offset+(len-rem), _cachedTopDirPath);
|
throwOnDiskWriterNotOpened(*i, offset+(len-rem), storeDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
totalReadLength +=
|
totalReadLength +=
|
||||||
|
@ -478,12 +475,13 @@ ssize_t MultiDiskAdaptor::readData(unsigned char* data, size_t len, off_t offset
|
||||||
|
|
||||||
bool MultiDiskAdaptor::fileExists()
|
bool MultiDiskAdaptor::fileExists()
|
||||||
{
|
{
|
||||||
|
// TODO Use FileEntry::fileExists() here.
|
||||||
|
|
||||||
// Don't use _cachedTopDirPath because they are initialized after opening files.
|
// Don't use _cachedTopDirPath because they are initialized after opening files.
|
||||||
// This method could be called before opening files.
|
// This method could be called before opening files.
|
||||||
std::string topDirPath = getTopDirPath();
|
|
||||||
for(std::deque<SharedHandle<FileEntry> >::iterator i =
|
for(std::deque<SharedHandle<FileEntry> >::iterator i =
|
||||||
fileEntries.begin(); i != fileEntries.end(); ++i) {
|
fileEntries.begin(); i != fileEntries.end(); ++i) {
|
||||||
if(File(topDirPath+"/"+(*i)->getPath()).exists()) {
|
if(File(storeDir+"/"+(*i)->getPath()).exists()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,7 +494,7 @@ uint64_t MultiDiskAdaptor::size()
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
for(DiskWriterEntries::const_iterator itr = diskWriterEntries.begin();
|
for(DiskWriterEntries::const_iterator itr = diskWriterEntries.begin();
|
||||||
itr != diskWriterEntries.end(); ++itr) {
|
itr != diskWriterEntries.end(); ++itr) {
|
||||||
openIfNot(*itr, &DiskWriterEntry::openFile, _cachedTopDirPath);
|
openIfNot(*itr, &DiskWriterEntry::openFile, storeDir);
|
||||||
size += (*itr)->size();
|
size += (*itr)->size();
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
|
@ -538,9 +536,9 @@ void MultiDiskAdaptor::cutTrailingGarbage()
|
||||||
for(std::deque<SharedHandle<DiskWriterEntry> >::const_iterator i =
|
for(std::deque<SharedHandle<DiskWriterEntry> >::const_iterator i =
|
||||||
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
|
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
|
||||||
uint64_t length = (*i)->getFileEntry()->getLength();
|
uint64_t length = (*i)->getFileEntry()->getLength();
|
||||||
if(File((*i)->getFilePath(_cachedTopDirPath)).size() > length) {
|
if(File((*i)->getFilePath(storeDir)).size() > length) {
|
||||||
// We need open file before calling DiskWriter::truncate(uint64_t)
|
// We need open file before calling DiskWriter::truncate(uint64_t)
|
||||||
openIfNot(*i, &DiskWriterEntry::openFile, _cachedTopDirPath);
|
openIfNot(*i, &DiskWriterEntry::openFile, storeDir);
|
||||||
(*i)->getDiskWriter()->truncate(length);
|
(*i)->getDiskWriter()->truncate(length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,7 +555,7 @@ size_t MultiDiskAdaptor::utime(const Time& actime, const Time& modtime)
|
||||||
for(std::deque<SharedHandle<FileEntry> >::const_iterator i =
|
for(std::deque<SharedHandle<FileEntry> >::const_iterator i =
|
||||||
fileEntries.begin(); i != fileEntries.end(); ++i) {
|
fileEntries.begin(); i != fileEntries.end(); ++i) {
|
||||||
if((*i)->isRequested()) {
|
if((*i)->isRequested()) {
|
||||||
File f(getTopDirPath()+"/"+(*i)->getPath());
|
File f(storeDir+"/"+(*i)->getPath());
|
||||||
if(f.isFile() && f.utime(actime, modtime)) {
|
if(f.isFile() && f.utime(actime, modtime)) {
|
||||||
++numOK;
|
++numOK;
|
||||||
}
|
}
|
||||||
|
@ -572,4 +570,9 @@ MultiDiskAdaptor::getDiskWriterEntries() const
|
||||||
return diskWriterEntries;
|
return diskWriterEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& MultiDiskAdaptor::getStoreDir() const
|
||||||
|
{
|
||||||
|
return storeDir;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -55,19 +55,19 @@ public:
|
||||||
|
|
||||||
~DiskWriterEntry();
|
~DiskWriterEntry();
|
||||||
|
|
||||||
std::string getFilePath(const std::string& topDir) const;
|
std::string getFilePath(const std::string& storeDir) const;
|
||||||
|
|
||||||
void initAndOpenFile(const std::string& topDir);
|
void initAndOpenFile(const std::string& storeDir);
|
||||||
|
|
||||||
void openFile(const std::string& topDir);
|
void openFile(const std::string& storeDir);
|
||||||
|
|
||||||
void openExistingFile(const std::string& topDir);
|
void openExistingFile(const std::string& storeDir);
|
||||||
|
|
||||||
void closeFile();
|
void closeFile();
|
||||||
|
|
||||||
bool isOpen() const;
|
bool isOpen() const;
|
||||||
|
|
||||||
bool fileExists(const std::string& topDir);
|
bool fileExists(const std::string& storeDir);
|
||||||
|
|
||||||
uint64_t size() const;
|
uint64_t size() const;
|
||||||
|
|
||||||
|
@ -105,8 +105,6 @@ private:
|
||||||
size_t pieceLength;
|
size_t pieceLength;
|
||||||
DiskWriterEntries diskWriterEntries;
|
DiskWriterEntries diskWriterEntries;
|
||||||
|
|
||||||
std::string _cachedTopDirPath;
|
|
||||||
|
|
||||||
std::deque<SharedHandle<DiskWriterEntry> > _openedDiskWriterEntries;
|
std::deque<SharedHandle<DiskWriterEntry> > _openedDiskWriterEntries;
|
||||||
|
|
||||||
size_t _maxOpenFiles;
|
size_t _maxOpenFiles;
|
||||||
|
@ -117,13 +115,13 @@ private:
|
||||||
|
|
||||||
void resetDiskWriterEntries();
|
void resetDiskWriterEntries();
|
||||||
|
|
||||||
void mkdir(const std::string& topDirPath) const;
|
void mkdir(const std::string& storeDir) const;
|
||||||
|
|
||||||
std::string getTopDirPath() const;
|
std::string getTopDirPath() const;
|
||||||
|
|
||||||
void openIfNot(const SharedHandle<DiskWriterEntry>& entry,
|
void openIfNot(const SharedHandle<DiskWriterEntry>& entry,
|
||||||
void (DiskWriterEntry::*f)(const std::string&),
|
void (DiskWriterEntry::*f)(const std::string&),
|
||||||
const std::string& topDirPath);
|
const std::string& storeDir);
|
||||||
|
|
||||||
static const size_t DEFAULT_MAX_OPEN_FILES = 100;
|
static const size_t DEFAULT_MAX_OPEN_FILES = 100;
|
||||||
|
|
||||||
|
@ -200,6 +198,8 @@ public:
|
||||||
|
|
||||||
const std::deque<SharedHandle<DiskWriterEntry> >&
|
const std::deque<SharedHandle<DiskWriterEntry> >&
|
||||||
getDiskWriterEntries() const;
|
getDiskWriterEntries() const;
|
||||||
|
|
||||||
|
const std::string& getStoreDir() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef SharedHandle<MultiDiskAdaptor> MultiDiskAdaptorHandle;
|
typedef SharedHandle<MultiDiskAdaptor> MultiDiskAdaptorHandle;
|
||||||
|
|
|
@ -59,7 +59,7 @@ void MultiFileAllocationIterator::allocateChunk()
|
||||||
FileEntryHandle fileEntry = entry->getFileEntry();
|
FileEntryHandle fileEntry = entry->getFileEntry();
|
||||||
// Open file before calling DiskWriterEntry::size()
|
// Open file before calling DiskWriterEntry::size()
|
||||||
_diskAdaptor->openIfNot(entry, &DiskWriterEntry::openFile,
|
_diskAdaptor->openIfNot(entry, &DiskWriterEntry::openFile,
|
||||||
_diskAdaptor->getTopDirPath());
|
_diskAdaptor->getStoreDir());
|
||||||
entry->enableDirectIO();
|
entry->enableDirectIO();
|
||||||
if(entry->needsFileAllocation() && entry->size() < fileEntry->getLength()) {
|
if(entry->needsFileAllocation() && entry->size() < fileEntry->getLength()) {
|
||||||
// Calling private function of MultiDiskAdaptor.
|
// Calling private function of MultiDiskAdaptor.
|
||||||
|
|
|
@ -968,6 +968,14 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
|
||||||
op->addTag(TAG_BITTORRENT);
|
op->addTag(TAG_BITTORRENT);
|
||||||
handlers.push_back(op);
|
handlers.push_back(op);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
SharedHandle<OptionHandler> op(new IndexOutOptionHandler
|
||||||
|
(PREF_INDEX_OUT,
|
||||||
|
TEXT_INDEX_OUT,
|
||||||
|
'O'));
|
||||||
|
op->addTag(TAG_BITTORRENT);
|
||||||
|
handlers.push_back(op);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
SharedHandle<OptionHandler> op(new IntegerRangeOptionHandler
|
SharedHandle<OptionHandler> op(new IntegerRangeOptionHandler
|
||||||
(PREF_LISTEN_PORT,
|
(PREF_LISTEN_PORT,
|
||||||
|
|
|
@ -366,6 +366,32 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IndexOutOptionHandler : public NameMatchOptionHandler {
|
||||||
|
private:
|
||||||
|
public:
|
||||||
|
IndexOutOptionHandler(const std::string& optName,
|
||||||
|
const std::string& description,
|
||||||
|
char shortName = 0):
|
||||||
|
NameMatchOptionHandler(optName, description, NO_DEFAULT_VALUE,
|
||||||
|
OptionHandler::REQ_ARG, shortName) {}
|
||||||
|
|
||||||
|
virtual ~IndexOutOptionHandler() {}
|
||||||
|
|
||||||
|
virtual void parseArg(Option& option, const std::string& optarg)
|
||||||
|
{
|
||||||
|
// See optarg is in the fomrat of "INDEX=PATH"
|
||||||
|
Util::parseIndexPath(optarg);
|
||||||
|
std::string value = option.get(_optName);
|
||||||
|
value += optarg+"\n";
|
||||||
|
option.put(_optName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string createPossibleValuesString() const
|
||||||
|
{
|
||||||
|
return "INDEX=PATH";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ParameterOptionHandler : public NameMatchOptionHandler {
|
class ParameterOptionHandler : public NameMatchOptionHandler {
|
||||||
private:
|
private:
|
||||||
std::deque<std::string> _validParamValues;
|
std::deque<std::string> _validParamValues;
|
||||||
|
|
22
src/Util.cc
22
src/Util.cc
|
@ -941,4 +941,26 @@ std::string Util::htmlEscape(const std::string& src)
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<size_t, std::string>::value_type
|
||||||
|
Util::parseIndexPath(const std::string& line)
|
||||||
|
{
|
||||||
|
std::pair<std::string, std::string> p = Util::split(line, "=");
|
||||||
|
size_t index = parseUInt(p.first);
|
||||||
|
if(p.second.empty()) {
|
||||||
|
throw DlAbortEx(StringFormat("Path with index=%u is empty.",
|
||||||
|
static_cast<unsigned int>(index)).str());
|
||||||
|
}
|
||||||
|
return std::map<size_t, std::string>::value_type(index, p.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<size_t, std::string> Util::createIndexPathMap(std::istream& i)
|
||||||
|
{
|
||||||
|
std::map<size_t, std::string> indexPathMap;
|
||||||
|
std::string line;
|
||||||
|
while(getline(i, line)) {
|
||||||
|
indexPathMap.insert(indexPathMap.begin(), parseIndexPath(line));
|
||||||
|
}
|
||||||
|
return indexPathMap;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "SharedHandle.h"
|
#include "SharedHandle.h"
|
||||||
#include "IntSequence.h"
|
#include "IntSequence.h"
|
||||||
|
@ -306,6 +307,13 @@ public:
|
||||||
return std::accumulate(elements.begin()+1, elements.end(), elements[0],
|
return std::accumulate(elements.begin()+1, elements.end(), elements[0],
|
||||||
Concat("/"));
|
Concat("/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parses INDEX=PATH format string. INDEX must be an unsigned
|
||||||
|
// integer.
|
||||||
|
static std::map<size_t, std::string>::value_type
|
||||||
|
parseIndexPath(const std::string& line);
|
||||||
|
|
||||||
|
static std::map<size_t, std::string> createIndexPathMap(std::istream& i);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "RequestGroup.h"
|
#include "RequestGroup.h"
|
||||||
#include "Option.h"
|
#include "Option.h"
|
||||||
|
@ -124,6 +125,13 @@ createBtRequestGroup(const std::string& torrentFilePath,
|
||||||
btContext->setDir(requestOption.get(PREF_DIR));
|
btContext->setDir(requestOption.get(PREF_DIR));
|
||||||
btContext->setFileFilter
|
btContext->setFileFilter
|
||||||
(Util::parseIntRange(requestOption.get(PREF_SELECT_FILE)));
|
(Util::parseIntRange(requestOption.get(PREF_SELECT_FILE)));
|
||||||
|
std::istringstream indexOutIn(requestOption.get(PREF_INDEX_OUT));
|
||||||
|
std::map<size_t, std::string> indexPathMap =
|
||||||
|
Util::createIndexPathMap(indexOutIn);
|
||||||
|
for(std::map<size_t, std::string>::const_iterator i = indexPathMap.begin();
|
||||||
|
i != indexPathMap.end(); ++i) {
|
||||||
|
btContext->setFilePathWithIndex((*i).first, (*i).second);
|
||||||
|
}
|
||||||
rg->setDownloadContext(btContext);
|
rg->setDownloadContext(btContext);
|
||||||
btContext->setOwnerRequestGroup(rg.get());
|
btContext->setOwnerRequestGroup(rg.get());
|
||||||
return rg;
|
return rg;
|
||||||
|
@ -295,11 +303,13 @@ static void createRequestGroupForUriList
|
||||||
if(uris.empty()) {
|
if(uris.empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// TODO use OptionParser to validate the value in the options.
|
||||||
// These options can be specified in input list(-i list).
|
// These options can be specified in input list(-i list).
|
||||||
static const std::string REQUEST_OPTIONS[] = {
|
static const std::string REQUEST_OPTIONS[] = {
|
||||||
PREF_DIR,
|
PREF_DIR,
|
||||||
PREF_OUT,
|
PREF_OUT,
|
||||||
PREF_SELECT_FILE
|
PREF_SELECT_FILE,
|
||||||
|
PREF_INDEX_OUT
|
||||||
};
|
};
|
||||||
foreachCopyIfndef(&REQUEST_OPTIONS[0],
|
foreachCopyIfndef(&REQUEST_OPTIONS[0],
|
||||||
&REQUEST_OPTIONS[arrayLength(REQUEST_OPTIONS)],
|
&REQUEST_OPTIONS[arrayLength(REQUEST_OPTIONS)],
|
||||||
|
|
|
@ -283,6 +283,8 @@ const std::string PREF_BT_HASH_CHECK_SEED("bt-hash-check-seed");
|
||||||
const std::string PREF_BT_MAX_PEERS("bt-max-peers");
|
const std::string PREF_BT_MAX_PEERS("bt-max-peers");
|
||||||
// values: a string (IP address)
|
// values: a string (IP address)
|
||||||
const std::string PREF_BT_EXTERNAL_IP("bt-external-ip");
|
const std::string PREF_BT_EXTERNAL_IP("bt-external-ip");
|
||||||
|
// values: 1*digit '=' a string that your file system recognizes as a file name.
|
||||||
|
const std::string PREF_INDEX_OUT("index-out");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metalink related preferences
|
* Metalink related preferences
|
||||||
|
|
|
@ -287,6 +287,8 @@ extern const std::string PREF_BT_HASH_CHECK_SEED;
|
||||||
extern const std::string PREF_BT_MAX_PEERS;
|
extern const std::string PREF_BT_MAX_PEERS;
|
||||||
// values: a string (IP address)
|
// values: a string (IP address)
|
||||||
extern const std::string PREF_BT_EXTERNAL_IP;
|
extern const std::string PREF_BT_EXTERNAL_IP;
|
||||||
|
// values: 1*digit '=' a string that your file system recognizes as a file name.
|
||||||
|
extern const std::string PREF_INDEX_OUT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metalink related preferences
|
* Metalink related preferences
|
||||||
|
|
|
@ -493,3 +493,9 @@ _(" --http-auth-challenge[=true|false] Send HTTP authorization header only when
|
||||||
" are embedded in URI, authorization header is\n"\
|
" are embedded in URI, authorization header is\n"\
|
||||||
" always sent to the server regardless of this\n"\
|
" always sent to the server regardless of this\n"\
|
||||||
" option.")
|
" option.")
|
||||||
|
#define TEXT_INDEX_OUT \
|
||||||
|
_(" -O, --index-out=INDEX=PATH Set file path for file with index=INDEX. You can\n"\
|
||||||
|
" find the file index using the --show-files option.\n"\
|
||||||
|
" PATH is a relative path to the path specified in\n"\
|
||||||
|
" --dir option. You can use this option multiple\n"\
|
||||||
|
" times.")
|
||||||
|
|
|
@ -108,11 +108,11 @@ void DefaultBtContextTest::testGetFileEntries() {
|
||||||
std::deque<SharedHandle<FileEntry> >::iterator itr = fileEntries.begin();
|
std::deque<SharedHandle<FileEntry> >::iterator itr = fileEntries.begin();
|
||||||
|
|
||||||
SharedHandle<FileEntry> fileEntry1 = *itr;
|
SharedHandle<FileEntry> fileEntry1 = *itr;
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2/src/aria2c"),
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2-test/aria2/src/aria2c"),
|
||||||
fileEntry1->getPath());
|
fileEntry1->getPath());
|
||||||
itr++;
|
itr++;
|
||||||
SharedHandle<FileEntry> fileEntry2 = *itr;
|
SharedHandle<FileEntry> fileEntry2 = *itr;
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.2.2.tar.bz2"),
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2-test/aria2-0.2.2.tar.bz2"),
|
||||||
fileEntry2->getPath());
|
fileEntry2->getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ void DefaultBtContextTest::testGetFileEntries_multiFileUrlList() {
|
||||||
std::deque<SharedHandle<FileEntry> >::iterator itr = fileEntries.begin();
|
std::deque<SharedHandle<FileEntry> >::iterator itr = fileEntries.begin();
|
||||||
|
|
||||||
SharedHandle<FileEntry> fileEntry1 = *itr;
|
SharedHandle<FileEntry> fileEntry1 = *itr;
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2/src/aria2c"),
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2-test/aria2/src/aria2c"),
|
||||||
fileEntry1->getPath());
|
fileEntry1->getPath());
|
||||||
std::deque<std::string> uris1 = fileEntry1->getAssociatedUris();
|
std::deque<std::string> uris1 = fileEntry1->getAssociatedUris();
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)2, uris1.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)2, uris1.size());
|
||||||
|
@ -300,7 +300,7 @@ void DefaultBtContextTest::testGetFileEntries_multiFileUrlList() {
|
||||||
|
|
||||||
itr++;
|
itr++;
|
||||||
SharedHandle<FileEntry> fileEntry2 = *itr;
|
SharedHandle<FileEntry> fileEntry2 = *itr;
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.2.2.tar.bz2"),
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2-test/aria2-0.2.2.tar.bz2"),
|
||||||
fileEntry2->getPath());
|
fileEntry2->getPath());
|
||||||
std::deque<std::string> uris2 = fileEntry2->getAssociatedUris();
|
std::deque<std::string> uris2 = fileEntry2->getAssociatedUris();
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)2, uris2.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)2, uris2.size());
|
||||||
|
|
|
@ -434,9 +434,7 @@ void MultiDiskAdaptorTest::testSize()
|
||||||
|
|
||||||
void MultiDiskAdaptorTest::testUtime()
|
void MultiDiskAdaptorTest::testUtime()
|
||||||
{
|
{
|
||||||
std::string storeDir = "/tmp";
|
std::string storeDir = "/tmp/aria2_MultiDiskAdaptorTest_testUtime";
|
||||||
std::string topDir = "aria2_MultiDiskAdaptorTest_testUtime";
|
|
||||||
std::string prefix = storeDir+"/"+topDir;
|
|
||||||
SharedHandle<FileEntry> entries[] = {
|
SharedHandle<FileEntry> entries[] = {
|
||||||
SharedHandle<FileEntry>(new FileEntry("requested", 0, 0)),
|
SharedHandle<FileEntry>(new FileEntry("requested", 0, 0)),
|
||||||
SharedHandle<FileEntry>(new FileEntry("notFound", 0, 0)),
|
SharedHandle<FileEntry>(new FileEntry("notFound", 0, 0)),
|
||||||
|
@ -444,10 +442,10 @@ void MultiDiskAdaptorTest::testUtime()
|
||||||
SharedHandle<FileEntry>(new FileEntry("anotherRequested", 0, 0)),
|
SharedHandle<FileEntry>(new FileEntry("anotherRequested", 0, 0)),
|
||||||
};
|
};
|
||||||
|
|
||||||
createFile(prefix+"/"+entries[0]->getPath(), entries[0]->getLength());
|
createFile(storeDir+"/"+entries[0]->getPath(), entries[0]->getLength());
|
||||||
File(prefix+"/"+entries[1]->getPath()).remove();
|
File(storeDir+"/"+entries[1]->getPath()).remove();
|
||||||
createFile(prefix+"/"+entries[2]->getPath(), entries[2]->getLength());
|
createFile(storeDir+"/"+entries[2]->getPath(), entries[2]->getLength());
|
||||||
createFile(prefix+"/"+entries[3]->getPath(), entries[3]->getLength());
|
createFile(storeDir+"/"+entries[3]->getPath(), entries[3]->getLength());
|
||||||
|
|
||||||
entries[2]->setRequested(false);
|
entries[2]->setRequested(false);
|
||||||
|
|
||||||
|
@ -455,7 +453,6 @@ void MultiDiskAdaptorTest::testUtime()
|
||||||
(&entries[0], &entries[arrayLength(entries)]);
|
(&entries[0], &entries[arrayLength(entries)]);
|
||||||
MultiDiskAdaptor adaptor;
|
MultiDiskAdaptor adaptor;
|
||||||
adaptor.setStoreDir(storeDir);
|
adaptor.setStoreDir(storeDir);
|
||||||
adaptor.setTopDir(topDir);
|
|
||||||
adaptor.setFileEntries(fileEntries);
|
adaptor.setFileEntries(fileEntries);
|
||||||
|
|
||||||
time_t atime = (time_t) 100000;
|
time_t atime = (time_t) 100000;
|
||||||
|
@ -464,14 +461,14 @@ void MultiDiskAdaptorTest::testUtime()
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)2, adaptor.utime(Time(atime), Time(mtime)));
|
CPPUNIT_ASSERT_EQUAL((size_t)2, adaptor.utime(Time(atime), Time(mtime)));
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL((time_t)mtime,
|
CPPUNIT_ASSERT_EQUAL((time_t)mtime,
|
||||||
File(prefix+"/"+entries[0]->getPath())
|
File(storeDir+"/"+entries[0]->getPath())
|
||||||
.getModifiedTime().getTime());
|
.getModifiedTime().getTime());
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL((time_t)mtime,
|
CPPUNIT_ASSERT_EQUAL((time_t)mtime,
|
||||||
File(prefix+"/"+entries[3]->getPath())
|
File(storeDir+"/"+entries[3]->getPath())
|
||||||
.getModifiedTime().getTime());
|
.getModifiedTime().getTime());
|
||||||
|
|
||||||
CPPUNIT_ASSERT((time_t)mtime != File(prefix+"/"+entries[2]->getPath())
|
CPPUNIT_ASSERT((time_t)mtime != File(storeDir+"/"+entries[2]->getPath())
|
||||||
.getModifiedTime().getTime());
|
.getModifiedTime().getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
#include "MultiFileAllocationIterator.h"
|
#include "MultiFileAllocationIterator.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
#include "File.h"
|
#include "File.h"
|
||||||
#include "MultiDiskAdaptor.h"
|
#include "MultiDiskAdaptor.h"
|
||||||
#include "FileEntry.h"
|
#include "FileEntry.h"
|
||||||
|
@ -6,9 +12,6 @@
|
||||||
#include "array_fun.h"
|
#include "array_fun.h"
|
||||||
#include "TestUtil.h"
|
#include "TestUtil.h"
|
||||||
#include "DiskWriter.h"
|
#include "DiskWriter.h"
|
||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include <cppunit/extensions/HelperMacros.h>
|
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -53,20 +56,17 @@ void MultiFileAllocationIteratorTest::testMakeDiskWriterEntries()
|
||||||
fs[8]->setRequested(false); // file9
|
fs[8]->setRequested(false); // file9
|
||||||
fs[9]->setRequested(false); // fileA
|
fs[9]->setRequested(false); // fileA
|
||||||
|
|
||||||
std::string topDir = "top";
|
|
||||||
std::string storeDir = "/tmp/aria2_MultiFileAllocationIteratorTest"
|
std::string storeDir = "/tmp/aria2_MultiFileAllocationIteratorTest"
|
||||||
"_testMakeDiskWriterEntries";
|
"_testMakeDiskWriterEntries";
|
||||||
std::string prefix = storeDir+"/"+topDir;
|
|
||||||
|
|
||||||
// create empty file4
|
// create empty file4
|
||||||
createFile(prefix+std::string("/file4"), 0);
|
createFile(storeDir+std::string("/file4"), 0);
|
||||||
|
|
||||||
SharedHandle<MultiDiskAdaptor> diskAdaptor(new MultiDiskAdaptor());
|
SharedHandle<MultiDiskAdaptor> diskAdaptor(new MultiDiskAdaptor());
|
||||||
diskAdaptor->setFileEntries
|
diskAdaptor->setFileEntries
|
||||||
(std::deque<SharedHandle<FileEntry> >(&fs[0], &fs[arrayLength(fs)]));
|
(std::deque<SharedHandle<FileEntry> >(&fs[0], &fs[arrayLength(fs)]));
|
||||||
diskAdaptor->setPieceLength(1024);
|
diskAdaptor->setPieceLength(1024);
|
||||||
diskAdaptor->setStoreDir(storeDir);
|
diskAdaptor->setStoreDir(storeDir);
|
||||||
diskAdaptor->setTopDir(topDir);
|
|
||||||
diskAdaptor->openFile();
|
diskAdaptor->openFile();
|
||||||
|
|
||||||
SharedHandle<MultiFileAllocationIterator> itr
|
SharedHandle<MultiFileAllocationIterator> itr
|
||||||
|
@ -78,67 +78,67 @@ void MultiFileAllocationIteratorTest::testMakeDiskWriterEntries()
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)11, entries.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)11, entries.size());
|
||||||
|
|
||||||
// file1
|
// file1
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file1"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file1"),
|
||||||
entries[0]->getFilePath(prefix));
|
entries[0]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(entries[0]->needsFileAllocation());
|
CPPUNIT_ASSERT(entries[0]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[0]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[0]->getDiskWriter().isNull());
|
||||||
// file2
|
// file2
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file2"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file2"),
|
||||||
entries[1]->getFilePath(prefix));
|
entries[1]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(entries[1]->needsFileAllocation());
|
CPPUNIT_ASSERT(entries[1]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[1]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[1]->getDiskWriter().isNull());
|
||||||
// file3
|
// file3
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file3"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file3"),
|
||||||
entries[2]->getFilePath(prefix));
|
entries[2]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(entries[2]->needsFileAllocation());
|
CPPUNIT_ASSERT(entries[2]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[2]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[2]->getDiskWriter().isNull());
|
||||||
// file4, diskWriter is not null, because file exists.
|
// file4, diskWriter is not null, because file exists.
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file4"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file4"),
|
||||||
entries[3]->getFilePath(prefix));
|
entries[3]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(!entries[3]->needsFileAllocation());
|
CPPUNIT_ASSERT(!entries[3]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[3]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[3]->getDiskWriter().isNull());
|
||||||
// file5
|
// file5
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file5"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file5"),
|
||||||
entries[4]->getFilePath(prefix));
|
entries[4]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(!entries[4]->needsFileAllocation());
|
CPPUNIT_ASSERT(!entries[4]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(entries[4]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(entries[4]->getDiskWriter().isNull());
|
||||||
// file6
|
// file6
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file6"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file6"),
|
||||||
entries[5]->getFilePath(prefix));
|
entries[5]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(entries[5]->needsFileAllocation());
|
CPPUNIT_ASSERT(entries[5]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[5]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[5]->getDiskWriter().isNull());
|
||||||
// file7
|
// file7
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file7"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file7"),
|
||||||
entries[6]->getFilePath(prefix));
|
entries[6]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(entries[6]->needsFileAllocation());
|
CPPUNIT_ASSERT(entries[6]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[6]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[6]->getDiskWriter().isNull());
|
||||||
// file8
|
// file8
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file8"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file8"),
|
||||||
entries[7]->getFilePath(prefix));
|
entries[7]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(entries[7]->needsFileAllocation());
|
CPPUNIT_ASSERT(entries[7]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[7]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[7]->getDiskWriter().isNull());
|
||||||
// file9
|
// file9
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file9"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file9"),
|
||||||
entries[8]->getFilePath(prefix));
|
entries[8]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(!entries[8]->needsFileAllocation());
|
CPPUNIT_ASSERT(!entries[8]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[8]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[8]->getDiskWriter().isNull());
|
||||||
// fileA
|
// fileA
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/fileA"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/fileA"),
|
||||||
entries[9]->getFilePath(prefix));
|
entries[9]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(!entries[9]->needsFileAllocation());
|
CPPUNIT_ASSERT(!entries[9]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(entries[9]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(entries[9]->getDiskWriter().isNull());
|
||||||
// fileB
|
// fileB
|
||||||
CPPUNIT_ASSERT_EQUAL(prefix+std::string("/fileB"),
|
CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/fileB"),
|
||||||
entries[10]->getFilePath(prefix));
|
entries[10]->getFilePath(storeDir));
|
||||||
CPPUNIT_ASSERT(entries[10]->needsFileAllocation());
|
CPPUNIT_ASSERT(entries[10]->needsFileAllocation());
|
||||||
CPPUNIT_ASSERT(!entries[10]->getDiskWriter().isNull());
|
CPPUNIT_ASSERT(!entries[10]->getDiskWriter().isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiFileAllocationIteratorTest::testAllocate()
|
void MultiFileAllocationIteratorTest::testAllocate()
|
||||||
{
|
{
|
||||||
std::string dir = "/tmp";
|
std::string storeDir =
|
||||||
std::string topDir = "aria2_MultiFileAllocationIteratorTest_testAllocate";
|
"/tmp/aria2_MultiFileAllocationIteratorTest_testAllocate";
|
||||||
std::string prefix = dir+"/"+topDir;
|
|
||||||
std::string fname1 = "file1";
|
std::string fname1 = "file1";
|
||||||
std::string fname2 = "file2";
|
std::string fname2 = "file2";
|
||||||
std::string fname3 = "file3";
|
std::string fname3 = "file3";
|
||||||
|
@ -154,8 +154,7 @@ void MultiFileAllocationIteratorTest::testAllocate()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SharedHandle<MultiDiskAdaptor> diskAdaptor(new MultiDiskAdaptor());
|
SharedHandle<MultiDiskAdaptor> diskAdaptor(new MultiDiskAdaptor());
|
||||||
diskAdaptor->setStoreDir(dir);
|
diskAdaptor->setStoreDir(storeDir);
|
||||||
diskAdaptor->setTopDir(topDir);
|
|
||||||
diskAdaptor->setPieceLength(1);
|
diskAdaptor->setPieceLength(1);
|
||||||
|
|
||||||
int64_t offset = 0;
|
int64_t offset = 0;
|
||||||
|
@ -199,12 +198,12 @@ void MultiFileAllocationIteratorTest::testAllocate()
|
||||||
diskAdaptor->setFileEntries(fs);
|
diskAdaptor->setFileEntries(fs);
|
||||||
|
|
||||||
|
|
||||||
File(prefix+"/"+fname1).remove();
|
File(storeDir+"/"+fname1).remove();
|
||||||
File(prefix+"/"+fname2).remove();
|
File(storeDir+"/"+fname2).remove();
|
||||||
File(prefix+"/"+fname3).remove();
|
File(storeDir+"/"+fname3).remove();
|
||||||
File(prefix+"/"+fname4).remove();
|
File(storeDir+"/"+fname4).remove();
|
||||||
File(prefix+"/"+fname5).remove();
|
File(storeDir+"/"+fname5).remove();
|
||||||
File(prefix+"/"+fname6).remove();
|
File(storeDir+"/"+fname6).remove();
|
||||||
|
|
||||||
// we have to open file first.
|
// we have to open file first.
|
||||||
diskAdaptor->initAndOpenFile();
|
diskAdaptor->initAndOpenFile();
|
||||||
|
@ -214,13 +213,13 @@ void MultiFileAllocationIteratorTest::testAllocate()
|
||||||
while(!itr->finished()) {
|
while(!itr->finished()) {
|
||||||
itr->allocateChunk();
|
itr->allocateChunk();
|
||||||
}
|
}
|
||||||
CPPUNIT_ASSERT_EQUAL((uint64_t)length1, File(prefix+"/"+fname1).size());
|
CPPUNIT_ASSERT_EQUAL((uint64_t)length1, File(storeDir+"/"+fname1).size());
|
||||||
CPPUNIT_ASSERT_EQUAL((uint64_t)length2, File(prefix+"/"+fname2).size());
|
CPPUNIT_ASSERT_EQUAL((uint64_t)length2, File(storeDir+"/"+fname2).size());
|
||||||
CPPUNIT_ASSERT_EQUAL((uint64_t)length3, File(prefix+"/"+fname3).size());
|
CPPUNIT_ASSERT_EQUAL((uint64_t)length3, File(storeDir+"/"+fname3).size());
|
||||||
CPPUNIT_ASSERT(!File(prefix+"/"+fname4).isFile());
|
CPPUNIT_ASSERT(!File(storeDir+"/"+fname4).isFile());
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL((uint64_t)length5, File(prefix+"/"+fname5).size());
|
CPPUNIT_ASSERT_EQUAL((uint64_t)length5, File(storeDir+"/"+fname5).size());
|
||||||
CPPUNIT_ASSERT(!File(prefix+"/"+fname6).isFile());
|
CPPUNIT_ASSERT(!File(storeDir+"/"+fname6).isFile());
|
||||||
|
|
||||||
} catch(Exception& e) {
|
} catch(Exception& e) {
|
||||||
CPPUNIT_FAIL(e.stackTrace());
|
CPPUNIT_FAIL(e.stackTrace());
|
||||||
|
|
|
@ -54,6 +54,8 @@ class UtilTest:public CppUnit::TestFixture {
|
||||||
CPPUNIT_TEST(testUrlencode);
|
CPPUNIT_TEST(testUrlencode);
|
||||||
CPPUNIT_TEST(testHtmlEscape);
|
CPPUNIT_TEST(testHtmlEscape);
|
||||||
CPPUNIT_TEST(testJoinPath);
|
CPPUNIT_TEST(testJoinPath);
|
||||||
|
CPPUNIT_TEST(testParseIndexPath);
|
||||||
|
CPPUNIT_TEST(testCreateIndexPathMap);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -97,6 +99,8 @@ public:
|
||||||
void testUrlencode();
|
void testUrlencode();
|
||||||
void testHtmlEscape();
|
void testHtmlEscape();
|
||||||
void testJoinPath();
|
void testJoinPath();
|
||||||
|
void testParseIndexPath();
|
||||||
|
void testCreateIndexPathMap();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -778,4 +782,36 @@ void UtilTest::testJoinPath()
|
||||||
&parentdot[arrayLength(parentdot)]));
|
&parentdot[arrayLength(parentdot)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UtilTest::testParseIndexPath()
|
||||||
|
{
|
||||||
|
std::map<size_t, std::string>::value_type p = Util::parseIndexPath("1=foo");
|
||||||
|
CPPUNIT_ASSERT_EQUAL((size_t)1, p.first);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("foo"), p.second);
|
||||||
|
try {
|
||||||
|
Util::parseIndexPath("1X=foo");
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(Exception& e) {
|
||||||
|
// success
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Util::parseIndexPath("1=");
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(Exception& e) {
|
||||||
|
// success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UtilTest::testCreateIndexPathMap()
|
||||||
|
{
|
||||||
|
std::stringstream in
|
||||||
|
("1=/tmp/myfile\n"
|
||||||
|
"100=/myhome/mypicture.png\n");
|
||||||
|
std::map<size_t, std::string> m = Util::createIndexPathMap(in);
|
||||||
|
CPPUNIT_ASSERT_EQUAL((size_t)2, m.size());
|
||||||
|
CPPUNIT_ASSERT(m.find(1) != m.end());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("/tmp/myfile"), m[1]);
|
||||||
|
CPPUNIT_ASSERT(m.find(100) != m.end());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("/myhome/mypicture.png"), m[100]);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
Loading…
Reference in New Issue