linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #06359
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3158: avoid re-hashing when upgrading the hash registry to v3
------------------------------------------------------------
revno: 3158
committer: poy <poy@xxxxxxxxxx>
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);
}