summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2009-03-07 03:10:53 +0000
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2009-03-07 03:10:53 +0000
commitf44554a6346605468f5fbc221746e32735db44ca (patch)
tree308ddd0b6173cc1aa72c291fa64fe6a204ef1de7
parent4aae48c9b2e9b1280f724df50ac71dd64fe1c0df (diff)
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
-rw-r--r--ChangeLog27
-rw-r--r--src/DefaultBtContext.cc25
-rw-r--r--src/DefaultBtContext.h6
-rw-r--r--src/MultiDiskAdaptor.cc73
-rw-r--r--src/MultiDiskAdaptor.h18
-rw-r--r--src/MultiFileAllocationIterator.cc2
-rw-r--r--src/OptionHandlerFactory.cc8
-rw-r--r--src/OptionHandlerImpl.h26
-rw-r--r--src/Util.cc22
-rw-r--r--src/Util.h8
-rw-r--r--src/download_helper.cc12
-rw-r--r--src/prefs.cc2
-rw-r--r--src/prefs.h2
-rw-r--r--src/usage_text.h6
-rw-r--r--test/DefaultBtContextTest.cc8
-rw-r--r--test/MultiDiskAdaptorTest.cc19
-rw-r--r--test/MultiFileAllocationIteratorTest.cc91
-rw-r--r--test/UtilTest.cc36
18 files changed, 280 insertions, 111 deletions
diff --git a/ChangeLog b/ChangeLog
index 986c2d6a..91c607cf 100644
--- a/ChangeLog
+++ b/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>
Use Util::pathJoin()
diff --git a/src/DefaultBtContext.cc b/src/DefaultBtContext.cc
index aede7d07..79976621 100644
--- a/src/DefaultBtContext.cc
+++ b/src/DefaultBtContext.cc
@@ -151,14 +151,20 @@ void DefaultBtContext::extractFileEntries(const bencode::BDE& infoDict,
throw DlAbortEx("Path is empty.");
}
- std::vector<std::string> elements(pathList.size());
- std::transform(pathList.listBegin(), pathList.listEnd(), elements.begin(),
+ std::vector<std::string> pathelem(pathList.size());
+ std::transform(pathList.listBegin(), pathList.listEnd(), pathelem.begin(),
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::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(),
offset, uris));
fileEntries.push_back(fileEntry);
@@ -475,4 +481,15 @@ void DefaultBtContext::setInfoHash(const unsigned char* 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
diff --git a/src/DefaultBtContext.h b/src/DefaultBtContext.h
index d736edb7..3a1bec86 100644
--- a/src/DefaultBtContext.h
+++ b/src/DefaultBtContext.h
@@ -182,6 +182,12 @@ private:
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);
static const std::string DEFAULT_PEER_ID_PREFIX;
diff --git a/src/MultiDiskAdaptor.cc b/src/MultiDiskAdaptor.cc
index b7ab9b53..c7da07ff 100644
--- a/src/MultiDiskAdaptor.cc
+++ b/src/MultiDiskAdaptor.cc
@@ -58,15 +58,15 @@ DiskWriterEntry::DiskWriterEntry(const SharedHandle<FileEntry>& fileEntry):
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()) {
- diskWriter->initAndOpenFile(getFilePath(topDir), fileEntry->getLength());
+ diskWriter->initAndOpenFile(getFilePath(storeDir), fileEntry->getLength());
if(_directIO) {
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()) {
- diskWriter->openFile(getFilePath(topDir), fileEntry->getLength());
+ diskWriter->openFile(getFilePath(storeDir), fileEntry->getLength());
if(_directIO) {
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()) {
- diskWriter->openExistingFile(getFilePath(topDir), fileEntry->getLength());
+ diskWriter->openExistingFile(getFilePath(storeDir), fileEntry->getLength());
if(_directIO) {
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
@@ -270,9 +270,9 @@ void MultiDiskAdaptor::resetDiskWriterEntries()
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
if((*i)->needsFileAllocation() ||
dwreq.find((*i)->getFileEntry()->getPath()) != dwreq.end() ||
- (*i)->fileExists(getTopDirPath())) {
+ (*i)->fileExists(storeDir)) {
logger->debug("Creating DiskWriter for filename=%s",
- (*i)->getFilePath(getTopDirPath()).c_str());
+ (*i)->getFilePath(storeDir).c_str());
(*i)->setDiskWriter(dwFactory.newDiskWriter());
(*i)->getDiskWriter()->setDirectIOAllowed(_directIOAllowed);
if(_readOnly) {
@@ -287,25 +287,25 @@ std::string MultiDiskAdaptor::getTopDirPath() const
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 =
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
- (*i)->getFileEntry()->setupDir(topDirPath);
+ (*i)->getFileEntry()->setupDir(storeDir);
}
}
void MultiDiskAdaptor::openIfNot
(const SharedHandle<DiskWriterEntry>& entry,
void (DiskWriterEntry::*open)(const std::string&),
- const std::string& topDirPath)
+ const std::string& storeDir)
{
if(!entry->isOpen()) {
// logger->debug("DiskWriterEntry: Cache MISS. offset=%s",
// Util::itos(entry->getFileEntry()->getOffset()).c_str());
size_t numOpened = _openedDiskWriterEntries.size();
- (entry.get()->*open)(topDirPath);
+ (entry.get()->*open)(storeDir);
if(numOpened >= _maxOpenFiles) {
// Cache is full.
// Choose one DiskWriterEntry randomly and close it.
@@ -326,32 +326,29 @@ void MultiDiskAdaptor::openIfNot
void MultiDiskAdaptor::openFile()
{
- _cachedTopDirPath = getTopDirPath();
resetDiskWriterEntries();
- mkdir(_cachedTopDirPath);
+ mkdir(storeDir);
// Call DiskWriterEntry::openFile to make sure that zero-length files are
// created.
for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
itr != diskWriterEntries.end(); ++itr) {
- openIfNot(*itr, &DiskWriterEntry::openFile, _cachedTopDirPath);
+ openIfNot(*itr, &DiskWriterEntry::openFile, storeDir);
}
}
void MultiDiskAdaptor::initAndOpenFile()
{
- _cachedTopDirPath = getTopDirPath();
resetDiskWriterEntries();
- mkdir(_cachedTopDirPath);
+ mkdir(storeDir);
// Call DiskWriterEntry::initAndOpenFile to make files truncated.
for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
itr != diskWriterEntries.end(); ++itr) {
- openIfNot(*itr, &DiskWriterEntry::initAndOpenFile, _cachedTopDirPath);
+ openIfNot(*itr, &DiskWriterEntry::initAndOpenFile, storeDir);
}
}
void MultiDiskAdaptor::openExistingFile()
{
- _cachedTopDirPath = getTopDirPath();
resetDiskWriterEntries();
// Not need to call openIfNot here.
}
@@ -416,12 +413,12 @@ findFirstDiskWriterEntry(const DiskWriterEntries& diskWriterEntries, off_t offse
static void throwOnDiskWriterNotOpened(const SharedHandle<DiskWriterEntry>& e,
off_t offset,
- const std::string& topDirPath)
+ const std::string& storeDir)
{
throw DlAbortEx
(StringFormat("DiskWriter for offset=%s, filename=%s is not opened.",
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,
@@ -434,10 +431,10 @@ void MultiDiskAdaptor::writeData(const unsigned char* data, size_t len,
for(DiskWriterEntries::const_iterator i = first; i != diskWriterEntries.end(); ++i) {
size_t writeLength = calculateLength(*i, fileOffset, rem);
- openIfNot(*i, &DiskWriterEntry::openFile, _cachedTopDirPath);
+ openIfNot(*i, &DiskWriterEntry::openFile, storeDir);
if(!(*i)->isOpen()) {
- throwOnDiskWriterNotOpened(*i, offset+(len-rem), _cachedTopDirPath);
+ throwOnDiskWriterNotOpened(*i, offset+(len-rem), storeDir);
}
(*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) {
size_t readLength = calculateLength(*i, fileOffset, rem);
- openIfNot(*i, &DiskWriterEntry::openFile, _cachedTopDirPath);
+ openIfNot(*i, &DiskWriterEntry::openFile, storeDir);
if(!(*i)->isOpen()) {
- throwOnDiskWriterNotOpened(*i, offset+(len-rem), _cachedTopDirPath);
+ throwOnDiskWriterNotOpened(*i, offset+(len-rem), storeDir);
}
totalReadLength +=
@@ -478,12 +475,13 @@ ssize_t MultiDiskAdaptor::readData(unsigned char* data, size_t len, off_t offset
bool MultiDiskAdaptor::fileExists()
{
+ // TODO Use FileEntry::fileExists() here.
+
// Don't use _cachedTopDirPath because they are initialized after opening files.
// This method could be called before opening files.
- std::string topDirPath = getTopDirPath();
for(std::deque<SharedHandle<FileEntry> >::iterator i =
fileEntries.begin(); i != fileEntries.end(); ++i) {
- if(File(topDirPath+"/"+(*i)->getPath()).exists()) {
+ if(File(storeDir+"/"+(*i)->getPath()).exists()) {
return true;
}
}
@@ -496,7 +494,7 @@ uint64_t MultiDiskAdaptor::size()
uint64_t size = 0;
for(DiskWriterEntries::const_iterator itr = diskWriterEntries.begin();
itr != diskWriterEntries.end(); ++itr) {
- openIfNot(*itr, &DiskWriterEntry::openFile, _cachedTopDirPath);
+ openIfNot(*itr, &DiskWriterEntry::openFile, storeDir);
size += (*itr)->size();
}
return size;
@@ -538,9 +536,9 @@ void MultiDiskAdaptor::cutTrailingGarbage()
for(std::deque<SharedHandle<DiskWriterEntry> >::const_iterator i =
diskWriterEntries.begin(); i != diskWriterEntries.end(); ++i) {
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)
- openIfNot(*i, &DiskWriterEntry::openFile, _cachedTopDirPath);
+ openIfNot(*i, &DiskWriterEntry::openFile, storeDir);
(*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 =
fileEntries.begin(); i != fileEntries.end(); ++i) {
if((*i)->isRequested()) {
- File f(getTopDirPath()+"/"+(*i)->getPath());
+ File f(storeDir+"/"+(*i)->getPath());
if(f.isFile() && f.utime(actime, modtime)) {
++numOK;
}
@@ -572,4 +570,9 @@ MultiDiskAdaptor::getDiskWriterEntries() const
return diskWriterEntries;
}
+const std::string& MultiDiskAdaptor::getStoreDir() const
+{
+ return storeDir;
+}
+
} // namespace aria2
diff --git a/src/MultiDiskAdaptor.h b/src/MultiDiskAdaptor.h
index a52e8b1e..686ef694 100644
--- a/src/MultiDiskAdaptor.h
+++ b/src/MultiDiskAdaptor.h
@@ -55,19 +55,19 @@ public:
~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();
bool isOpen() const;
- bool fileExists(const std::string& topDir);
+ bool fileExists(const std::string& storeDir);
uint64_t size() const;
@@ -105,8 +105,6 @@ private:
size_t pieceLength;
DiskWriterEntries diskWriterEntries;
- std::string _cachedTopDirPath;
-
std::deque<SharedHandle<DiskWriterEntry> > _openedDiskWriterEntries;
size_t _maxOpenFiles;
@@ -117,13 +115,13 @@ private:
void resetDiskWriterEntries();
- void mkdir(const std::string& topDirPath) const;
+ void mkdir(const std::string& storeDir) const;
std::string getTopDirPath() const;
void openIfNot(const SharedHandle<DiskWriterEntry>& entry,
void (DiskWriterEntry::*f)(const std::string&),
- const std::string& topDirPath);
+ const std::string& storeDir);
static const size_t DEFAULT_MAX_OPEN_FILES = 100;
@@ -200,6 +198,8 @@ public:
const std::deque<SharedHandle<DiskWriterEntry> >&
getDiskWriterEntries() const;
+
+ const std::string& getStoreDir() const;
};
typedef SharedHandle<MultiDiskAdaptor> MultiDiskAdaptorHandle;
diff --git a/src/MultiFileAllocationIterator.cc b/src/MultiFileAllocationIterator.cc
index 7fcb7b3e..7ab33832 100644
--- a/src/MultiFileAllocationIterator.cc
+++ b/src/MultiFileAllocationIterator.cc
@@ -59,7 +59,7 @@ void MultiFileAllocationIterator::allocateChunk()
FileEntryHandle fileEntry = entry->getFileEntry();
// Open file before calling DiskWriterEntry::size()
_diskAdaptor->openIfNot(entry, &DiskWriterEntry::openFile,
- _diskAdaptor->getTopDirPath());
+ _diskAdaptor->getStoreDir());
entry->enableDirectIO();
if(entry->needsFileAllocation() && entry->size() < fileEntry->getLength()) {
// Calling private function of MultiDiskAdaptor.
diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc
index 9387881c..6b6ef14a 100644
--- a/src/OptionHandlerFactory.cc
+++ b/src/OptionHandlerFactory.cc
@@ -969,6 +969,14 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
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
(PREF_LISTEN_PORT,
TEXT_LISTEN_PORT,
diff --git a/src/OptionHandlerImpl.h b/src/OptionHandlerImpl.h
index d20ddbba..2475d4a9 100644
--- a/src/OptionHandlerImpl.h
+++ b/src/OptionHandlerImpl.h
@@ -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 {
private:
std::deque<std::string> _validParamValues;
diff --git a/src/Util.cc b/src/Util.cc
index c8227779..21ce6d37 100644
--- a/src/Util.cc
+++ b/src/Util.cc
@@ -941,4 +941,26 @@ std::string Util::htmlEscape(const std::string& src)
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
diff --git a/src/Util.h b/src/Util.h
index f171ac13..b1b5005d 100644
--- a/src/Util.h
+++ b/src/Util.h
@@ -44,6 +44,7 @@
#include <deque>
#include <iosfwd>
#include <numeric>
+#include <map>
#include "SharedHandle.h"
#include "IntSequence.h"
@@ -306,6 +307,13 @@ public:
return std::accumulate(elements.begin()+1, elements.end(), elements[0],
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
diff --git a/src/download_helper.cc b/src/download_helper.cc
index 67988b6e..490c2215 100644
--- a/src/download_helper.cc
+++ b/src/download_helper.cc
@@ -37,6 +37,7 @@
#include <iostream>
#include <fstream>
#include <algorithm>
+#include <sstream>
#include "RequestGroup.h"
#include "Option.h"
@@ -124,6 +125,13 @@ createBtRequestGroup(const std::string& torrentFilePath,
btContext->setDir(requestOption.get(PREF_DIR));
btContext->setFileFilter
(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);
btContext->setOwnerRequestGroup(rg.get());
return rg;
@@ -295,11 +303,13 @@ static void createRequestGroupForUriList
if(uris.empty()) {
continue;
}
+ // TODO use OptionParser to validate the value in the options.
// These options can be specified in input list(-i list).
static const std::string REQUEST_OPTIONS[] = {
PREF_DIR,
PREF_OUT,
- PREF_SELECT_FILE
+ PREF_SELECT_FILE,
+ PREF_INDEX_OUT
};
foreachCopyIfndef(&REQUEST_OPTIONS[0],
&REQUEST_OPTIONS[arrayLength(REQUEST_OPTIONS)],
diff --git a/src/prefs.cc b/src/prefs.cc
index 765fd801..9306c127 100644
--- a/src/prefs.cc
+++ b/src/prefs.cc
@@ -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");
// values: a string (IP address)
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
diff --git a/src/prefs.h b/src/prefs.h
index dbaa1f2c..4a95b821 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -287,6 +287,8 @@ extern const std::string PREF_BT_HASH_CHECK_SEED;
extern const std::string PREF_BT_MAX_PEERS;
// values: a string (IP address)
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
diff --git a/src/usage_text.h b/src/usage_text.h
index 92ae0bc0..ffce426c 100644
--- a/src/usage_text.h
+++ b/src/usage_text.h
@@ -493,3 +493,9 @@ _(" --http-auth-challenge[=true|false] Send HTTP authorization header only when
" are embedded in URI, authorization header is\n"\
" always sent to the server regardless of this\n"\
" 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.")
diff --git a/test/DefaultBtContextTest.cc b/test/DefaultBtContextTest.cc
index 0824b485..dd0ad2b5 100644
--- a/test/DefaultBtContextTest.cc
+++ b/test/DefaultBtContextTest.cc
@@ -108,11 +108,11 @@ void DefaultBtContextTest::testGetFileEntries() {
std::deque<SharedHandle<FileEntry> >::iterator itr = fileEntries.begin();
SharedHandle<FileEntry> fileEntry1 = *itr;
- CPPUNIT_ASSERT_EQUAL(std::string("aria2/src/aria2c"),
+ CPPUNIT_ASSERT_EQUAL(std::string("aria2-test/aria2/src/aria2c"),
fileEntry1->getPath());
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());
}
@@ -289,7 +289,7 @@ void DefaultBtContextTest::testGetFileEntries_multiFileUrlList() {
std::deque<SharedHandle<FileEntry> >::iterator itr = fileEntries.begin();
SharedHandle<FileEntry> fileEntry1 = *itr;
- CPPUNIT_ASSERT_EQUAL(std::string("aria2/src/aria2c"),
+ CPPUNIT_ASSERT_EQUAL(std::string("aria2-test/aria2/src/aria2c"),
fileEntry1->getPath());
std::deque<std::string> uris1 = fileEntry1->getAssociatedUris();
CPPUNIT_ASSERT_EQUAL((size_t)2, uris1.size());
@@ -300,7 +300,7 @@ void DefaultBtContextTest::testGetFileEntries_multiFileUrlList() {
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());
std::deque<std::string> uris2 = fileEntry2->getAssociatedUris();
CPPUNIT_ASSERT_EQUAL((size_t)2, uris2.size());
diff --git a/test/MultiDiskAdaptorTest.cc b/test/MultiDiskAdaptorTest.cc
index 7e6fc395..bc7498a2 100644
--- a/test/MultiDiskAdaptorTest.cc
+++ b/test/MultiDiskAdaptorTest.cc
@@ -434,9 +434,7 @@ void MultiDiskAdaptorTest::testSize()
void MultiDiskAdaptorTest::testUtime()
{
- std::string storeDir = "/tmp";
- std::string topDir = "aria2_MultiDiskAdaptorTest_testUtime";
- std::string prefix = storeDir+"/"+topDir;
+ std::string storeDir = "/tmp/aria2_MultiDiskAdaptorTest_testUtime";
SharedHandle<FileEntry> entries[] = {
SharedHandle<FileEntry>(new FileEntry("requested", 0, 0)),
SharedHandle<FileEntry>(new FileEntry("notFound", 0, 0)),
@@ -444,10 +442,10 @@ void MultiDiskAdaptorTest::testUtime()
SharedHandle<FileEntry>(new FileEntry("anotherRequested", 0, 0)),
};
- createFile(prefix+"/"+entries[0]->getPath(), entries[0]->getLength());
- File(prefix+"/"+entries[1]->getPath()).remove();
- createFile(prefix+"/"+entries[2]->getPath(), entries[2]->getLength());
- createFile(prefix+"/"+entries[3]->getPath(), entries[3]->getLength());
+ createFile(storeDir+"/"+entries[0]->getPath(), entries[0]->getLength());
+ File(storeDir+"/"+entries[1]->getPath()).remove();
+ createFile(storeDir+"/"+entries[2]->getPath(), entries[2]->getLength());
+ createFile(storeDir+"/"+entries[3]->getPath(), entries[3]->getLength());
entries[2]->setRequested(false);
@@ -455,7 +453,6 @@ void MultiDiskAdaptorTest::testUtime()
(&entries[0], &entries[arrayLength(entries)]);
MultiDiskAdaptor adaptor;
adaptor.setStoreDir(storeDir);
- adaptor.setTopDir(topDir);
adaptor.setFileEntries(fileEntries);
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((time_t)mtime,
- File(prefix+"/"+entries[0]->getPath())
+ File(storeDir+"/"+entries[0]->getPath())
.getModifiedTime().getTime());
CPPUNIT_ASSERT_EQUAL((time_t)mtime,
- File(prefix+"/"+entries[3]->getPath())
+ File(storeDir+"/"+entries[3]->getPath())
.getModifiedTime().getTime());
- CPPUNIT_ASSERT((time_t)mtime != File(prefix+"/"+entries[2]->getPath())
+ CPPUNIT_ASSERT((time_t)mtime != File(storeDir+"/"+entries[2]->getPath())
.getModifiedTime().getTime());
}
diff --git a/test/MultiFileAllocationIteratorTest.cc b/test/MultiFileAllocationIteratorTest.cc
index 1ca3dfb0..90c7e74c 100644
--- a/test/MultiFileAllocationIteratorTest.cc
+++ b/test/MultiFileAllocationIteratorTest.cc
@@ -1,4 +1,10 @@
#include "MultiFileAllocationIterator.h"
+
+#include <algorithm>
+#include <iostream>
+
+#include <cppunit/extensions/HelperMacros.h>
+
#include "File.h"
#include "MultiDiskAdaptor.h"
#include "FileEntry.h"
@@ -6,9 +12,6 @@
#include "array_fun.h"
#include "TestUtil.h"
#include "DiskWriter.h"
-#include <algorithm>
-#include <iostream>
-#include <cppunit/extensions/HelperMacros.h>
namespace aria2 {
@@ -53,20 +56,17 @@ void MultiFileAllocationIteratorTest::testMakeDiskWriterEntries()
fs[8]->setRequested(false); // file9
fs[9]->setRequested(false); // fileA
- std::string topDir = "top";
std::string storeDir = "/tmp/aria2_MultiFileAllocationIteratorTest"
"_testMakeDiskWriterEntries";
- std::string prefix = storeDir+"/"+topDir;
// create empty file4
- createFile(prefix+std::string("/file4"), 0);
+ createFile(storeDir+std::string("/file4"), 0);
SharedHandle<MultiDiskAdaptor> diskAdaptor(new MultiDiskAdaptor());
diskAdaptor->setFileEntries
(std::deque<SharedHandle<FileEntry> >(&fs[0], &fs[arrayLength(fs)]));
diskAdaptor->setPieceLength(1024);
diskAdaptor->setStoreDir(storeDir);
- diskAdaptor->setTopDir(topDir);
diskAdaptor->openFile();
SharedHandle<MultiFileAllocationIterator> itr
@@ -78,67 +78,67 @@ void MultiFileAllocationIteratorTest::testMakeDiskWriterEntries()
CPPUNIT_ASSERT_EQUAL((size_t)11, entries.size());
// file1
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file1"),
- entries[0]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file1"),
+ entries[0]->getFilePath(storeDir));
CPPUNIT_ASSERT(entries[0]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[0]->getDiskWriter().isNull());
// file2
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file2"),
- entries[1]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file2"),
+ entries[1]->getFilePath(storeDir));
CPPUNIT_ASSERT(entries[1]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[1]->getDiskWriter().isNull());
// file3
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file3"),
- entries[2]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file3"),
+ entries[2]->getFilePath(storeDir));
CPPUNIT_ASSERT(entries[2]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[2]->getDiskWriter().isNull());
// file4, diskWriter is not null, because file exists.
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file4"),
- entries[3]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file4"),
+ entries[3]->getFilePath(storeDir));
CPPUNIT_ASSERT(!entries[3]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[3]->getDiskWriter().isNull());
// file5
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file5"),
- entries[4]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file5"),
+ entries[4]->getFilePath(storeDir));
CPPUNIT_ASSERT(!entries[4]->needsFileAllocation());
CPPUNIT_ASSERT(entries[4]->getDiskWriter().isNull());
// file6
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file6"),
- entries[5]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file6"),
+ entries[5]->getFilePath(storeDir));
CPPUNIT_ASSERT(entries[5]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[5]->getDiskWriter().isNull());
// file7
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file7"),
- entries[6]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file7"),
+ entries[6]->getFilePath(storeDir));
CPPUNIT_ASSERT(entries[6]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[6]->getDiskWriter().isNull());
// file8
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file8"),
- entries[7]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file8"),
+ entries[7]->getFilePath(storeDir));
CPPUNIT_ASSERT(entries[7]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[7]->getDiskWriter().isNull());
// file9
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/file9"),
- entries[8]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/file9"),
+ entries[8]->getFilePath(storeDir));
CPPUNIT_ASSERT(!entries[8]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[8]->getDiskWriter().isNull());
// fileA
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/fileA"),
- entries[9]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/fileA"),
+ entries[9]->getFilePath(storeDir));
CPPUNIT_ASSERT(!entries[9]->needsFileAllocation());
CPPUNIT_ASSERT(entries[9]->getDiskWriter().isNull());
// fileB
- CPPUNIT_ASSERT_EQUAL(prefix+std::string("/fileB"),
- entries[10]->getFilePath(prefix));
+ CPPUNIT_ASSERT_EQUAL(storeDir+std::string("/fileB"),
+ entries[10]->getFilePath(storeDir));
CPPUNIT_ASSERT(entries[10]->needsFileAllocation());
CPPUNIT_ASSERT(!entries[10]->getDiskWriter().isNull());
}
void MultiFileAllocationIteratorTest::testAllocate()
{
- std::string dir = "/tmp";
- std::string topDir = "aria2_MultiFileAllocationIteratorTest_testAllocate";
- std::string prefix = dir+"/"+topDir;
+ std::string storeDir =
+ "/tmp/aria2_MultiFileAllocationIteratorTest_testAllocate";
+
std::string fname1 = "file1";
std::string fname2 = "file2";
std::string fname3 = "file3";
@@ -154,8 +154,7 @@ void MultiFileAllocationIteratorTest::testAllocate()
try {
SharedHandle<MultiDiskAdaptor> diskAdaptor(new MultiDiskAdaptor());
- diskAdaptor->setStoreDir(dir);
- diskAdaptor->setTopDir(topDir);
+ diskAdaptor->setStoreDir(storeDir);
diskAdaptor->setPieceLength(1);
int64_t offset = 0;
@@ -199,12 +198,12 @@ void MultiFileAllocationIteratorTest::testAllocate()
diskAdaptor->setFileEntries(fs);
- File(prefix+"/"+fname1).remove();
- File(prefix+"/"+fname2).remove();
- File(prefix+"/"+fname3).remove();
- File(prefix+"/"+fname4).remove();
- File(prefix+"/"+fname5).remove();
- File(prefix+"/"+fname6).remove();
+ File(storeDir+"/"+fname1).remove();
+ File(storeDir+"/"+fname2).remove();
+ File(storeDir+"/"+fname3).remove();
+ File(storeDir+"/"+fname4).remove();
+ File(storeDir+"/"+fname5).remove();
+ File(storeDir+"/"+fname6).remove();
// we have to open file first.
diskAdaptor->initAndOpenFile();
@@ -214,13 +213,13 @@ void MultiFileAllocationIteratorTest::testAllocate()
while(!itr->finished()) {
itr->allocateChunk();
}
- CPPUNIT_ASSERT_EQUAL((uint64_t)length1, File(prefix+"/"+fname1).size());
- CPPUNIT_ASSERT_EQUAL((uint64_t)length2, File(prefix+"/"+fname2).size());
- CPPUNIT_ASSERT_EQUAL((uint64_t)length3, File(prefix+"/"+fname3).size());
- CPPUNIT_ASSERT(!File(prefix+"/"+fname4).isFile());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)length1, File(storeDir+"/"+fname1).size());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)length2, File(storeDir+"/"+fname2).size());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)length3, File(storeDir+"/"+fname3).size());
+ CPPUNIT_ASSERT(!File(storeDir+"/"+fname4).isFile());
- CPPUNIT_ASSERT_EQUAL((uint64_t)length5, File(prefix+"/"+fname5).size());
- CPPUNIT_ASSERT(!File(prefix+"/"+fname6).isFile());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)length5, File(storeDir+"/"+fname5).size());
+ CPPUNIT_ASSERT(!File(storeDir+"/"+fname6).isFile());
} catch(Exception& e) {
CPPUNIT_FAIL(e.stackTrace());
diff --git a/test/UtilTest.cc b/test/UtilTest.cc
index cc3a38b7..15697eab 100644
--- a/test/UtilTest.cc
+++ b/test/UtilTest.cc
@@ -54,6 +54,8 @@ class UtilTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testUrlencode);
CPPUNIT_TEST(testHtmlEscape);
CPPUNIT_TEST(testJoinPath);
+ CPPUNIT_TEST(testParseIndexPath);
+ CPPUNIT_TEST(testCreateIndexPathMap);
CPPUNIT_TEST_SUITE_END();
private:
@@ -97,6 +99,8 @@ public:
void testUrlencode();
void testHtmlEscape();
void testJoinPath();
+ void testParseIndexPath();
+ void testCreateIndexPathMap();
};
@@ -778,4 +782,36 @@ void UtilTest::testJoinPath()
&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