📄 sharemanager.cpp
字号:
tmp += i->second->getSize();
}
return tmp;
}
size_t ShareManager::getSharedFiles() throw() {
RLock<> l(cs);
size_t tmp = 0;
for(Directory::MapIter i = directories.begin(); i != directories.end(); ++i) {
tmp += i->second->countFiles();
}
return tmp;
}
string ShareManager::Directory::getADCPath() const throw() {
if(parent == NULL)
return '/' + name + '/';
return parent->getADCPath() + name + '/';
}
string ShareManager::Directory::getFullName() const throw() {
if(parent == NULL)
return getName() + '\\';
return parent->getFullName() + getName() + '\\';
}
void ShareManager::Directory::addType(u_int32_t type) throw() {
if(!hasType(type)) {
fileTypes |= (1 << type);
if(getParent() != NULL)
getParent()->addType(type);
}
}
class FileFindIter {
#ifdef _WIN32
public:
/** End iterator constructor */
FileFindIter() : handle(INVALID_HANDLE_VALUE) { }
/** Begin iterator constructor, path in utf-8 */
FileFindIter(const string& path) : handle(INVALID_HANDLE_VALUE) {
handle = ::FindFirstFile(Text::toT(path).c_str(), &data);
}
~FileFindIter() {
if(handle != INVALID_HANDLE_VALUE) {
::FindClose(handle);
}
}
FileFindIter& operator++() {
if(!::FindNextFile(handle, &data)) {
::FindClose(handle);
handle = INVALID_HANDLE_VALUE;
}
return *this;
}
bool operator!=(const FileFindIter& rhs) const { return handle != rhs.handle; }
struct DirData : public WIN32_FIND_DATA {
string getFileName() {
return Text::fromT(cFileName);
}
bool isDirectory() {
return (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0;
}
bool isHidden() {
return ((dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) || (cFileName[0] == L'.'));
}
int64_t getSize() {
return (int64_t)nFileSizeLow | ((int64_t)nFileSizeHigh)<<32;
}
u_int32_t getLastWriteTime() {
return File::convertTime(&ftLastWriteTime);
}
};
private:
HANDLE handle;
#else
// This code has been cleaned up/fixed a little.
public:
FileFindIter() {
dir = NULL;
data.ent = NULL;
}
~FileFindIter() {
if (dir) closedir(dir);
}
FileFindIter(const string& name) {
dir = opendir(name.c_str());
if (!dir)
return;
data.base = name;
data.ent = readdir(dir);
if (!data.ent) {
closedir(dir);
dir = NULL;
}
}
FileFindIter& operator++() {
if (!dir)
return *this;
data.ent = readdir(dir);
if (!data.ent) {
closedir(dir);
dir = NULL;
}
return *this;
}
// good enough to to say if it's null
bool operator !=(const FileFindIter& rhs) const {
return dir != rhs.dir;
}
struct DirData {
DirData() : ent(NULL) {}
string getFileName() {
if (!ent) return Util::emptyString;
return string(ent->d_name);
}
bool isDirectory() {
struct stat inode;
if (!ent) return false;
if (stat((base + PATH_SEPARATOR + ent->d_name).c_str(), &inode) == -1) return false;
return S_ISDIR(inode.st_mode);
}
bool isHidden() {
if (!ent) return false;
return ent->d_name[0] == '.';
}
int64_t getSize() {
struct stat inode;
if (!ent) return false;
if (stat((base + PATH_SEPARATOR + ent->d_name).c_str(), &inode) == -1) return 0;
return inode.st_size;
}
u_int32_t getLastWriteTime() {
struct stat inode;
if (!ent) return false;
if (stat((base + PATH_SEPARATOR + ent->d_name).c_str(), &inode) == -1) return 0;
return inode.st_mtime;
}
struct dirent* ent;
string base;
};
private:
DIR* dir;
#endif
public:
DirData& operator*() { return data; }
DirData* operator->() { return &data; }
private:
DirData data;
};
ShareManager::Directory* ShareManager::buildTree(const string& aName, Directory* aParent) {
Directory* dir = new Directory(Util::getLastDir(aName), aParent);
dir->addType(SearchManager::TYPE_DIRECTORY); // needed since we match our own name in directory searches
Directory::File::Iter lastFileIter = dir->files.begin();
FileFindIter end;
#ifdef _WIN32
for(FileFindIter i(aName + "*"); 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) {
#endif
string name = i->getFileName();
if(name == "." || name == "..")
continue;
if(name.find('$') != string::npos) {
LogManager::getInstance()->message(STRING(FORBIDDEN_DOLLAR_FILE) + name + " (" + STRING(SIZE) + ": " + Util::toString(File::getSize(name)) + " " + STRING(B) + ") (" + STRING(DIRECTORY) + ": \"" + aName + "\")");
continue;
}
if(!BOOLSETTING(SHARE_HIDDEN) && i->isHidden() )
continue;
if(i->isDirectory()) {
string newName = aName + name + PATH_SEPARATOR;
if(Util::stricmp(newName + PATH_SEPARATOR, SETTING(TEMP_DOWNLOAD_DIRECTORY)) != 0) {
dir->directories[name] = buildTree(newName, dir);
}
} 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;
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&) {
}
}
}
}
return dir;
}
void ShareManager::addTree(Directory* dir) {
bloom.add(Text::toLower(dir->getName()));
for(Directory::MapIter i = dir->directories.begin(); i != dir->directories.end(); ++i) {
Directory* d = i->second;
addTree(d);
}
for(Directory::File::Iter i = dir->files.begin(); i != dir->files.end(); ) {
addFile(dir, i++);
}
}
void ShareManager::addFile(Directory* dir, Directory::File::Iter i) {
const Directory::File& f = *i;
HashFileIter j = tthIndex.find(const_cast<TTHValue*>(&f.getTTH()));
if(j == tthIndex.end()) {
dir->size+=f.getSize();
} else {
if(!SETTING(LIST_DUPES)) {
LogManager::getInstance()->message(STRING(DUPLICATE_FILE_NOT_SHARED) + dir->getFullName() + f.getName() + " (" + STRING(SIZE) + ": " + Util::toString(f.getSize()) + " " + STRING(B) + ") " + STRING(DUPLICATE_MATCH) + j->second->getParent()->getFullName() + j->second->getName() );
dir->files.erase(i);
return;
}
}
dir->addType(getType(f.getName()));
tthIndex.insert(make_pair(const_cast<TTHValue*>(&f.getTTH()), i));
bloom.add(Text::toLower(f.getName()));
}
void ShareManager::removeTTH(const TTHValue& tth, const Directory::File& file) {
pair<HashFileIter, HashFileIter> range = tthIndex.equal_range(const_cast<TTHValue*>(&tth));
for(HashFileIter j = range.first; j != range.second; ++j) {
if(*j->second == file) {
tthIndex.erase(j);
break;
}
}
}
void ShareManager::refresh(bool dirs /* = false */, bool aUpdate /* = true */, bool block /* = false */) throw(ThreadException, ShareException) {
if(Thread::safeInc(refreshing) > 1) {
Thread::safeDec(refreshing);
LogManager::getInstance()->message(STRING(FILE_LIST_REFRRESH_IN_PROGRESS));
return;
}
update = aUpdate;
refreshDirs = dirs;
join();
bool cached = false;
if(initial) {
cached = loadCache();
initial = false;
}
try {
start();
if(block && !cached) {
join();
} else {
setThreadPriority(Thread::LOW);
}
} catch(const ThreadException& e) {
LogManager::getInstance()->message(STRING(FILE_LIST_REFRESH_FAILED) + e.getError());
}
}
int ShareManager::run() {
LogManager::getInstance()->message(STRING(FILE_LIST_REFRESH_INITIATED));
{
if(refreshDirs) {
lastFullUpdate = GET_TICK();
StringPairList dirs;
Directory::Map newDirs;
{
RLock<> l(cs);
dirs = virtualMap;
}
for(StringPairIter i = dirs.begin(); i != dirs.end(); ++i) {
Directory* dp = buildTree(i->second, NULL);
dp->setName(i->first);
newDirs.insert(make_pair(i->second, dp));
}
{
WLock<> l(cs);
StringPairList dirs = virtualMap;
for(StringPairIter i = dirs.begin(); i != dirs.end(); ++i) {
removeDirectory(i->second, true);
}
bloom.clear();
virtualMap = dirs;
for(Directory::MapIter i = newDirs.begin(); i != newDirs.end(); ++i) {
addTree(i->second);
directories.insert(*i);
}
}
refreshDirs = false;
}
}
Thread::safeDec(refreshing);
LogManager::getInstance()->message(STRING(FILE_LIST_REFRESH_FINISHED));
if(update) {
ClientManager::getInstance()->infoUpdated();
}
return 0;
}
void ShareManager::generateXmlList() {
Lock l(listGenLock);
if(xmlDirty && (lastXmlUpdate + 15 * 60 * 1000 < GET_TICK() || lastXmlUpdate < lastFullUpdate)) {
listN++;
try {
string tmp2;
string indent;
string newXmlName = Util::getConfigPath() + "files" + Util::toString(listN) + ".xml.bz2";
{
File f(newXmlName, File::WRITE, File::TRUNCATE | File::CREATE);
// We don't care about the leaves...
CalcOutputStream<TTFilter<1024*1024*1024>, false> bzTree(&f);
FilteredOutputStream<BZFilter, false> bzipper(&bzTree);
CalcOutputStream<TTFilter<1024*1024*1024>, false> newXmlFile(&bzipper);
newXmlFile.write(SimpleXML::utf8Header);
newXmlFile.write("<FileListing Version=\"1\" CID=\"" + ClientManager::getInstance()->getMe()->getCID().toBase32() + "\" Base=\"/\" Generator=\"" APPNAME " " VERSIONSTRING "\">\r\n");
for(Directory::MapIter i = directories.begin(); i != directories.end(); ++i) {
i->second->toXml(newXmlFile, indent, tmp2, true);
}
newXmlFile.write("</FileListing>");
newXmlFile.flush();
newXmlFile.getFilter().getTree().finalize();
bzTree.getFilter().getTree().finalize();
xmlRoot = newXmlFile.getFilter().getTree().getRoot();
xmlbzRoot = bzTree.getFilter().getTree().getRoot();
}
if(xFile != NULL) {
delete xFile;
xFile = NULL;
File::deleteFile(getBZXmlFile());
}
try {
File::renameFile(newXmlName, Util::getConfigPath() + "files.xml.bz2");
newXmlName = Util::getConfigPath() + "files.xml.bz2";
} catch(const FileException&) {
// Ignore, this is for caching only...
}
xFile = new File(newXmlName, File::READ, File::OPEN);
setBZXmlFile(newXmlName);
bzXmlListLen = File::getSize(newXmlName);
} catch(const Exception&) {
// No new file lists...
}
xmlDirty = false;
lastXmlUpdate = GET_TICK();
}
}
MemoryInputStream* ShareManager::generatePartialList(const string& dir, bool recurse) {
if(dir[0] != '/' || dir[dir.size()-1] != '/')
return NULL;
string xml = SimpleXML::utf8Header;
string tmp;
xml += "<FileListing Version=\"1\" CID=\"" + ClientManager::getInstance()->getMe()->getCID().toBase32() + "\" Base=\"" + SimpleXML::escape(dir, tmp, false) + "\" Generator=\"" APPNAME " " VERSIONSTRING "\">\r\n";
StringOutputStream sos(xml);
string indent = "\t";
RLock<> l(cs);
if(dir == "/") {
for(ShareManager::Directory::MapIter i = directories.begin(); i != directories.end(); ++i) {
tmp.clear();
i->second->toXml(sos, indent, tmp, recurse);
}
} else {
string::size_type i = 1, j = 1;
ShareManager::Directory::MapIter it = directories.end();
bool first = true;
while( (i = dir.find('/', j)) != string::npos) {
if(i == j) {
j++;
continue;
}
if(first) {
first = false;
StringPairIter k = lookupVirtual(dir.substr(j, i-j));
if(k == virtualMap.end())
return NULL;
it = directories.find(k->second);
if(it == directories.end())
return NULL;
} else {
ShareManager::Directory::MapIter it2 = it->second->directories.find(dir.substr(j, i-j));
if(it2 == it->second->directories.end()) {
return NULL;
}
it = it2;
}
j = i + 1;
}
for(ShareManager::Directory::MapIter it2 = it->second->directories.begin(); it2 != it->second->directories.end(); ++it2) {
it2->second->toXml(sos, indent, tmp, recurse);
}
it->second->filesToXml(sos, indent, tmp);
}
xml += "</FileListing>";
return new MemoryInputStream(xml);
}
bool ShareManager::getTTH(const string& aFile, TTHValue& tth) throw() {
if(aFile.length() < 3 || aFile[0] != '/')
return false;
string::size_type i = aFile.find('/', 1);
if(i == string::npos)
return false;
RLock<> l(cs);
StringPairIter j = lookupVirtual(aFile.substr(1, i-1));
if(j == virtualMap.end()) {
return false;
}
Directory::File::Iter it;
if(!checkFile(j->second, aFile.substr(i + 1), it))
return false;
tth = it->getTTH();
return true;
}
MemoryInputStream* ShareManager::getTree(const string& aFile) {
TigerTree tree;
if(aFile.compare(0, 4, "TTH/") == 0) {
if(!HashManager::getInstance()->getTree(TTHValue(aFile.substr(4)), tree))
return NULL;
} else {
try {
TTHValue tth;
if(getTTH(aFile, tth))
HashManager::getInstance()->getTree(tth, tree);
} catch(const Exception&) {
return NULL;
}
}
vector<u_int8_t> buf = tree.getLeafData();
return new MemoryInputStream(&buf[0], buf.size());
}
static const string& escaper(const string& n, string& tmp) {
if(SimpleXML::needsEscape(n, true, false)) {
tmp.clear();
tmp.append(n);
return SimpleXML::escape(tmp, true, false);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -