------------------------------------------------------------ revno: 3158 committer: poy <p...@123gen.com> branch nick: trunk timestamp: Mon 2012-12-17 19:49:40 +0100 message: avoid re-hashing when upgrading the hash registry to v3 modified: changelog.txt dcpp/HashManager.cpp
-- 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 'changelog.txt' --- changelog.txt 2012-12-14 17:07:25 +0000 +++ changelog.txt 2012-12-17 18:49:40 +0000 @@ -1,7 +1,3 @@ -*** WARNING *** - In order to allow case-sensitive sharing, your files will have to be - re-hashed. Hashes stored by queued downloads won't be lost. -*** WARNING *** * Fix a race condition on file list download (thanks bigmuscle) * [L#668548] Fix a potential infinite loop in BufferedSocket->setDataMode (crise) * Add "chunked" transfer encoding as per the HTTP/1.1 spec (crise) @@ -16,6 +12,8 @@ * [L#311818] Share file name duplicates due to directory merges (poy) * [L#311818] Share file name duplicates due to case differences (poy) +Note for XP users: shared files will have to be re-hashed. + -- 0.802 2012-10-20 -- * Perf improvements using lock-free queues, requires P6 CPUs (poy) * Reduce freezes when displaying file list dirs that contain lots of files (poy) === modified file 'dcpp/HashManager.cpp' --- dcpp/HashManager.cpp 2012-12-14 17:07:25 +0000 +++ dcpp/HashManager.cpp 2012-12-17 18:49:40 +0000 @@ -331,6 +331,7 @@ HashManager::HashStore& store; int version; + string file; bool inTrees; bool inFiles; @@ -349,6 +350,93 @@ } } +namespace { +/* version 2 files were stored in lower-case; carry the file registration over only if the file can +be found, and if it has no case-insensitive duplicate. */ + +#ifdef _WIN32 + +/* we are going to use GetFinalPathNameByHandle to retrieve a properly cased path out of the +lower-case one that the version 2 file registry has provided us with. that API is only available +on Windows >= Vista. */ +typedef DWORD (WINAPI *t_GetFinalPathNameByHandle)(HANDLE, LPTSTR, DWORD, DWORD); +t_GetFinalPathNameByHandle initGFPNBH() { + static bool init = false; + static t_GetFinalPathNameByHandle GetFinalPathNameByHandle = nullptr; + + if(!init) { + init = true; + + auto lib = ::LoadLibrary(_T("kernel32.dll")); + if(lib) { + GetFinalPathNameByHandle = reinterpret_cast<t_GetFinalPathNameByHandle>( + ::GetProcAddress(lib, "GetFinalPathNameByHandleW")); + } + } + + return GetFinalPathNameByHandle; +} + +bool upgradeFromV2(string& file) { + auto GetFinalPathNameByHandle = initGFPNBH(); + if(!GetFinalPathNameByHandle) { + return false; + } + + WIN32_FIND_DATA data; + // FindFirstFile does a case-insensitive search by default + auto handle = ::FindFirstFile(Text::toT(file).c_str(), &data); + if(handle == INVALID_HANDLE_VALUE) { + // file not found + return false; + } + if(::FindNextFile(handle, &data)) { + // found a dupe + ::FindClose(handle); + return false; + } + ::FindClose(handle); + + // don't use dcpp::File as that would be case-sensitive + handle = ::CreateFile((Text::toT(Util::getFilePath(file)) + data.cFileName).c_str(), + GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if(handle == INVALID_HANDLE_VALUE) { + return false; + } + + wstring buf(file.size() * 2, 0); + buf.resize(GetFinalPathNameByHandle(handle, &buf[0], buf.size(), 0)); + + ::CloseHandle(handle); + + if(buf.empty()) { + return false; + } + // GetFinalPathNameByHandle prepends "\\?\"; remove it. + if(buf.size() >= 4 && buf.substr(0, 4) == L"\\\\?\\") { + buf.erase(0, 4); + } + + auto buf8 = Text::fromT(buf); + if(Text::toLower(buf8) == file) { + file = move(buf8); + return true; + } + + return false; +} + +#else + +bool upgradeFromV2(string& file) { + /// @todo implement this on Linux; by default, force re-hashing. + return false; +} + +#endif + +} + static const string sHashStore = "HashStore"; static const string sversion = "version"; // Oops, v1 was like this static const string sVersion = "Version"; @@ -373,7 +461,6 @@ } inHashStore = !simple; } else if (inHashStore && (version == 2 || version == 3)) { - // when upgrading from version 2 to 3, import trees but not the file registry. if (inTrees && name == sHash) { const string& type = getAttrib(attribs, sType, 0); int64_t index = Util::toInt64(getAttrib(attribs, sIndex, 1)); @@ -383,12 +470,11 @@ if (!root.empty() && type == sTTH && (index >= 8 || index == HashManager::SMALL_TREE) && blockSize >= 1024) { store.treeIndex[TTHValue(root)] = HashManager::HashStore::TreeInfo(size, index, blockSize); } - } else if (inFiles && version != 2 && name == sFile) { - const auto& file = getAttrib(attribs, sName, 0); + } else if (inFiles && name == sFile) { + file = getAttrib(attribs, sName, 0); auto timeStamp = Util::toUInt32(getAttrib(attribs, sTimeStamp, 1)); const auto& root = getAttrib(attribs, sRoot, 2); - - if (!file.empty() && timeStamp > 0 && !root.empty()) { + if(!file.empty() && timeStamp > 0 && !root.empty() && (version != 2 || upgradeFromV2(file))) { auto fname = Util::getFileName(file), fpath = Util::getFilePath(file); store.fileIndex[fpath].emplace_back(fname, TTHValue(root), timeStamp, false); }
_______________________________________________ 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