linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #06361
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3159: Reject file lists that contain duplicate items
------------------------------------------------------------
revno: 3159
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Thu 2012-12-20 20:38:26 +0100
message:
Reject file lists that contain duplicate items
modified:
changelog.txt
dcpp/ADLSearch.cpp
dcpp/DirectoryListing.cpp
dcpp/DirectoryListing.h
win32/DirectoryListingFrame.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-17 18:49:40 +0000
+++ changelog.txt 2012-12-20 19:38:26 +0000
@@ -11,8 +11,11 @@
* [L#1071363] Apply link & plugin formatting to status messages (crise, poy)
* [L#311818] Share file name duplicates due to directory merges (poy)
* [L#311818] Share file name duplicates due to case differences (poy)
+* [L#311818] Reject file lists that contain duplicate items (poy)
-Note for XP users: shared files will have to be re-hashed.
+Note: The hash registry will be upgraded when running this version for the
+first time. Make sure all your drives are connected to avoid re-hashing.
+That upgrade only works on Win >= Vista; re-hashing is compulsory on XP.
-- 0.802 2012-10-20 --
* Perf improvements using lock-free queues, requires P6 CPUs (poy)
=== modified file 'dcpp/ADLSearch.cpp'
--- dcpp/ADLSearch.cpp 2012-06-21 18:52:47 +0000
+++ dcpp/ADLSearch.cpp 2012-12-20 19:38:26 +0000
@@ -287,7 +287,7 @@
DirectoryListing::File *copyFile = new DirectoryListing::File(*currentFile, true);
dcassert(id.subdir->getAdls());
- id.subdir->files.push_back(copyFile);
+ id.subdir->files.insert(copyFile);
}
id.fileAdded = false; // Prepare for next stage
}
@@ -305,7 +305,7 @@
}
if(is.matchesFile(currentFile->getName(), filePath, currentFile->getSize())) {
DirectoryListing::File *copyFile = new DirectoryListing::File(*currentFile, true);
- destDirVector[is.ddIndex].dir->files.push_back(copyFile);
+ destDirVector[is.ddIndex].dir->files.insert(copyFile);
destDirVector[is.ddIndex].fileAdded = true;
if(is.isAutoQueue){
@@ -329,7 +329,7 @@
if(id.subdir != NULL) {
DirectoryListing::Directory* newDir =
new DirectoryListing::AdlDirectory(fullPath, id.subdir, currentDir->getName());
- id.subdir->directories.push_back(newDir);
+ id.subdir->directories.insert(newDir);
id.subdir = newDir;
}
}
@@ -347,7 +347,7 @@
if(is.matchesDirectory(currentDir->getName())) {
destDirVector[is.ddIndex].subdir =
new DirectoryListing::AdlDirectory(fullPath, destDirVector[is.ddIndex].dir, currentDir->getName());
- destDirVector[is.ddIndex].dir->directories.push_back(destDirVector[is.ddIndex].subdir);
+ destDirVector[is.ddIndex].dir->directories.insert(destDirVector[is.ddIndex].subdir);
if(breakOnFirst) {
// Found a match, search no more
break;
@@ -417,7 +417,7 @@
} else if(Util::stricmp(i.dir->getName(), szDiscard) == 0) {
delete i.dir;
} else {
- root->directories.push_back(i.dir);
+ root->directories.insert(i.dir);
}
}
}
=== modified file 'dcpp/DirectoryListing.cpp'
--- dcpp/DirectoryListing.cpp 2012-12-13 17:50:01 +0000
+++ dcpp/DirectoryListing.cpp 2012-12-20 19:38:26 +0000
@@ -179,45 +179,49 @@
return;
TTHValue tth(h); /// @todo verify validity?
- if(updating) {
- // just update the current file if it is already there.
- for(auto& i: cur->files) {
- auto& file = *i;
- /// @todo comparisons should be case-insensitive but it takes too long - add a cache
- if(file.getTTH() == tth || file.getName() == n) {
- file.setName(n);
- file.setSize(size);
- file.setTTH(tth);
- return;
- }
+ auto f = new DirectoryListing::File(cur, n, size, tth);
+ auto insert = cur->files.insert(f);
+
+ if(!insert.second) {
+ // the file was already there
+ delete f;
+ if(updating) {
+ // partial file list
+ f = *insert.first;
+ f->setName(n); // the casing might have changed
+ f->setSize(size);
+ f->setTTH(tth);
+ } else {
+ // duplicates are forbidden in complete file lists
+ throw Exception(_("Duplicate item in the file list"));
}
}
- DirectoryListing::File* f = new DirectoryListing::File(cur, n, size, tth);
- cur->files.push_back(f);
-
} else if(name == sDirectory) {
const string& n = getAttrib(attribs, sName, 0);
if(n.empty()) {
throw SimpleXMLException(_("Directory missing name attribute"));
}
+
bool incomp = getAttrib(attribs, sIncomplete, 1) == "1";
- DirectoryListing::Directory* d = nullptr;
- if(updating) {
- for(auto i: cur->directories) {
- /// @todo comparisons should be case-insensitive but it takes too long - add a cache
- if(i->getName() == n) {
- d = i;
- if(!d->getComplete())
- d->setComplete(!incomp);
- break;
- }
+
+ auto d = new DirectoryListing::Directory(cur, n, false, !incomp);
+ auto insert = cur->directories.insert(d);
+
+ if(!insert.second) {
+ // the dir was already there
+ delete d;
+ if(updating) {
+ // partial file list
+ d = *insert.first;
+ if(!d->getComplete())
+ d->setComplete(!incomp);
+ } else {
+ // duplicates are forbidden in complete file lists
+ throw Exception(_("Duplicate item in the file list"));
}
}
- if(!d) {
- d = new DirectoryListing::Directory(cur, n, false, !incomp);
- cur->directories.push_back(d);
- }
+
cur = d;
if(simple) {
@@ -225,6 +229,7 @@
endTag(name);
}
}
+
} else if(name == sFileListing) {
const string& b = getAttrib(attribs, sBase, 2);
if(b.size() >= 1 && b[0] == '/' && *(b.end() - 1) == '/') {
@@ -245,7 +250,7 @@
}
if(!d) {
d = new DirectoryListing::Directory(cur, i, false, false);
- cur->directories.push_back(d);
+ cur->directories.insert(d);
}
cur = d;
}
@@ -339,26 +344,6 @@
stream.write(getTTH().toBase32(tmp));
stream.write(LIT("\"/>\r\n"));
}
-
-void DirectoryListing::sortDirs() {
- root->sortDirs();
-}
-
-void DirectoryListing::Directory::sortDirs() {
- for(auto d: directories) {
- d->sortDirs();
- }
- sort(directories.begin(), directories.end(), Directory::Sort());
-}
-
-bool DirectoryListing::Directory::Sort::operator()(const Ptr& a, const Ptr& b) const {
- return compare(a->getName(), b->getName()) < 0;
-}
-
-bool DirectoryListing::File::Sort::operator()(const Ptr& a, const Ptr& b) const {
- return compare(a->getName(), b->getName()) < 0;
-}
-
void DirectoryListing::setComplete(bool complete) {
root->setAllComplete(complete);
}
@@ -404,17 +389,12 @@
}
void DirectoryListing::download(Directory* aDir, const string& aTarget, bool highPrio) {
- string tmp;
string target = (aDir == getRoot()) ? aTarget : aTarget + aDir->getName() + PATH_SEPARATOR;
// First, recurse over the directories
- Directory::List& lst = aDir->directories;
- sort(lst.begin(), lst.end(), Directory::Sort());
- for(auto& j: lst) {
+ for(auto& j: aDir->directories) {
download(j, target, highPrio);
}
// Then add the files
- File::List& l = aDir->files;
- sort(l.begin(), l.end(), File::Sort());
for(auto file: aDir->files) {
try {
download(file, target + file->getName(), false, highPrio);
@@ -458,25 +438,9 @@
return nullptr;
}
-struct HashContained {
- HashContained(const DirectoryListing::Directory::TTHSet& l) : tl(l) { }
- const DirectoryListing::Directory::TTHSet& tl;
- bool operator()(const DirectoryListing::File::Ptr i) const {
- return tl.count((i->getTTH())) && (DeleteFunction()(i), true);
- }
-};
-
-struct DirectoryEmpty {
- bool operator()(const DirectoryListing::Directory::Ptr i) const {
- bool r = i->getFileCount() + i->directories.size() == 0;
- if (r) DeleteFunction()(i);
- return r;
- }
-};
-
DirectoryListing::Directory::~Directory() {
- for_each(directories.begin(), directories.end(), DeleteFunction());
- for_each(files.begin(), files.end(), DeleteFunction());
+ std::for_each(directories.begin(), directories.end(), DeleteFunction());
+ std::for_each(files.begin(), files.end(), DeleteFunction());
}
void DirectoryListing::Directory::filterList(DirectoryListing& dirList) {
@@ -488,9 +452,28 @@
}
void DirectoryListing::Directory::filterList(DirectoryListing::Directory::TTHSet& l) {
- for(auto i: directories) i->filterList(l);
- directories.erase(std::remove_if(directories.begin(),directories.end(),DirectoryEmpty()),directories.end());
- files.erase(std::remove_if(files.begin(),files.end(),HashContained(l)),files.end());
+ for(auto i = directories.begin(); i != directories.end();) {
+ auto d = *i;
+
+ d->filterList(l);
+
+ if(d->directories.empty() || d->files.empty()) {
+ i = directories.erase(i);
+ delete d;
+ } else {
+ ++i;
+ }
+ }
+
+ for(auto i = files.begin(); i != files.end();) {
+ auto f = *i;
+ if(l.find(f->getTTH()) != l.end()) {
+ i = files.erase(i);
+ delete f;
+ } else {
+ ++i;
+ }
+ }
}
void DirectoryListing::Directory::getHashList(DirectoryListing::Directory::TTHSet& l) {
=== modified file 'dcpp/DirectoryListing.h'
--- dcpp/DirectoryListing.h 2012-12-13 17:50:01 +0000
+++ dcpp/DirectoryListing.h 2012-12-20 19:38:26 +0000
@@ -19,6 +19,10 @@
#ifndef DCPLUSPLUS_DCPP_DIRECTORY_LISTING_H
#define DCPLUSPLUS_DCPP_DIRECTORY_LISTING_H
+#include <set>
+
+#include <boost/noncopyable.hpp>
+
#include "forward.h"
#include "noexcept.h"
@@ -30,6 +34,8 @@
namespace dcpp {
+using std::set;
+
class ListLoader;
class DirectoryListing : boost::noncopyable
@@ -37,11 +43,9 @@
public:
class Directory;
- class File : public FastAlloc<File> {
+ class File : public FastAlloc<File>, boost::noncopyable {
public:
typedef File* Ptr;
- typedef vector<Ptr> List;
- typedef List::iterator Iter;
File(Directory* aDir, const string& aName, int64_t aSize, const TTHValue& aTTH) noexcept :
name(aName), size(aSize), parent(aDir), tthRoot(aTTH), adls(false)
@@ -54,8 +58,6 @@
void save(OutputStream& stream, string& indent, string& tmp) const;
- struct Sort { bool operator()(const Ptr& a, const Ptr& b) const; };
-
GETSET(string, name, Name);
GETSET(int64_t, size, Size);
GETSET(Directory*, parent, Parent);
@@ -66,13 +68,15 @@
class Directory : public FastAlloc<Directory>, boost::noncopyable {
public:
typedef Directory* Ptr;
- typedef vector<Ptr> List;
- typedef List::iterator Iter;
typedef unordered_set<TTHValue> TTHSet;
- List directories;
- File::List files;
+ template<typename T> struct Less {
+ bool operator()(typename T::Ptr a, typename T::Ptr b) const { return compare(a->getName(), b->getName()) < 0; }
+ };
+
+ set<Ptr, Less<Directory>> directories;
+ set<File::Ptr, Less<File>> files;
Directory(Directory* aParent, const string& aName, bool _adls, bool aComplete)
: name(aName), parent(aParent), adls(_adls), complete(aComplete) { }
@@ -85,7 +89,6 @@
void filterList(TTHSet& l);
void getHashList(TTHSet& l);
void save(OutputStream& stream, string& indent, string& tmp) const;
- void sortDirs();
void setAllComplete(bool complete);
size_t getFileCount() const { return files.size(); }
@@ -98,8 +101,6 @@
return x;
}
- struct Sort { bool operator()(const Ptr& a, const Ptr& b) const; };
-
GETSET(string, name, Name);
GETSET(Directory*, parent, Parent);
GETSET(bool, adls, Adls);
@@ -123,8 +124,6 @@
/** write an XML representation of this file list to the specified file. */
void save(const string& path) const;
- /** sort directories and sub-directories recursively (case-insensitive). */
- void sortDirs();
/** recursively mark directories and sub-directories as complete or incomplete. */
void setComplete(bool complete);
=== modified file 'win32/DirectoryListingFrame.cpp'
--- win32/DirectoryListingFrame.cpp 2012-11-05 20:39:11 +0000
+++ win32/DirectoryListingFrame.cpp 2012-12-20 19:38:26 +0000
@@ -469,9 +469,6 @@
step("ADLS");
ADLSearchManager::getInstance()->matchListing(*parent.dl);
- step("sorting dirs");
- parent.dl->sortDirs();
-
step("caching dirs");
cacheDirs(parent.dl->getRoot());
@@ -659,8 +656,7 @@
}
dirs->erase(dir);
dir = dirs->getChild(treeRoot);
- auto& pdirs = d->getParent()->directories;
- pdirs.erase(std::remove(pdirs.begin(), pdirs.end(), d), pdirs.end());
+ d->getParent()->directories.erase(d);
delete d;
} else {
dir = dirs->getNextSibling(dir);
@@ -668,8 +664,6 @@
}
ADLSearchManager::getInstance()->matchListing(*dl);
- dl->sortDirs();
-
loaded = true;
addRecent();