------------------------------------------------------------ revno: 3152 committer: poy <p...@123gen.com> 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 {
_______________________________________________ Mailing list: https://launchpad.net/~linuxdcpp-team Post to : linuxdcpp-team@lists.launchpad.net Unsubscribe : https://launchpad.net/~linuxdcpp-team More help : https://help.launchpad.net/ListHelp