From 5f69c9ea1f46480912c953a17b2763d59e721333 Mon Sep 17 00:00:00 2001 From: mr-alice Date: Thu, 24 Nov 2016 23:42:56 +0100 Subject: [PATCH] added an option to follow symbolic links or not, and anti-loop system during directories traversal --- .../src/file_sharing/directory_updater.cc | 31 ++- .../src/file_sharing/directory_updater.h | 6 +- .../src/file_sharing/file_sharing_defaults.h | 3 + libretroshare/src/file_sharing/p3filelists.cc | 45 +++- libretroshare/src/file_sharing/p3filelists.h | 3 + libretroshare/src/ft/ftserver.cc | 10 +- libretroshare/src/ft/ftserver.h | 2 + libretroshare/src/retroshare/rsfiles.h | 2 + libretroshare/src/util/rsdir.cc | 15 ++ libretroshare/src/util/rsdir.h | 4 + .../src/gui/settings/DirectoriesPage.cpp | 2 + .../src/gui/settings/DirectoriesPage.ui | 219 +++++++++--------- .../src/gui/settings/TransferPage.ui | 2 +- 13 files changed, 218 insertions(+), 126 deletions(-) diff --git a/libretroshare/src/file_sharing/directory_updater.cc b/libretroshare/src/file_sharing/directory_updater.cc index 2f2388ad1..f162f898b 100644 --- a/libretroshare/src/file_sharing/directory_updater.cc +++ b/libretroshare/src/file_sharing/directory_updater.cc @@ -43,6 +43,7 @@ LocalDirectoryUpdater::LocalDirectoryUpdater(HashStorage *hc,LocalDirectoryStora mDelayBetweenDirectoryUpdates = DELAY_BETWEEN_DIRECTORY_UPDATES; mIsEnabled = false ; + mFollowSymLinks = FOLLOW_SYMLINKS_DEFAULT ; } bool LocalDirectoryUpdater::isEnabled() const @@ -119,29 +120,42 @@ void LocalDirectoryUpdater::sweepSharedDirectories() // now for each of them, go recursively and match both files and dirs + std::set existing_dirs ; + for(DirectoryStorage::DirIterator stored_dir_it(mSharedDirectories,mSharedDirectories->root()) ; stored_dir_it;++stored_dir_it) { #ifdef DEBUG_LOCAL_DIR_UPDATER std::cerr << "[directory storage] recursing into " << stored_dir_it.name() << std::endl; #endif - recursUpdateSharedDir(stored_dir_it.name(), *stored_dir_it) ; // here we need to use the list that was stored, instead of the shared dir list, because the two + recursUpdateSharedDir(stored_dir_it.name(), *stored_dir_it,existing_dirs) ; // here we need to use the list that was stored, instead of the shared dir list, because the two // are not necessarily in the same order. } RsServer::notify()->notifyListChange(NOTIFY_LIST_DIRLIST_LOCAL, 0); } -void LocalDirectoryUpdater::recursUpdateSharedDir(const std::string& cumulated_path, DirectoryStorage::EntryIndex indx) +void LocalDirectoryUpdater::recursUpdateSharedDir(const std::string& cumulated_path, DirectoryStorage::EntryIndex indx,std::set& existing_directories) { #ifdef DEBUG_LOCAL_DIR_UPDATER std::cerr << "[directory storage] parsing directory " << cumulated_path << ", index=" << indx << std::endl; #endif + if(mFollowSymLinks) + { + std::string real_path = RsDirUtil::removeSymLinks(cumulated_path) ; + if(existing_directories.end() != existing_directories.find(real_path)) + { + std::cerr << "(EE) Directory " << cumulated_path << " has real path " << real_path << " which already belongs to another shared directory. Ignoring" << std::endl; + return ; + } + existing_directories.insert(real_path) ; + } + // make sure list of subdirs is the same // make sure list of subfiles is the same // request all hashes to the hashcache - librs::util::FolderIterator dirIt(cumulated_path,false,false); // disallow symbolic links and files from the future. + librs::util::FolderIterator dirIt(cumulated_path,mFollowSymLinks,false); // disallow symbolic links and files from the future. time_t dir_local_mod_time ; if(!mSharedDirectories->getDirectoryLocalModTime(indx,dir_local_mod_time)) @@ -213,7 +227,7 @@ void LocalDirectoryUpdater::recursUpdateSharedDir(const std::string& cumulated_p #ifdef DEBUG_LOCAL_DIR_UPDATER std::cerr << " recursing into " << stored_dir_it.name() << std::endl; #endif - recursUpdateSharedDir(cumulated_path + "/" + stored_dir_it.name(), *stored_dir_it) ; + recursUpdateSharedDir(cumulated_path + "/" + stored_dir_it.name(), *stored_dir_it,existing_directories) ; } } @@ -244,6 +258,15 @@ uint32_t LocalDirectoryUpdater::fileWatchPeriod() const return mDelayBetweenDirectoryUpdates ; } +void LocalDirectoryUpdater::setFollowSymLinks(bool b) +{ + mFollowSymLinks = b ; +} + +bool LocalDirectoryUpdater::followSymLinks() const +{ + return mFollowSymLinks ; +} diff --git a/libretroshare/src/file_sharing/directory_updater.h b/libretroshare/src/file_sharing/directory_updater.h index 85df00d6c..61c5a66da 100644 --- a/libretroshare/src/file_sharing/directory_updater.h +++ b/libretroshare/src/file_sharing/directory_updater.h @@ -47,6 +47,9 @@ public: void setFileWatchPeriod(int seconds) ; uint32_t fileWatchPeriod() const ; + void setFollowSymLinks(bool b) ; + bool followSymLinks() const ; + void setEnabled(bool b) ; bool isEnabled() const ; @@ -56,7 +59,7 @@ protected: virtual void hash_callback(uint32_t client_param, const std::string& name, const RsFileHash& hash, uint64_t size); virtual bool hash_confirm(uint32_t client_param) ; - void recursUpdateSharedDir(const std::string& cumulated_path,DirectoryStorage::EntryIndex indx); + void recursUpdateSharedDir(const std::string& cumulated_path, DirectoryStorage::EntryIndex indx, std::set& existing_directories); void sweepSharedDirectories(); private: @@ -70,5 +73,6 @@ private: uint32_t mDelayBetweenDirectoryUpdates; bool mIsEnabled ; + bool mFollowSymLinks; }; diff --git a/libretroshare/src/file_sharing/file_sharing_defaults.h b/libretroshare/src/file_sharing/file_sharing_defaults.h index 90060dd41..0b2f7bdd3 100644 --- a/libretroshare/src/file_sharing/file_sharing_defaults.h +++ b/libretroshare/src/file_sharing/file_sharing_defaults.h @@ -37,6 +37,7 @@ static const uint32_t DELAY_BEFORE_DELETE_EMPTY_REMOTE_DIR = 5*24*86400 ; static const std::string HASH_CACHE_DURATION_SS = "HASH_CACHE_DURATION" ; // key string to store hash remembering time static const std::string WATCH_FILE_DURATION_SS = "WATCH_FILES_DELAY" ; // key to store delay before re-checking for new files static const std::string WATCH_FILE_ENABLED_SS = "WATCH_FILES_ENABLED"; // key to store ON/OFF flags for file whatch +static const std::string FOLLOW_SYMLINKS_SS = "FOLLOW_SYMLINKS"; // dereference symbolic links, or just ignore them. static const std::string WATCH_HASH_SALT_SS = "WATCH_HASH_SALT"; // Salt that is used to hash directory names static const std::string FILE_SHARING_DIR_NAME = "file_sharing" ; // hard-coded directory name to store friend file lists, hash cache, etc. @@ -53,3 +54,5 @@ static const uint32_t NB_FRIEND_INDEX_BITS = 10 ; // Do not static const uint32_t NB_ENTRY_INDEX_BITS = 22 ; // Do not change this! static const uint32_t ENTRY_INDEX_BIT_MASK = 0x003fffff ; // used for storing (EntryIndex,Friend) couples into a 32bits pointer. Depends on the two values just before. Dont change! static const uint32_t DELAY_BEFORE_DROP_REQUEST = 600; // every 10 min + +static const bool FOLLOW_SYMLINKS_DEFAULT = true; diff --git a/libretroshare/src/file_sharing/p3filelists.cc b/libretroshare/src/file_sharing/p3filelists.cc index 36bad6cf0..017e6e9d9 100644 --- a/libretroshare/src/file_sharing/p3filelists.cc +++ b/libretroshare/src/file_sharing/p3filelists.cc @@ -273,19 +273,22 @@ cleanup = true; mLocalSharedDirs->getSharedDirectoryList(dirList); } - for(std::list::iterator it = dirList.begin(); it != dirList.end(); ++it) - { - RsFileConfigItem *fi = new RsFileConfigItem(); + { + RS_STACK_MUTEX(mFLSMtx) ; + for(std::list::iterator it = dirList.begin(); it != dirList.end(); ++it) + { + RsFileConfigItem *fi = new RsFileConfigItem(); - fi->file.path = (*it).filename ; - fi->file.name = (*it).virtualname ; - fi->flags = (*it).shareflags.toUInt32() ; + fi->file.path = (*it).filename ; + fi->file.name = (*it).virtualname ; + fi->flags = (*it).shareflags.toUInt32() ; - for(std::list::const_iterator it2( (*it).parent_groups.begin());it2!=(*it).parent_groups.end();++it2) - fi->parent_groups.ids.insert(*it2) ; + for(std::list::const_iterator it2( (*it).parent_groups.begin());it2!=(*it).parent_groups.end();++it2) + fi->parent_groups.ids.insert(*it2) ; - sList.push_back(fi); - } + sList.push_back(fi); + } + } RsConfigKeyValueSet *rskv = new RsConfigKeyValueSet(); @@ -314,7 +317,14 @@ cleanup = true; rskv->tlvkvs.pairs.push_back(kv); } + { + RsTlvKeyValue kv; + kv.key = FOLLOW_SYMLINKS_SS; + kv.value = followSymLinks()?"YES":"NO" ; + + rskv->tlvkvs.pairs.push_back(kv); + } { RsTlvKeyValue kv; @@ -373,6 +383,10 @@ bool p3FileDatabase::loadList(std::list& load) if(sscanf(kit->value.c_str(),"%d",&t) == 1) setWatchPeriod(t); } + else if(kit->key == FOLLOW_SYMLINKS_SS) + { + setFollowSymLinks(kit->value == "YES") ; + } else if(kit->key == WATCH_FILE_ENABLED_SS) { setWatchEnabled(kit->value == "YES") ; @@ -891,6 +905,17 @@ bool p3FileDatabase::inDirectoryCheck() RS_STACK_MUTEX(mFLSMtx) ; return mLocalDirWatcher->inDirectoryCheck(); } +void p3FileDatabase::setFollowSymLinks(bool b) +{ + RS_STACK_MUTEX(mFLSMtx) ; + mLocalDirWatcher->setFollowSymLinks(b) ; + IndicateConfigChanged(); +} +bool p3FileDatabase::followSymLinks() const +{ + RS_STACK_MUTEX(mFLSMtx) ; + return mLocalDirWatcher->followSymLinks() ; +} void p3FileDatabase::setWatchEnabled(bool b) { RS_STACK_MUTEX(mFLSMtx) ; diff --git a/libretroshare/src/file_sharing/p3filelists.h b/libretroshare/src/file_sharing/p3filelists.h index 8e9d2f055..4c051a21a 100644 --- a/libretroshare/src/file_sharing/p3filelists.h +++ b/libretroshare/src/file_sharing/p3filelists.h @@ -138,6 +138,9 @@ class p3FileDatabase: public p3Service, public p3Config, public ftSearch //, pub void setWatchEnabled(bool b) ; bool watchEnabled() ; + bool followSymLinks() const; + void setFollowSymLinks(bool b) ; + // interfact for directory parsing void forceDirectoryCheck(); // Force re-sweep the directories and see what's changed diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index d5797e210..caab409e8 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -804,11 +804,13 @@ bool ftServer::removeSharedDirectory(std::string dir) return true; } -bool ftServer::watchEnabled() { return mFileDatabase->watchEnabled() ; } -int ftServer::watchPeriod() const { return mFileDatabase->watchPeriod()/60 ; } +bool ftServer::watchEnabled() { return mFileDatabase->watchEnabled() ; } +int ftServer::watchPeriod() const { return mFileDatabase->watchPeriod()/60 ; } +bool ftServer::followSymLinks() const { return mFileDatabase->followSymLinks() ; } -void ftServer::setWatchEnabled(bool b) { mFileDatabase->setWatchEnabled(b) ; } -void ftServer::setWatchPeriod(int minutes) { mFileDatabase->setWatchPeriod(minutes*60) ; } +void ftServer::setWatchEnabled(bool b) { mFileDatabase->setWatchEnabled(b) ; } +void ftServer::setWatchPeriod(int minutes) { mFileDatabase->setWatchPeriod(minutes*60) ; } +void ftServer::setFollowSymLinks(bool b) { mFileDatabase->setFollowSymLinks(b) ; } bool ftServer::getShareDownloadDirectory() { diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index 00a34c1c5..d52c539d0 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -215,6 +215,8 @@ public: virtual int watchPeriod() const ; virtual void setWatchEnabled(bool b) ; virtual bool watchEnabled() ; + virtual bool followSymLinks() const; + virtual void setFollowSymLinks(bool b); /***************************************************************/ /*************** Data Transfer Interface ***********************/ diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index ad86befc6..ba24552e5 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -247,6 +247,8 @@ class RsFiles virtual void setWatchEnabled(bool b) =0; virtual int watchPeriod() const =0; virtual bool watchEnabled() =0; + virtual bool followSymLinks() const=0; + virtual void setFollowSymLinks(bool b)=0 ; virtual bool getShareDownloadDirectory() = 0; virtual bool shareDownloadDirectory(bool share) = 0; diff --git a/libretroshare/src/util/rsdir.cc b/libretroshare/src/util/rsdir.cc index 7d7d1dfe6..a54abccaf 100644 --- a/libretroshare/src/util/rsdir.cc +++ b/libretroshare/src/util/rsdir.cc @@ -480,6 +480,21 @@ bool RsDirUtil::checkCreateDirectory(const std::string& dir) } +std::string RsDirUtil::removeSymLinks(const std::string& path) +{ +#warning (Mr.Alice): I don't know how to do this on windows. See https://msdn.microsoft.com/en-us/library/windows/desktop/hh707084(v=vs.85).aspx +#ifdef WINDOWS_SYS + //if(!S_OK == PathCchCanonicalizeEx(tmp,...) ; + return path ; +#else + char *tmp = canonicalize_file_name(path.c_str()) ; + std::string result(tmp) ; + + free(tmp); + return result ; +#endif +} + bool RsDirUtil::cleanupDirectory(const std::string& cleandir, const std::set &keepFiles) { for(librs::util::FolderIterator it(cleandir,false);it.isValid();it.next()) diff --git a/libretroshare/src/util/rsdir.h b/libretroshare/src/util/rsdir.h index c2dfe3cd4..8f52b009f 100644 --- a/libretroshare/src/util/rsdir.h +++ b/libretroshare/src/util/rsdir.h @@ -91,6 +91,10 @@ bool checkFile(const std::string& filename,uint64_t& file_size,bool disallow bool checkDirectory(const std::string& dir); bool checkCreateDirectory(const std::string& dir); +// Removes all symbolic links along the path and computes the actual location of the file/dir passed as argument. + +std::string removeSymLinks(const std::string& path) ; + bool cleanupDirectory(const std::string& dir, const std::set &keepFiles); bool cleanupDirectoryFaster(const std::string& dir, const std::set &keepFiles); diff --git a/retroshare-gui/src/gui/settings/DirectoriesPage.cpp b/retroshare-gui/src/gui/settings/DirectoriesPage.cpp index b9d2ecc5e..c3c466980 100755 --- a/retroshare-gui/src/gui/settings/DirectoriesPage.cpp +++ b/retroshare-gui/src/gui/settings/DirectoriesPage.cpp @@ -68,6 +68,7 @@ bool DirectoriesPage::save(QString &/*errmsg*/) rsFiles->setWatchPeriod(ui.autoCheckDirectoriesDelay_SB->value()); rsFiles->shareDownloadDirectory(ui.shareDownloadDirectoryCB->isChecked()); + rsFiles->setFollowSymLinks(ui.followSymLinks_CB->isChecked()); return true; } @@ -83,6 +84,7 @@ void DirectoriesPage::load() ui.incomingDir->setText(QString::fromUtf8(rsFiles->getDownloadDirectory().c_str())); ui.partialsDir->setText(QString::fromUtf8(rsFiles->getPartialsDirectory().c_str())); + ui.followSymLinks_CB->setChecked(rsFiles->followSymLinks()); } void DirectoriesPage::setIncomingDirectory() diff --git a/retroshare-gui/src/gui/settings/DirectoriesPage.ui b/retroshare-gui/src/gui/settings/DirectoriesPage.ui index 9413ac2f9..52bb9759b 100755 --- a/retroshare-gui/src/gui/settings/DirectoriesPage.ui +++ b/retroshare-gui/src/gui/settings/DirectoriesPage.ui @@ -6,114 +6,12 @@ 0 0 - 895 + 929 549 - - - 6 - - - 0 - - - - - Incoming Directory - - - - - - true - - - - - - - - 31 - 31 - - - - - 31 - 31 - - - - Browse - - - - - - - :/images/directoryselect_24x24_shadow.png:/images/directoryselect_24x24_shadow.png - - - - 24 - 24 - - - - - - - - - - - Partials Directory - - - - - - true - - - - - - - - 31 - 31 - - - - - 31 - 31 - - - - Browse - - - - - - - :/images/directoryselect_24x24_shadow.png:/images/directoryselect_24x24_shadow.png - - - - 24 - 24 - - - - - - - - + + Shared Directories @@ -176,10 +74,119 @@ + + + + <html><head/><body><p>Tells Retroshare to follow the links. Loops and duplicate directories are automatically taken care of. If unchecked, Retroshare will just ignore symbolic links to both files and directories.</p></body></html> + + + follow symbolic links + + + true + + + - + + + + Incoming Directory + + + + + + true + + + + + + + + 31 + 31 + + + + + 31 + 31 + + + + Browse + + + + + + + :/images/directoryselect_24x24_shadow.png:/images/directoryselect_24x24_shadow.png + + + + 24 + 24 + + + + + + + + + + + Partials Directory + + + + + + true + + + + + + + + 31 + 31 + + + + + 31 + 31 + + + + Browse + + + + + + + :/images/directoryselect_24x24_shadow.png:/images/directoryselect_24x24_shadow.png + + + + 24 + 24 + + + + + + + + Qt::Vertical diff --git a/retroshare-gui/src/gui/settings/TransferPage.ui b/retroshare-gui/src/gui/settings/TransferPage.ui index 665009d65..1ef4fdb8a 100644 --- a/retroshare-gui/src/gui/settings/TransferPage.ui +++ b/retroshare-gui/src/gui/settings/TransferPage.ui @@ -7,7 +7,7 @@ 0 0 741 - 372 + 422