linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #06349
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3152: fix dupe hashing
------------------------------------------------------------
revno: 3152
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Thu 2012-12-13 18:04:31 +0100
message:
fix dupe hashing
modified:
dcpp/HashManager.cpp
dcpp/HashManager.h
dcpp/HashValue.h
dcpp/ShareManager.cpp
dcpp/ShareManager.h
--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk
Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'dcpp/HashManager.cpp'
--- dcpp/HashManager.cpp 2012-06-08 15:27:48 +0000
+++ dcpp/HashManager.cpp 2012-12-13 17:04:31 +0000
@@ -36,23 +36,13 @@
static const uint32_t HASH_FILE_VERSION = 2;
const int64_t HashManager::MIN_BLOCK_SIZE = 64 * 1024;
-bool HashManager::checkTTH(const string& aFileName, int64_t aSize, uint32_t aTimeStamp) {
- Lock l(cs);
- if (!store.checkTTH(aFileName, aSize, aTimeStamp)) {
- hasher.hashFile(aFileName, aSize);
- return false;
- }
- return true;
-}
-
-TTHValue HashManager::getTTH(const string& aFileName, int64_t aSize) {
- Lock l(cs);
- const TTHValue* tth = store.getTTH(aFileName);
- if (tth == NULL) {
- hasher.hashFile(aFileName, aSize);
- throw HashException();
- }
- return *tth;
+optional<TTHValue> HashManager::getTTH(const string& aFileName, int64_t aSize, uint32_t aTimeStamp) noexcept {
+ Lock l(cs);
+ auto tth = store.getTTH(aFileName, aSize, aTimeStamp);
+ if(!tth) {
+ hasher.hashFile(aFileName, aSize);
+ }
+ return tth;
}
bool HashManager::getTree(const TTHValue& root, TigerTree& tt) {
@@ -178,39 +168,28 @@
return i == treeIndex.end() ? 0 : i->second.getBlockSize();
}
-bool HashManager::HashStore::checkTTH(const string& aFileName, int64_t aSize, uint32_t aTimeStamp) {
+optional<TTHValue> HashManager::HashStore::getTTH(const string& aFileName, int64_t aSize, uint32_t aTimeStamp) noexcept {
auto fname = Text::toLower(Util::getFileName(aFileName));
auto fpath = Text::toLower(Util::getFilePath(aFileName));
+
auto i = fileIndex.find(fpath);
if (i != fileIndex.end()) {
auto j = find(i->second.begin(), i->second.end(), fname);
if (j != i->second.end()) {
FileInfo& fi = *j;
- auto ti = treeIndex.find(fi.getRoot());
- if (ti == treeIndex.end() || ti->second.getSize() != aSize || fi.getTimeStamp() != aTimeStamp) {
- i->second.erase(j);
- dirty = true;
- return false;
+ const auto& root = fi.getRoot();
+ auto ti = treeIndex.find(root);
+ if(ti != treeIndex.end() && ti->second.getSize() == aSize && fi.getTimeStamp() == aTimeStamp) {
+ fi.setUsed(true);
+ return root;
}
- return true;
- }
- }
- return false;
-}
-
-const TTHValue* HashManager::HashStore::getTTH(const string& aFileName) {
- auto fname = Text::toLower(Util::getFileName(aFileName));
- auto fpath = Text::toLower(Util::getFilePath(aFileName));
-
- auto i = fileIndex.find(fpath);
- if (i != fileIndex.end()) {
- auto j = find(i->second.begin(), i->second.end(), fname);
- if (j != i->second.end()) {
- j->setUsed(true);
- return &(j->getRoot());
- }
- }
- return NULL;
+
+ // the file size or the timestamp has changed
+ i->second.erase(j);
+ dirty = true;
+ }
+ }
+ return nullptr;
}
void HashManager::HashStore::rebuild() {
@@ -462,7 +441,7 @@
}
}
-void HashManager::Hasher::hashFile(const string& fileName, int64_t size) {
+void HashManager::Hasher::hashFile(const string& fileName, int64_t size) noexcept {
Lock l(cs);
if(w.insert(make_pair(fileName, size)).second) {
if(paused > 0)
@@ -472,18 +451,18 @@
}
}
-bool HashManager::Hasher::pause() {
+bool HashManager::Hasher::pause() noexcept {
Lock l(cs);
return paused++;
}
-void HashManager::Hasher::resume() {
+void HashManager::Hasher::resume() noexcept {
Lock l(cs);
while(--paused > 0)
s.signal();
}
-bool HashManager::Hasher::isPaused() const {
+bool HashManager::Hasher::isPaused() const noexcept {
Lock l(cs);
return paused > 0;
}
@@ -637,17 +616,17 @@
HashManager::getInstance()->resumeHashing();
}
-bool HashManager::pauseHashing() {
+bool HashManager::pauseHashing() noexcept {
Lock l(cs);
return hasher.pause();
}
-void HashManager::resumeHashing() {
+void HashManager::resumeHashing() noexcept {
Lock l(cs);
hasher.resume();
}
-bool HashManager::isHashingPaused() const {
+bool HashManager::isHashingPaused() const noexcept {
Lock l(cs);
return hasher.isPaused();
}
=== modified file 'dcpp/HashManager.h'
--- dcpp/HashManager.h 2012-01-13 20:55:20 +0000
+++ dcpp/HashManager.h 2012-12-13 17:04:31 +0000
@@ -21,6 +21,8 @@
#include <map>
+#include <boost/optional.hpp>
+
#include "Singleton.h"
#include "MerkleTree.h"
#include "Thread.h"
@@ -34,6 +36,8 @@
using std::map;
+using boost::optional;
+
STANDARD_EXCEPTION(HashException);
class HashLoader;
@@ -54,17 +58,12 @@
hasher.join();
}
- /**
- * Check if the TTH tree associated with the filename is current.
- */
- bool checkTTH(const string& aFileName, int64_t aSize, uint32_t aTimeStamp);
+ /** Get the TTH root associated with the filename if its tree is current. */
+ optional<TTHValue> getTTH(const string& aFileName, int64_t aSize, uint32_t aTimeStamp) noexcept;
void stopHashing(const string& baseDir) { hasher.stopHashing(baseDir); }
void setPriority(Thread::Priority p) { hasher.setThreadPriority(p); }
- /** @return TTH root */
- TTHValue getTTH(const string& aFileName, int64_t aSize);
-
bool getTree(const TTHValue& root, TigerTree& tt);
/** Return block size of the tree associated with root, or 0 if no such tree is in the store */
@@ -102,21 +101,21 @@
};
/// @return whether hashing was already paused
- bool pauseHashing();
- void resumeHashing();
- bool isHashingPaused() const;
+ bool pauseHashing() noexcept;
+ void resumeHashing() noexcept;
+ bool isHashingPaused() const noexcept;
private:
class Hasher : public Thread {
public:
Hasher() : stop(false), running(false), paused(0), rebuild(false), currentSize(0) { }
- void hashFile(const string& fileName, int64_t size);
+ void hashFile(const string& fileName, int64_t size) noexcept;
/// @return whether hashing was already paused
- bool pause();
- void resume();
- bool isPaused() const;
+ bool pause() noexcept;
+ void resume() noexcept;
+ bool isPaused() const noexcept;
void stopHashing(const string& baseDir);
virtual int run();
@@ -157,10 +156,9 @@
void rebuild();
- bool checkTTH(const string& aFileName, int64_t aSize, uint32_t aTimeStamp);
+ optional<TTHValue> getTTH(const string& aFileName, int64_t aSize, uint32_t aTimeStamp) noexcept;
void addTree(const TigerTree& tt) noexcept;
- const TTHValue* getTTH(const string& aFileName);
bool getTree(const TTHValue& root, TigerTree& tth);
size_t getBlockSize(const TTHValue& root) const;
bool isDirty() { return dirty; }
=== modified file 'dcpp/HashValue.h'
--- dcpp/HashValue.h 2012-01-13 20:55:20 +0000
+++ dcpp/HashValue.h 2012-12-13 17:04:31 +0000
@@ -32,8 +32,7 @@
HashValue() { }
explicit HashValue(const uint8_t* aData) { memcpy(data, aData, BYTES); }
explicit HashValue(const std::string& base32) { Encoder::fromBase32(base32.c_str(), data, BYTES); }
- HashValue(const HashValue& rhs) { memcpy(data, rhs.data, BYTES); }
- HashValue& operator=(const HashValue& rhs) { memcpy(data, rhs.data, BYTES); return *this; }
+
bool operator!=(const HashValue& rhs) const { return !(*this == rhs); }
bool operator==(const HashValue& rhs) const { return memcmp(data, rhs.data, BYTES) == 0; }
bool operator<(const HashValue& rhs) const { return memcmp(data, rhs.data, BYTES) < 0; }
=== modified file 'dcpp/ShareManager.cpp'
--- dcpp/ShareManager.cpp 2012-12-12 22:44:47 +0000
+++ dcpp/ShareManager.cpp 2012-12-13 17:04:31 +0000
@@ -135,9 +135,9 @@
}
string ShareManager::toVirtual(const TTHValue& tth) const {
- if(tth == bzXmlRoot) {
+ if(bzXmlRoot && tth == bzXmlRoot) {
return Transfer::USER_LIST_NAME_BZ;
- } else if(tth == xmlRoot) {
+ } else if(xmlRoot && tth == xmlRoot) {
return Transfer::USER_LIST_NAME;
}
@@ -165,8 +165,8 @@
return make_pair(getBZXmlFile(), 0);
}
- auto i = findFile(virtualFile);
- return make_pair(i->getRealPath(), i->getSize());
+ auto f = findFile(virtualFile);
+ return make_pair(f.getRealPath(), f.getSize());
}
StringList ShareManager::getRealPaths(const string& virtualPath) {
@@ -203,7 +203,7 @@
return ret;
}
-TTHValue ShareManager::getTTH(const string& virtualFile) const {
+optional<TTHValue> ShareManager::getTTH(const string& virtualFile) const {
Lock l(cs);
if(virtualFile == Transfer::USER_LIST_NAME_BZ) {
return bzXmlRoot;
@@ -211,20 +211,21 @@
return xmlRoot;
}
- return findFile(virtualFile)->getTTH();
+ return findFile(virtualFile).tth;
}
MemoryInputStream* ShareManager::getTree(const string& virtualFile) const {
TigerTree tree;
if(virtualFile.compare(0, 4, "TTH/") == 0) {
if(!HashManager::getInstance()->getTree(TTHValue(virtualFile.substr(4)), tree))
- return 0;
+ return nullptr;
} else {
try {
- TTHValue tth = getTTH(virtualFile);
- HashManager::getInstance()->getTree(tth, tree);
+ auto tth = getTTH(virtualFile);
+ if(!tth) { return nullptr; }
+ HashManager::getInstance()->getTree(*tth, tree);
} catch(const Exception&) {
- return 0;
+ return nullptr;
}
}
@@ -235,18 +236,27 @@
AdcCommand ShareManager::getFileInfo(const string& aFile) {
if(aFile == Transfer::USER_LIST_NAME) {
generateXmlList();
+ if(!xmlRoot) {
+ throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
+ }
+
AdcCommand cmd(AdcCommand::CMD_RES);
cmd.addParam("FN", aFile);
cmd.addParam("SI", Util::toString(xmlListLen));
- cmd.addParam("TR", xmlRoot.toBase32());
+ cmd.addParam("TR", xmlRoot->toBase32());
return cmd;
- } else if(aFile == Transfer::USER_LIST_NAME_BZ) {
+ }
+
+ if(aFile == Transfer::USER_LIST_NAME_BZ) {
generateXmlList();
+ if(!bzXmlRoot) {
+ throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
+ }
AdcCommand cmd(AdcCommand::CMD_RES);
cmd.addParam("FN", aFile);
cmd.addParam("SI", Util::toString(bzXmlListLen));
- cmd.addParam("TR", bzXmlRoot.toBase32());
+ cmd.addParam("TR", bzXmlRoot->toBase32());
return cmd;
}
@@ -264,7 +274,7 @@
AdcCommand cmd(AdcCommand::CMD_RES);
cmd.addParam("FN", f.getADCPath());
cmd.addParam("SI", Util::toString(f.getSize()));
- cmd.addParam("TR", f.getTTH().toBase32());
+ cmd.addParam("TR", f.tth->toBase32());
return cmd;
}
@@ -297,13 +307,13 @@
return make_pair(d, virtualPath.substr(j));
}
-ShareManager::Directory::File::Set::const_iterator ShareManager::findFile(const string& virtualFile) const {
+const ShareManager::Directory::File& ShareManager::findFile(const string& virtualFile) const {
if(virtualFile.compare(0, 4, "TTH/") == 0) {
auto i = tthIndex.find(TTHValue(virtualFile.substr(4)));
if(i == tthIndex.end()) {
throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
}
- return i->second;
+ return *i->second;
}
auto v = splitVirtual(virtualFile);
@@ -311,7 +321,7 @@
Directory::File::StringComp(v.second));
if(it == v.first->files.end())
throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
- return it;
+ return *it;
}
string ShareManager::validateVirtual(const string& aVirt) const noexcept {
@@ -683,20 +693,17 @@
}
} else {
// Not a directory, assume it's a file...make sure we're not sharing the settings file...
- if( (Util::stricmp(name.c_str(), "DCPlusPlus.xml") != 0) &&
- (Util::stricmp(name.c_str(), "Favorites.xml") != 0)) {
-
- int64_t size = i->getSize();
- string fileName = aName + name;
- if(Util::stricmp(fileName, SETTING(TLS_PRIVATE_KEY_FILE)) == 0) {
- continue;
- }
- try {
- if(HashManager::getInstance()->checkTTH(fileName, size, i->getLastWriteTime()))
- lastFileIter = dir->files.insert(lastFileIter, Directory::File(name, size, dir, HashManager::getInstance()->getTTH(fileName, size)));
- } catch(const HashException&) {
- }
- }
+ if(Util::stricmp(name.c_str(), "DCPlusPlus.xml") == 0 ||
+ Util::stricmp(name.c_str(), "Favorites.xml") == 0) { continue; }
+
+ int64_t size = i->getSize();
+ string fileName = aName + name;
+
+ // don't share the private key file
+ if(Util::stricmp(fileName, SETTING(TLS_PRIVATE_KEY_FILE)) == 0) { continue; }
+
+ lastFileIter = dir->files.insert(lastFileIter, Directory::File(name, size, dir,
+ HashManager::getInstance()->getTTH(fileName, size, i->getLastWriteTime())));
}
}
@@ -739,9 +746,14 @@
void ShareManager::updateIndices(Directory& dir, const Directory::File::Set::iterator& i) {
const Directory::File& f = *i;
- auto j = tthIndex.find(f.getTTH());
+ if(!f.tth) {
+ return;
+ }
+
+ auto j = tthIndex.find(*f.tth);
if(j == tthIndex.end()) {
- dir.size+=f.getSize();
+ dir.size += f.getSize();
+
} else {
if(!SETTING(LIST_DUPES)) {
try {
@@ -756,7 +768,7 @@
dir.addType(getType(f.getName()));
- tthIndex[f.getTTH()] = i;
+ tthIndex[*f.tth] = &f;
bloom.add(Text::toLower(f.getName()));
}
@@ -1013,6 +1025,7 @@
void ShareManager::Directory::filesToXml(OutputStream& xmlFile, string& indent, string& tmp2) const {
for(auto& f: files) {
+ if(!f.tth) { continue; }
xmlFile.write(indent);
xmlFile.write(LITERAL("<File Name=\""));
xmlFile.write(SimpleXML::escape(f.getName(), tmp2, true));
@@ -1020,7 +1033,7 @@
xmlFile.write(Util::toString(f.getSize()));
xmlFile.write(LITERAL("\" TTH=\""));
tmp2.clear();
- xmlFile.write(f.getTTH().toBase32(tmp2));
+ xmlFile.write(f.tth->toBase32(tmp2));
xmlFile.write(LITERAL("\"/>\r\n"));
}
}
@@ -1166,15 +1179,18 @@
bool sizeOk = (aSearchType != SearchManager::SIZE_ATLEAST) || (aSize == 0);
if( (cur->empty()) &&
- (((aFileType == SearchManager::TYPE_ANY) && sizeOk) || (aFileType == SearchManager::TYPE_DIRECTORY)) ) {
+ (((aFileType == SearchManager::TYPE_ANY) && sizeOk) || (aFileType == SearchManager::TYPE_DIRECTORY)) )
+ {
// We satisfied all the search words! Add the directory...(NMDC searches don't support directory size)
- SearchResultPtr sr(new SearchResult(SearchResult::TYPE_DIRECTORY, 0, getFullName(), TTHValue()));
+ /// @todo send the directory hash when we have one
+ SearchResultPtr sr(new SearchResult(SearchResult::TYPE_DIRECTORY, 0, getFullName(), TTHValue(string(39, 'A'))));
aResults.push_back(sr);
ShareManager::getInstance()->setHits(ShareManager::getInstance()->getHits()+1);
}
if(aFileType != SearchManager::TYPE_DIRECTORY) {
for(auto& i: files) {
+ if(!i.tth) { continue; }
if(aSearchType == SearchManager::SIZE_ATLEAST && aSize > i.getSize()) {
continue;
@@ -1190,7 +1206,7 @@
// Check file type...
if(checkType(i.getName(), aFileType)) {
- SearchResultPtr sr(new SearchResult(SearchResult::TYPE_FILE, i.getSize(), getFullName() + i.getName(), i.getTTH()));
+ SearchResultPtr sr(new SearchResult(SearchResult::TYPE_FILE, i.getSize(), getFullName() + i.getName(), *i.tth));
aResults.push_back(sr);
ShareManager::getInstance()->setHits(ShareManager::getInstance()->getHits()+1);
if(aResults.size() >= maxResults) {
@@ -1213,7 +1229,7 @@
auto i = tthIndex.find(tth);
if(i != tthIndex.end()) {
SearchResultPtr sr(new SearchResult(SearchResult::TYPE_FILE, i->second->getSize(),
- i->second->getParent()->getFullName() + i->second->getName(), i->second->getTTH()));
+ i->second->getParent()->getFullName() + i->second->getName(), *i->second->tth));
results.push_back(sr);
ShareManager::getInstance()->addHits(1);
@@ -1245,7 +1261,7 @@
}
ShareManager::AdcSearch::AdcSearch(const StringList& params) : include(&includeX), gt(0),
- lt(numeric_limits<int64_t>::max()), hasRoot(false), isDirectory(false)
+ lt(numeric_limits<int64_t>::max()), isDirectory(false)
{
for(const auto& p: params) {
if(p.length() <= 2)
@@ -1253,7 +1269,6 @@
uint16_t cmd = toCode(p[0], p[1]);
if(toCode('T', 'R') == cmd) {
- hasRoot = true;
root = TTHValue(p.substr(2));
return;
} else if(toCode('A', 'N') == cmd) {
@@ -1324,13 +1339,15 @@
bool sizeOk = (aStrings.gt == 0);
if( cur->empty() && aStrings.ext.empty() && sizeOk ) {
// We satisfied all the search words! Add the directory...
- SearchResultPtr sr(new SearchResult(SearchResult::TYPE_DIRECTORY, getSize(), getFullName(), TTHValue()));
+ /// @todo send the directory hash when we have one
+ SearchResultPtr sr(new SearchResult(SearchResult::TYPE_DIRECTORY, getSize(), getFullName(), TTHValue(string(39, 'A'))));
aResults.push_back(sr);
ShareManager::getInstance()->setHits(ShareManager::getInstance()->getHits()+1);
}
if(!aStrings.isDirectory) {
for(auto& i: files) {
+ if(!i.tth) { continue; }
if(!(i.getSize() >= aStrings.gt)) {
continue;
@@ -1352,7 +1369,7 @@
if(aStrings.hasExt(i.getName())) {
SearchResultPtr sr(new SearchResult(SearchResult::TYPE_FILE,
- i.getSize(), getFullName() + i.getName(), i.getTTH()));
+ i.getSize(), getFullName() + i.getName(), *i.tth));
aResults.push_back(sr);
ShareManager::getInstance()->addHits(1);
if(aResults.size() >= maxResults) {
@@ -1373,12 +1390,12 @@
Lock l(cs);
- if(srch.hasRoot) {
- auto i = tthIndex.find(srch.root);
+ if(srch.root) {
+ auto i = tthIndex.find(*srch.root);
if(i != tthIndex.end()) {
SearchResultPtr sr(new SearchResult(SearchResult::TYPE_FILE,
i->second->getSize(), i->second->getParent()->getFullName() + i->second->getName(),
- i->second->getTTH()));
+ *i->second->tth));
results.push_back(sr);
addHits(1);
}
@@ -1395,9 +1412,9 @@
}
}
-ShareManager::Directory::Ptr ShareManager::getDirectory(const string& fname) {
+ShareManager::Directory::Ptr ShareManager::getDirectory(const string& realPath) noexcept {
for(auto& mi: shares) {
- if(Util::strnicmp(fname, mi.first, mi.first.length()) == 0) {
+ if(Util::strnicmp(realPath, mi.first, mi.first.length()) == 0) {
Directory::Ptr d;
for(auto& i: directories) {
if(Util::stricmp(i->getName(), mi.second) == 0) {
@@ -1411,8 +1428,8 @@
string::size_type i;
string::size_type j = mi.first.length();
- while( (i = fname.find(PATH_SEPARATOR, j)) != string::npos) {
- auto dmi = d->directories.find(fname.substr(j, i-j));
+ while( (i = realPath.find(PATH_SEPARATOR, j)) != string::npos) {
+ auto dmi = d->directories.find(realPath.substr(j, i-j));
j = i + 1;
if(dmi == d->directories.end())
return Directory::Ptr();
@@ -1424,42 +1441,82 @@
return Directory::Ptr();
}
-void ShareManager::on(QueueManagerListener::FileMoved, const string& n) noexcept {
+optional<const ShareManager::Directory::File&> ShareManager::getFile(const string& realPath, Directory::Ptr d) noexcept {
+ if(!d) {
+ d = getDirectory(realPath);
+ if(!d) {
+ return nullptr;
+ }
+ }
+
+ auto i = d->findFile(Util::getFileName(realPath));
+ if(i == d->files.end()) {
+ /* should never happen, but let's fail gracefully (maybe a synchro issue with a dir being
+ removed during hashing...)... */
+ dcdebug("ShareManager::getFile: the file <%s> could not be found, strange!\n", realPath.c_str());
+ return nullptr;
+ }
+
+ if(i->realPath && i->realPath == realPath) {
+ /* lucky! the base file already had a real path set (should never happen - it's only for
+ dupes). */
+ dcdebug("ShareManager::getFile: wtf, a non-renamed file has realPath set: <%s>\n", realPath.c_str());
+ return *i;
+ }
+
+ /* see if the files sorted right before this one have a real path we are looking for. this is
+ the most common case for dupes: "x (1).ext" is sorted before "x.ext". */
+ auto real = i;
+ --real;
+ while(real != d->files.end() && real->realPath) {
+ if(real->realPath == realPath) {
+ return *real;
+ }
+ --real;
+ }
+
+ /* couldn't find it before the base file? maybe it's sorted after; could happen with files with
+ no ext: "x (1)" is sorted after "x". */
+ real = i;
+ ++real;
+ while(real != d->files.end() && real->realPath) {
+ if(real->realPath == realPath) {
+ return *real;
+ }
+ ++real;
+ }
+
+ /* most common case: no duplicate; just return the base file. */
+ return *i;
+}
+
+void ShareManager::on(QueueManagerListener::FileMoved, const string& realPath) noexcept {
if(SETTING(ADD_FINISHED_INSTANTLY)) {
- // Check if finished download is supposed to be shared
+ auto size = File::getSize(realPath);
+ if(size == -1) {
+ // looks like the file isn't actually there...
+ return;
+ }
+
Lock l(cs);
- for(auto& i: shares) {
- if(Util::strnicmp(i.first, n, i.first.size()) == 0 && n[i.first.size() - 1] == PATH_SEPARATOR) {
- try {
- // Schedule for hashing, it'll be added automatically later on...
- HashManager::getInstance()->checkTTH(n, File::getSize(n), 0);
- } catch(const Exception&) {
- // Not a vital feature...
- }
- break;
- }
+ // Check if the finished download dir is supposed to be shared
+ auto dir = getDirectory(realPath);
+ if(dir) {
+ dir->files.insert(Directory::File(Util::getFileName(realPath), size, dir,
+ HashManager::getInstance()->getTTH(realPath, size, 0)));
}
}
}
-void ShareManager::on(HashManagerListener::TTHDone, const string& fname, const TTHValue& root) noexcept {
+void ShareManager::on(HashManagerListener::TTHDone, const string& realPath, const TTHValue& root) noexcept {
Lock l(cs);
- Directory::Ptr d = getDirectory(fname);
- if(d) {
- auto i = d->findFile(Util::getFileName(fname));
- if(i != d->files.end()) {
- if(root != i->getTTH())
- tthIndex.erase(i->getTTH());
- // Get rid of false constness...
- auto f = const_cast<Directory::File*>(&(*i));
- f->setTTH(root);
- tthIndex[f->getTTH()] = i;
- } else {
- string name = Util::getFileName(fname);
- int64_t size = File::getSize(fname);
- auto it = d->files.insert(Directory::File(name, size, d, root)).first;
- updateIndices(*d, it);
- }
+ auto f = getFile(realPath);
+ if(f) {
+ if(f->tth && root != f->tth)
+ tthIndex.erase(*f->tth);
+ const_cast<Directory::File&>(*f).tth = root;
+ tthIndex[*f->tth] = &f.get();
+
setDirty();
forceXmlRefresh = true;
}
=== modified file 'dcpp/ShareManager.h'
--- dcpp/ShareManager.h 2012-12-12 22:44:47 +0000
+++ dcpp/ShareManager.h 2012-12-13 17:04:31 +0000
@@ -20,6 +20,7 @@
#define DCPLUSPLUS_DCPP_SHARE_MANAGER_H
#include <list>
+#include <map>
#include <memory>
#include <set>
#include <unordered_map>
@@ -45,10 +46,13 @@
namespace dcpp {
+using std::map;
using std::set;
using std::unique_ptr;
using std::unordered_map;
+using boost::optional;
+
STANDARD_EXCEPTION(ShareException);
class SimpleXML;
@@ -75,7 +79,7 @@
/** @return Actual file path & size. Returns 0 for file lists. */
pair<string, int64_t> toRealWithSize(const string& virtualFile);
StringList getRealPaths(const string& virtualPath);
- TTHValue getTTH(const string& virtualFile) const;
+ optional<TTHValue> getTTH(const string& virtualFile) const;
void refresh(bool dirs = false, bool aUpdate = true, bool block = false) noexcept;
void setDirty() { xmlDirty = true; }
@@ -143,8 +147,8 @@
typedef set<File, FileLess> Set;
File() : size(0), parent(0) { }
- File(const string& aName, int64_t aSize, const Directory::Ptr& aParent, const TTHValue& aRoot) :
- name(aName), tth(aRoot), size(aSize), parent(aParent.get()) { }
+ File(const string& aName, int64_t aSize, const Directory::Ptr& aParent, const optional<TTHValue>& aRoot) :
+ name(aName), tth(aRoot), size(aSize), parent(aParent.get()) { }
bool operator==(const File& rhs) const {
return getParent() == rhs.getParent() && (Util::stricmp(getName(), rhs.getName()) == 0);
@@ -161,12 +165,10 @@
string getRealPath() const { return realPath ? realPath.get() : parent->getRealPath(name); }
GETSET(string, name, Name);
- GETSET(TTHValue, tth, TTH);
+ optional<string> realPath; // only defined if this file had to be renamed to avoid duplication.
+ optional<TTHValue> tth;
GETSET(int64_t, size, Size);
GETSET(Directory*, parent, Parent);
-
- private:
- boost::optional<string> realPath;
};
int64_t size;
@@ -237,16 +239,15 @@
int64_t gt;
int64_t lt;
- TTHValue root;
- bool hasRoot;
+ optional<TTHValue> root;
bool isDirectory;
};
int64_t xmlListLen;
- TTHValue xmlRoot;
+ optional<TTHValue> xmlRoot;
int64_t bzXmlListLen;
- TTHValue bzXmlRoot;
+ optional<TTHValue> bzXmlRoot;
unique_ptr<File> bzXmlRef;
bool xmlDirty;
@@ -272,14 +273,11 @@
The map is sorted to make sure conflicts are always resolved in the same order when merging. */
map<string, string> shares;
- typedef unordered_map<TTHValue, Directory::File::Set::const_iterator> HashFileMap;
- typedef HashFileMap::iterator HashFileIter;
-
- HashFileMap tthIndex;
+ unordered_map<TTHValue, const Directory::File*> tthIndex;
BloomFilter<5> bloom;
- Directory::File::Set::const_iterator findFile(const string& virtualFile) const;
+ const Directory::File& findFile(const string& virtualFile) const;
Directory::Ptr buildTree(const string& aName, const Directory::Ptr& aParent);
bool checkHidden(const string& aName) const;
@@ -297,15 +295,19 @@
pair<Directory::Ptr, string> splitVirtual(const string& virtualPath) const;
string findRealRoot(const string& virtualRoot, const string& virtualLeaf) const;
- Directory::Ptr getDirectory(const string& fname);
+ /** Get the directory pointer corresponding to a given real path (on disk). Note that only
+ directories are considered here but not the file's base name. */
+ Directory::Ptr getDirectory(const string& realPath) noexcept;
+ /** Get the file corresponding to a given real path (on disk). */
+ optional<const ShareManager::Directory::File&> getFile(const string& realPath, Directory::Ptr d = nullptr) noexcept;
virtual int run();
// QueueManagerListener
- virtual void on(QueueManagerListener::FileMoved, const string& n) noexcept;
+ virtual void on(QueueManagerListener::FileMoved, const string& realPath) noexcept;
// HashManagerListener
- virtual void on(HashManagerListener::TTHDone, const string& fname, const TTHValue& root) noexcept;
+ virtual void on(HashManagerListener::TTHDone, const string& realPath, const TTHValue& root) noexcept;
// SettingsManagerListener
virtual void on(SettingsManagerListener::Save, SimpleXML& xml) noexcept {