← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3157: rename case-insensitive duplicated directories

 

------------------------------------------------------------
revno: 3157
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Mon 2012-12-17 18:07:08 +0100
message:
  rename case-insensitive duplicated directories
modified:
  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/ShareManager.cpp'
--- dcpp/ShareManager.cpp	2012-12-14 17:07:25 +0000
+++ dcpp/ShareManager.cpp	2012-12-17 17:07:08 +0000
@@ -85,6 +85,10 @@
 {
 }
 
+const string& ShareManager::Directory::getRealName() const noexcept {
+	return realName ? realName.get() : name;
+}
+
 string ShareManager::Directory::getADCPath() const noexcept {
 	if(!getParent())
 		return '/' + name + '/';
@@ -107,9 +111,9 @@
 
 string ShareManager::Directory::getRealPath(const std::string& path) const {
 	if(getParent()) {
-		return getParent()->getRealPath(getName() + PATH_SEPARATOR_STR + path);
+		return getParent()->getRealPath(getRealName() + PATH_SEPARATOR_STR + path);
 	} else {
-		return ShareManager::getInstance()->findRealRoot(getName(), path);
+		return ShareManager::getInstance()->findRealRoot(getRealName(), path);
 	}
 }
 
@@ -288,12 +292,12 @@
 		throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
 	}
 
-	auto dmi = getByVirtual( virtualPath.substr(1, i - 1));
+	auto dmi = directories.find(virtualPath.substr(1, i - 1));
 	if(dmi == directories.end()) {
 		throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
 	}
 
-	auto d = *dmi;
+	auto d = dmi->second;
 
 	auto j = i + 1;
 	while((i = virtualPath.find('/', j)) != string::npos) {
@@ -336,7 +340,7 @@
 
 bool ShareManager::hasVirtual(const string& virtualName) const noexcept {
 	Lock l(cs);
-	return getByVirtual(virtualName) != directories.end();
+	return directories.find(virtualName) != directories.end();
 }
 
 void ShareManager::load(SimpleXML& aXml) {
@@ -358,8 +362,8 @@
 			const string& virtualName = aXml.getChildAttrib("Virtual");
 			string vName = validateVirtual(virtualName.empty() ? Util::getLastDir(realPath) : virtualName);
 			shares[move(realPath)] = vName;
-			if(getByVirtual(vName) == directories.end()) {
-				directories.push_back(Directory::create(vName));
+			if(directories.find(vName) == directories.end()) {
+				directories[vName] = Directory::create(vName);
 			}
 		}
 		aXml.stepOut();
@@ -373,17 +377,15 @@
 static const string STTH = "TTH";
 
 struct ShareLoader : public SimpleXMLReader::CallBack {
-	ShareLoader(ShareManager::DirList& aDirs) : dirs(aDirs), cur(0), depth(0) { }
+	ShareLoader(decltype(ShareManager::directories)& aDirs) : dirs(aDirs), cur(0), depth(0) { }
 	void startTag(const string& name, StringPairList& attribs, bool simple) {
 		if(name == SDIRECTORY) {
 			const string& name = getAttrib(attribs, SNAME, 0);
 			if(!name.empty()) {
 				if(depth == 0) {
-					for(auto& i: dirs) {
-						if(Util::stricmp(i->getName(), name) == 0) {
-							cur = i;
-							break;
-						}
+					auto i = dirs.find(name);
+					if(i != dirs.end()) {
+						cur = i->second;
 					}
 				} else if(cur) {
 					cur = ShareManager::Directory::create(name, cur);
@@ -419,7 +421,7 @@
 	}
 
 private:
-	ShareManager::DirList& dirs;
+	decltype(ShareManager::directories)& dirs;
 
 	ShareManager::Directory::Ptr cur;
 	size_t depth;
@@ -435,8 +437,8 @@
 
 		xml.parse(f);
 
-		for(const auto& d: directories) {
-			updateIndices(*d);
+		for(const auto& i: directories) {
+			updateIndices(*i.second);
 		}
 
 		return true;
@@ -487,7 +489,7 @@
 
 	HashManager::HashPauser pauser;
 
-	Directory::Ptr dp = buildTree(realPath, Directory::Ptr());
+	auto dp = buildTree(realPath);
 
 	string vName = validateVirtual(virtualName);
 	dp->setName(vName);
@@ -503,17 +505,16 @@
 }
 
 ShareManager::Directory::Ptr ShareManager::merge(const Directory::Ptr& directory, const string& realPath) {
-	for(auto& i: directories) {
-		if(Util::stricmp(i->getName(), directory->getName()) == 0) {
-			dcdebug("Merging directory <%s> into %s\n", realPath.c_str(), directory->getName().c_str());
-			i->merge(directory, realPath);
-			return i;
-		}
+	auto i = directories.find(directory->getName());
+	if(i != directories.end()) {
+		dcdebug("Merging directory <%s> into %s\n", realPath.c_str(), directory->getName().c_str());
+		i->second->merge(directory, realPath);
+		return i->second;
 	}
 
 	dcdebug("Adding new directory %s\n", directory->getName().c_str());
 
-	directories.push_back(directory);
+	directories[directory->getName()] = directory;
 	return directory;
 }
 
@@ -570,7 +571,7 @@
 			vname = base + " (" + Util::toString(num) + ")" + ext;
 		} while(parent->nameInUse(vname));
 		dcdebug("Renaming duplicate <%s> to <%s>\n", name.c_str(), vname.c_str());
-		realPath = sourcePath + name;
+		realPath = sourcePath + move(name);
 		name = move(vname);
 	} else {
 		realPath.reset();
@@ -591,13 +592,7 @@
 	}
 
 	auto vName = i->second;
-	for(auto j = directories.begin(); j != directories.end(); ) {
-		if(Util::stricmp((*j)->getName(), vName) == 0) {
-			directories.erase(j++);
-		} else {
-			++j;
-		}
-	}
+	directories.erase(vName);
 
 	shares.erase(i);
 
@@ -606,7 +601,7 @@
 	// Readd all directories with the same vName
 	for(i = shares.begin(); i != shares.end(); ++i) {
 		if(Util::stricmp(i->second, vName) == 0 && checkHidden(i->first)) {
-			Directory::Ptr dp = buildTree(i->first, 0);
+			auto dp = buildTree(i->first);
 			dp->setName(i->second);
 			merge(dp, i->first);
 		}
@@ -621,24 +616,15 @@
 	addDirectory(realPath, virtualName);
 }
 
-ShareManager::DirList::const_iterator ShareManager::getByVirtual(const string& virtualName) const noexcept {
-	for(auto i = directories.begin(); i != directories.end(); ++i) {
-		if(Util::stricmp((*i)->getName(), virtualName) == 0) {
-			return i;
-		}
-	}
-	return directories.end();
-}
-
 int64_t ShareManager::getShareSize(const string& realPath) const noexcept {
 	Lock l(cs);
  	dcassert(realPath.size()>0);
 	auto i = shares.find(realPath);
 
 	if(i != shares.end()) {
-		auto j = getByVirtual(i->second);
+		auto j = directories.find(i->second);
 		if(j != directories.end()) {
-			return (*j)->getSize();
+			return j->second->getSize();
 		}
 	}
 	return -1;
@@ -658,27 +644,25 @@
 	return tthIndex.size();
 }
 
-ShareManager::Directory::Ptr ShareManager::buildTree(const string& aName, const Directory::Ptr& aParent) {
-	auto dir = Directory::create(Util::getLastDir(aName), aParent);
+ShareManager::Directory::Ptr ShareManager::buildTree(const string& realPath, optional<const string&> dirName, const Directory::Ptr& parent) {
+	auto dir = Directory::create(dirName ? dirName.get() : Util::getLastDir(realPath), parent);
 
 	auto lastFileIter = dir->files.begin();
 
-	FileFindIter end;
 #ifdef _WIN32
-	for(FileFindIter i(aName + "*"); i != end; ++i) {
+	for(FileFindIter i(realPath + "*"), end; i != end; ++i) {
 #else
 	//the fileiter just searches directorys for now, not sure if more
 	//will be needed later
-	//for(FileFindIter i(aName + "*"); i != end; ++i) {
-	for(FileFindIter i(aName); i != end; ++i) {
+	for(FileFindIter i(realPath), end; i != end; ++i) {
 #endif
-		string name = i->getFileName();
+		auto name = i->getFileName();
 
 		if(name.empty()) {
-			LogManager::getInstance()->message(str(F_("Invalid file name found while hashing folder %1%") % Util::addBrackets(aName)));
+			LogManager::getInstance()->message(str(F_("Invalid file name found while hashing folder %1%") % Util::addBrackets(realPath)));
 			continue;
 		}
-		
+
 		if(name == "." || name == "..")
 			continue;
 		if(!SETTING(SHARE_HIDDEN) && i->isHidden())
@@ -687,24 +671,39 @@
  			continue;
 
 		if(i->isDirectory()) {
-			string newName = aName + name + PATH_SEPARATOR;
-			if(Util::stricmp(newName, SETTING(TEMP_DOWNLOAD_DIRECTORY)) != 0) {
-				dir->directories[name] = buildTree(newName, dir);
-			}
+			auto newRealPath = realPath + name + PATH_SEPARATOR;
+
+			// don't share unfinished downloads
+			if(newRealPath == SETTING(TEMP_DOWNLOAD_DIRECTORY)) { continue; }
+
+			auto virtualName = name;
+			if(dir->nameInUse(virtualName)) {
+				uint32_t num = 0;
+				do {
+					++num;
+					virtualName = name + " (" + Util::toString(num) + ")";
+				} while(dir->nameInUse(virtualName));
+			}
+
+			dir->directories[virtualName] = buildTree(newRealPath, virtualName, dir);
+
+			if(virtualName != name) {
+				dir->directories[virtualName]->setRealName(move(name));
+			}
+
 		} 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) { continue; }
+			if(name == "DCPlusPlus.xml" || name == "Favorites.xml") { continue; }
 
-			int64_t size = i->getSize();
-			string fileName = aName + name;
+			auto size = i->getSize();
+			auto fileName = realPath + name;
 
 			// don't share the private key file
-			if(Util::stricmp(fileName, SETTING(TLS_PRIVATE_KEY_FILE)) == 0) { continue; }
+			if(fileName == SETTING(TLS_PRIVATE_KEY_FILE)) { continue; }
 
 			Directory::File f(name, size, dir,
 				HashManager::getInstance()->getTTH(fileName, size, i->getLastWriteTime()));
-			f.validateName(aName);
+			f.validateName(realPath);
 			lastFileIter = dir->files.insert(lastFileIter, move(f));
 		}
 	}
@@ -712,8 +711,8 @@
 	return dir;
 }
 
-bool ShareManager::checkHidden(const string& aName) const {
-	FileFindIter ff = FileFindIter(aName.substr(0, aName.size() - 1));
+bool ShareManager::checkHidden(const string& realPath) const {
+	FileFindIter ff = FileFindIter(realPath.substr(0, realPath.size() - 1));
 
 	if (ff != FileFindIter()) {
 		return (SETTING(SHARE_HIDDEN) || !ff->isHidden());
@@ -741,11 +740,11 @@
 	bloom.clear();
 
 	for(auto& i: directories) {
-		updateIndices(*i);
+		updateIndices(*i.second);
 	}
 }
 
-void ShareManager::updateIndices(Directory& dir, const Directory::File::Set::iterator& i) {
+void ShareManager::updateIndices(Directory& dir, const decltype(std::declval<Directory>().files.begin())& i) {
 	const Directory::File& f = *i;
 
 	if(!f.tth) {
@@ -826,7 +825,7 @@
 		vector<pair<Directory::Ptr, string>> newDirs;
 		for(auto& i: dirs) {
 			if (checkHidden(i.second)) {
-				Directory::Ptr dp = buildTree(i.second, Directory::Ptr());
+				auto dp = buildTree(i.second);
 				dp->setName(i.first);
 				newDirs.emplace_back(dp, i.second);
 			}
@@ -888,7 +887,7 @@
 				newXmlFile.write(SimpleXML::utf8Header);
 				newXmlFile.write("<FileListing Version=\"1\" CID=\"" + ClientManager::getInstance()->getMe()->getCID().toBase32() + "\" Base=\"/\" Generator=\"" APPNAME " " VERSIONSTRING "\">\r\n");
 				for(auto& i: directories) {
-					i->toXml(newXmlFile, indent, tmp2, -1);
+					i.second->toXml(newXmlFile, indent, tmp2, -1);
 				}
 				newXmlFile.write("</FileListing>");
 				newXmlFile.flush();
@@ -941,7 +940,7 @@
 	if(dir == "/") {
 		for(auto& i: directories) {
 			tmp.clear();
-			i->toXml(sos, indent, tmp, recurse ? -1 : 0);
+			i.second->toXml(sos, indent, tmp, recurse ? -1 : 0);
 		}
 	} else {
 		string::size_type i = 1, j = 1;
@@ -957,11 +956,10 @@
 
 			if(first) {
 				first = false;
-				auto it = getByVirtual(dir.substr(j, i-j));
-
+				auto it = directories.find(dir.substr(j, i-j));
 				if(it == directories.end())
 					return 0;
-				root = *it;
+				root = it->second;
 
 			} else {
 				auto it2 = root->directories.find(dir.substr(j, i-j));
@@ -1254,7 +1252,7 @@
 		return;
 
 	for(auto j = directories.begin(); (j != directories.end()) && (results.size() < maxResults); ++j) {
-		(*j)->search(results, ssl, aSearchType, aSize, aFileType, aClient, maxResults);
+		j->second->search(results, ssl, aSearchType, aSize, aFileType, aClient, maxResults);
 	}
 }
 
@@ -1410,37 +1408,42 @@
 	}
 
 	for(auto j = directories.begin(); (j != directories.end()) && (results.size() < maxResults); ++j) {
-		(*j)->search(results, srch, maxResults);
+		j->second->search(results, srch, maxResults);
 	}
 }
 
 ShareManager::Directory::Ptr ShareManager::getDirectory(const string& realPath) noexcept {
 	for(auto& mi: shares) {
 		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) {
-					d = i;
-				}
-			}
-
-			if(!d) {
-				return Directory::Ptr();
-			}
+			auto di = directories.find(mi.second);
+			if(di == directories.end()) {
+				return nullptr;
+			}
+			auto d = di->second;
 
 			string::size_type i;
 			string::size_type j = mi.first.length();
-			while( (i = realPath.find(PATH_SEPARATOR, j)) != string::npos) {
-				auto dmi = d->directories.find(realPath.substr(j, i-j));
+			while((i = realPath.find(PATH_SEPARATOR, j)) != string::npos) {
+				auto dirName = realPath.substr(j, i - j);
+
+				auto& subDirs = d->directories;
+				d.reset();
+				for(auto& subDir: subDirs) {
+					if(subDir.second->getRealName() == dirName) {
+						d = subDir.second;
+						break;
+					}
+				}
+				if(!d) {
+					return nullptr;
+				}
+
 				j = i + 1;
-				if(dmi == d->directories.end())
-					return Directory::Ptr();
-				d = dmi->second;
 			}
 			return d;
 		}
 	}
-	return Directory::Ptr();
+	return nullptr;
 }
 
 optional<const ShareManager::Directory::File&> ShareManager::getFile(const string& realPath, Directory::Ptr d) noexcept {

=== modified file 'dcpp/ShareManager.h'
--- dcpp/ShareManager.h	2012-12-13 17:50:01 +0000
+++ dcpp/ShareManager.h	2012-12-17 17:07:08 +0000
@@ -19,7 +19,6 @@
 #ifndef DCPLUSPLUS_DCPP_SHARE_MANAGER_H
 #define DCPLUSPLUS_DCPP_SHARE_MANAGER_H
 
-#include <list>
 #include <map>
 #include <memory>
 #include <set>
@@ -130,10 +129,16 @@
 	class Directory : public FastAlloc<Directory>, public intrusive_ptr_base<Directory>, boost::noncopyable {
 	public:
 		typedef boost::intrusive_ptr<Directory> Ptr;
-		typedef unordered_map<string, Ptr, noCaseStringHash, noCaseStringEq> Map;
-		typedef Map::iterator MapIter;
 
 		struct File {
+			File() : size(0), parent(0) { }
+			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);
+			}
+
 			struct StringComp {
 				StringComp(const string& s) : a(s) { }
 				bool operator()(const File& b) const { return Util::stricmp(a, b.getName()) == 0; }
@@ -142,15 +147,6 @@
 			struct FileLess {
 				bool operator()(const File& a, const File& b) const { return (Util::stricmp(a.getName(), b.getName()) < 0); }
 			};
-			typedef set<File, FileLess> Set;
-
-			File() : size(0), parent(0) { }
-			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);
-			}
 
 			/** Ensure this file's name doesn't clash with the names of the parent directory's sub-
 			directories or files; rename to "file (N).ext" otherwise (and set realPath to the
@@ -170,8 +166,8 @@
 		};
 
 		int64_t size;
-		Map directories;
-		File::Set files;
+		unordered_map<string, Ptr, noCaseStringHash, noCaseStringEq> directories;
+		set<File, File::FileLess> files;
 
 		static Ptr create(const string& aName, const Ptr& aParent = Ptr()) { return Ptr(new Directory(aName, aParent)); }
 
@@ -180,6 +176,9 @@
 		}
 		void addType(uint32_t type) noexcept;
 
+		const string& getRealName() const noexcept;
+		template<typename SetT> void setRealName(SetT&& realName) noexcept { this->realName = std::forward<SetT>(realName); }
+
 		string getADCPath() const noexcept;
 		string getFullName() const noexcept;
 		string getRealPath(const std::string& path) const;
@@ -197,21 +196,23 @@
 		void toXml(OutputStream& xmlFile, string& indent, string& tmp2, int8_t level) const;
 		void filesToXml(OutputStream& xmlFile, string& indent, string& tmp2) const;
 
-		File::Set::const_iterator findFile(const string& aFile) const { return find_if(files.begin(), files.end(), Directory::File::StringComp(aFile)); }
+		auto findFile(const string& aFile) const -> decltype(files.cbegin()) { return find_if(files.begin(), files.end(), File::StringComp(aFile)); }
 
 		void merge(const Ptr& source, const string& realPath);
 
 		GETSET(string, name, Name);
 		GETSET(Directory*, parent, Parent);
+
 	private:
 		friend void intrusive_ptr_release(intrusive_ptr_base<Directory>*);
 
 		Directory(const string& aName, const Ptr& aParent);
 		~Directory() { }
 
+		optional<string> realName; // only defined if this directory had to be renamed to avoid duplication.
+
 		/** Set of flags that say which SearchManager::TYPE_* a directory contains */
 		uint32_t fileTypes;
-
 	};
 
 	friend class Directory;
@@ -264,8 +265,7 @@
 	mutable CriticalSection cs;
 
 	// List of root directory items
-	typedef std::list<Directory::Ptr> DirList;
-	DirList directories;
+	unordered_map<string, Directory::Ptr, noCaseStringHash, noCaseStringEq> directories;
 
 	/** Map real name to virtual name - multiple real names may be mapped to a single virtual one.
 	The map is sorted to make sure conflicts are always resolved in the same order when merging. */
@@ -277,19 +277,18 @@
 
 	const Directory::File& findFile(const string& virtualFile) const;
 
-	Directory::Ptr buildTree(const string& aName, const Directory::Ptr& aParent);
-	bool checkHidden(const string& aName) const;
+	Directory::Ptr buildTree(const string& realPath, optional<const string&> dirName = nullptr, const Directory::Ptr& parent = nullptr);
+	bool checkHidden(const string& realPath) const;
 
 	void rebuildIndices();
 
 	void updateIndices(Directory& aDirectory);
-	void updateIndices(Directory& dir, const Directory::File::Set::iterator& i);
+	void updateIndices(Directory& dir, const decltype(std::declval<Directory>().files.begin())& i);
 
 	Directory::Ptr merge(const Directory::Ptr& directory, const string& realPath);
 
 	void generateXmlList();
 	bool loadCache() noexcept;
-	DirList::const_iterator getByVirtual(const string& virtualName) const noexcept;
 	pair<Directory::Ptr, string> splitVirtual(const string& virtualPath) const;
 	string findRealRoot(const string& virtualRoot, const string& virtualLeaf) const;