improved FolderIterator class

This commit is contained in:
mr-alice 2016-07-23 22:14:43 -04:00
parent 3c976bb7ee
commit 3e48b0fd95
11 changed files with 183 additions and 62 deletions

View File

@ -789,7 +789,7 @@ void FileIndexMonitor::updateCycle()
to_hash.back().realpath = realpath ; to_hash.back().realpath = realpath ;
to_hash.back().dirpath = dirpath ; to_hash.back().dirpath = dirpath ;
while(isRunning() && dirIt.readdir()) for(;dirIt.isValid() && isRunning();dirIt.next())
{ {
/* check entry type */ /* check entry type */
std::string fname; std::string fname;

View File

@ -5,6 +5,9 @@ class InternalFileHierarchyStorage
class FileStorageNode class FileStorageNode
{ {
public: public:
static const uint32_t TYPE_FILE = 0x0001 ;
static const uint32_t TYPE_DIR = 0x0002 ;
virtual uint32_t type() const =0; virtual uint32_t type() const =0;
}; };
class FileEntry: public FileStorageNode class FileEntry: public FileStorageNode
@ -19,12 +22,12 @@ class InternalFileHierarchyStorage
public: public:
virtual uint32_t type() const { return FileStorageNode::TYPE_DIR ; } virtual uint32_t type() const { return FileStorageNode::TYPE_DIR ; }
std::set<EntryIndex> subdirs ; std::set<DirectoryStorage::EntryIndex> subdirs ;
std::set<EntryIndex> subfiles ; std::set<DirectoryStorage::EntryIndex> subfiles ;
}; };
// file/dir access and modification // file/dir access and modification
bool findSubDirectory(EntryIndex e,const std::string& s) const ; // returns true when s is the name of a sub-directory in the given entry e bool findSubDirectory(DirectoryStorage::EntryIndex e,const std::string& s) const ; // returns true when s is the name of a sub-directory in the given entry e
uint32_t root ; uint32_t root ;

View File

@ -39,27 +39,44 @@ class DirectoryStorage
{ {
public: public:
DirIterator(const DirIterator& d) ; DirIterator(const DirIterator& d) ;
DirIterator(const EntryIndex& d) ;
DirIterator& operator++() ; DirIterator& operator++() ;
EntryIndex operator*() const ; // current directory entry EntryIndex operator*() const ; // current directory entry
bool operator()() const ; // used in for loops. Returns true when the iterator is valid. operator bool() const ; // used in for loops. Returns true when the iterator is valid.
};
// info about the directory that is pointed by the iterator
const std::string& name() const ;
};
class FileIterator class FileIterator
{ {
public: public:
FileIterator(DirIterator& d); // crawls all files in specified directory FileIterator(DirIterator& d); // crawls all files in specified directory
FileIterator(EntryIndex& e); // crawls all files in specified directory
uint32_t size() const ; // number of files in this directory
FileIterator& operator++() ; FileIterator& operator++() ;
EntryIndex operator*() const ; // current file entry EntryIndex operator*() const ; // current file entry
bool operator()() const ; // used in for loops. Returns true when the iterator is valid. operator bool() const ; // used in for loops. Returns true when the iterator is valid.
};
// info about the file that is pointed by the iterator
std::string name() const ;
std::string fullpath() const ;
uint64_t size() const ;
RsFileHash hash() const ;
time_t modtime() const ;
};
virtual DirIterator root() ; // returns the index of the root directory entry. virtual DirIterator root() ; // returns the index of the root directory entry.
private: void updateSubDirectoryList(const EntryIndex& indx,const std::list<std::string>& subdirs) ;
void updateSubFilesList(const EntryIndex& indx,const std::list<std::string>& subfiles) ;
void removeDirectory(const EntryIndex& indx) ;
private:
void load(const std::string& local_file_name) ; void load(const std::string& local_file_name) ;
void save(const std::string& local_file_name) ; void save(const std::string& local_file_name) ;

View File

@ -1,19 +1,24 @@
#include "util/folderiterator.h"
#include "directory_storage.h" #include "directory_storage.h"
#include "directory_updater.h" #include "directory_updater.h"
#define DEBUG_LOCAL_DIR_UPDATER 1
void RemoteDirectoryUpdater::tick() void RemoteDirectoryUpdater::tick()
{ {
// use the stored iterator // use the stored iterator
} }
LocalDirectoryUpdater::LocalDirectoryUpdater() LocalDirectoryUpdater::LocalDirectoryUpdater(HashCache *hc)
: mHashCache(hc)
{ {
// tell the hash cache that we're the client
mHashCache->setClient(this) ;
} }
void LocalDirectoryUpdater::tick() void LocalDirectoryUpdater::tick()
{ {
std::cerr << "LocalDirectoryUpdater::tick()" << std::endl;
// recursive update algorithm works that way: // recursive update algorithm works that way:
// - the external loop starts on the shared directory list and goes through sub-directories // - the external loop starts on the shared directory list and goes through sub-directories
// - at the same time, it updates the local list of shared directories. A single sweep is performed over the whole directory structure. // - at the same time, it updates the local list of shared directories. A single sweep is performed over the whole directory structure.
@ -21,28 +26,29 @@ void LocalDirectoryUpdater::tick()
// - doing so, changing directory names or moving files between directories does not cause a re-hash of the content. // - doing so, changing directory names or moving files between directories does not cause a re-hash of the content.
// //
std::list<SharedDirInfo> shared_directory_list ; std::list<SharedDirInfo> shared_directory_list ;
std::list<std::string> sub_dir_list ;
for(std::list<SharedDirInfo>::const_iterator real_dir_it(shared_directory_list.begin());it!=shared_directory_list.end();++it) for(std::list<SharedDirInfo>::const_iterator real_dir_it(shared_directory_list.begin());real_dir_it!=shared_directory_list.end();++real_dir_it)
sub_dir_list.push_back( (*it).filename ) ; sub_dir_list.push_back( (*real_dir_it).filename ) ;
// make sure that entries in stored_dir_it are the same than paths in real_dir_it, and in the same order. // make sure that entries in stored_dir_it are the same than paths in real_dir_it, and in the same order.
mSharedDirectories->updateSubDirectoryList(mSharedDirectories->root(),sub_dir_list) ; mSharedDirectories->updateSubDirectoryList(*mSharedDirectories->root(),sub_dir_list) ;
// now for each of them, go recursively and match both files and dirs // now for each of them, go recursively and match both files and dirs
DirectoryStorage::DirIterator stored_dir_it(mLocalSharedDirs.root()) ; DirectoryStorage::DirIterator stored_dir_it(mSharedDirectories->root()) ;
for(std::list<SharedDirInfo>::const_iterator real_dir_it(shared_directory_list.begin());it!=shared_directory_list.end();++it, ++stored_dir_it) for(std::list<SharedDirInfo>::const_iterator real_dir_it(shared_directory_list.begin());real_dir_it!=shared_directory_list.end();++real_dir_it, ++stored_dir_it)
recursUpdateSharedDir(*real_dir_it, *stored_dir_it) ; recursUpdateSharedDir(real_dir_it->filename, *stored_dir_it) ;
} }
LocalDirectoryUpdater::recursUpdateSharedDir(const std::string& cumulated_path,const DirectoryStorage::EntryIndex indx) void LocalDirectoryUpdater::recursUpdateSharedDir(const std::string& cumulated_path, DirectoryStorage::EntryIndex indx)
{ {
std::cerr << " parsing directory " << cumulated_path << ", index=" << indx << std::endl;
// make sure list of subdirs is the same // make sure list of subdirs is the same
// make sure list of subfiles is the same // make sure list of subfiles is the same
// request all hashes to the hashcache // request all hashes to the hashcache
librs::util::FolderIterator dirIt(cumulated_path); librs::util::FolderIterator dirIt(cumulated_path);
@ -60,22 +66,18 @@ LocalDirectoryUpdater::recursUpdateSharedDir(const std::string& cumulated_path,c
while(dirIt.readdir()) while(dirIt.readdir())
{ {
std::string name ; switch(dirIt.file_type())
uint64_t size ;
uint8_t type ;
time_t mod_time ;
dirIt.readEntryInformation(type,name,size,mod_time) ;
switch(type)
{ {
case librs::util::FolderIterator::TYPE_FILE: subfiles.push_back(name) ; case librs::util::FolderIterator::TYPE_FILE: subfiles.push_back(dirIt.file_name()) ;
break; std::cerr << " adding sub-file \"" << dirIt.file_name() << "\"" << std::endl;
case librs::util::FolderIterator::TYPE_DIR: subdirs.push_back(name) ; break;
case librs::util::FolderIterator::TYPE_DIR: subdirs.push_back(dirIt.file_name()) ;
std::cerr << " adding sub-dir \"" << dirIt.file_name() << "\"" << std::endl;
break; break;
default: default:
std::cerr << "(EE) Dir entry of unknown type with path \"" << cumulated_path << "/" << name << "\"" << std::endl; std::cerr << "(EE) Dir entry of unknown type with path \"" << cumulated_path << "/" << dirIt.file_name() << "\"" << std::endl;
} }
} }
// update file and dir lists for current directory. // update file and dir lists for current directory.
@ -87,18 +89,16 @@ LocalDirectoryUpdater::recursUpdateSharedDir(const std::string& cumulated_path,c
for(DirectoryStorage::FileIterator dit(indx);dit;++dit) for(DirectoryStorage::FileIterator dit(indx);dit;++dit)
{ {
// ask about the hash. If not present, ask HashCache. If not present, the callback will update it. // ask about the hash. If not present, ask HashCache. If not present, or different, the callback will update it.
if() mHashCache->requestHash(dit.fullpath(),dit.size(),dit.modtime(),dit.hash(),this) ;
if(mHashCache.requestHash(realpath,name,size,modtime,hash),this)
mSharedDirectories->updateFileHash(*dit,hash) ;
} }
// go through the list of sub-dirs and recursively update // go through the list of sub-dirs and recursively update
DirectoryStorage::DirIterator stored_dir_it(indx) ; DirectoryStorage::DirIterator stored_dir_it(indx) ;
for(std::list<std::string>::const_iterator real_dir_it(subdirs.begin());it!=subdirs.end();++real_dir_it, ++stored_dir_it) for(std::list<std::string>::const_iterator real_dir_it(subdirs.begin());real_dir_it!=subdirs.end();++real_dir_it, ++stored_dir_it)
recursUpdateSharedDir(*real_dir_it, *stored_dir_it) ; recursUpdateSharedDir(*real_dir_it, *stored_dir_it) ;
} }

View File

@ -3,7 +3,8 @@
// - local: directories are crawled n disk and files are hashed / requested from a cache // - local: directories are crawled n disk and files are hashed / requested from a cache
// - remote: directories are requested remotely to a providing client // - remote: directories are requested remotely to a providing client
// //
class HashCache ; #include "file_sharing/hash_cache.h"
class LocalDirectoryStorage ; class LocalDirectoryStorage ;
class DirectoryUpdater class DirectoryUpdater
@ -19,12 +20,16 @@ class DirectoryUpdater
// //
}; };
class LocalDirectoryUpdater: public DirectoryUpdater class LocalDirectoryUpdater: public DirectoryUpdater, public HashCacheClient
{ {
public: public:
LocalDirectoryUpdater(HashCache *hash_cache) ; LocalDirectoryUpdater(HashCache *hash_cache) ;
virtual void tick() ; virtual void tick() ;
protected:
virtual void hash_callback(const std::string& full_name,const RsFileHash& hash) ;
void recursUpdateSharedDir(const std::string& cumulated_path,DirectoryStorage::EntryIndex indx);
private: private:
HashCache *mHashCache ; HashCache *mHashCache ;
LocalDirectoryStorage *mSharedDirectories ; LocalDirectoryStorage *mSharedDirectories ;

View File

@ -2,14 +2,28 @@
#include <map> #include <map>
#include "util/rsthreads.h" #include "util/rsthreads.h"
#include "retroshare/rsfiles.h"
class HashCacheClient
{
public:
virtual void hash_callback(const std::string& full_path,const RsFileHash& hash) ;
};
class FileHashingThread: public RsTickingThread
{
public:
FileHashingThread() {}
virtual void data_tick() ;
};
class HashCache class HashCache
{ {
public: public:
HashCache(const std::string& save_file_name) ; HashCache(const std::string& save_file_name) ;
void insert(const std::string& full_path,uint64_t size,time_t time_stamp,const RsFileHash& hash) ; bool requestHash(const std::string& full_path,uint64_t size,time_t mod_time,const RsFileHash& known_hash,HashCacheClient *c) ;
bool find(const std::string& full_path,uint64_t size,time_t time_stamp,RsFileHash& hash) ;
struct HashCacheInfo struct HashCacheInfo
{ {
@ -21,10 +35,10 @@ public:
} ; } ;
// interaction with GUI, called from p3FileLists // interaction with GUI, called from p3FileLists
void setRememberHashFilesDuration(uint32_t days) { _max_cache_duration_days = days ; } void setRememberHashFilesDuration(uint32_t days) { mMaxCacheDurationDays = days ; }
uint32_t rememberHashFilesDuration() const { return _max_cache_duration_days ; } uint32_t rememberHashFilesDuration() const { return mMaxCacheDurationDays ; }
void clear() { _files.clear(); } void clear() { mFiles.clear(); }
bool empty() const { return _files.empty() ; } bool empty() const { return mFiles.empty() ; }
private: private:
void clean() ; void clean() ;
@ -33,7 +47,7 @@ private:
void load() ; void load() ;
// threaded stuff // threaded stuff
RsTickingThread mHashingThread ; FileHashingThread mHashingThread ;
RsMutex mHashMtx ; RsMutex mHashMtx ;
// Local configuration and storage // Local configuration and storage
@ -45,6 +59,6 @@ private:
// current work // current work
std::map<std::string> mFilesToHash ; std::map<std::string,HashCacheClient *> mFilesToHash ;
}; };

View File

@ -146,7 +146,7 @@ void RsPluginManager::loadPlugins(const std::vector<std::string>& plugin_directo
continue ; continue ;
} }
while(dirIt.readdir()) for(;dirIt.isValid();dirIt.next())
{ {
std::string fname; std::string fname;
dirIt.d_name(fname); dirIt.d_name(fname);

View File

@ -533,7 +533,7 @@ bool RsAccountsDetail::getAvailableAccounts(std::map<RsPeerId, AccountDetails> &
struct stat64 buf; struct stat64 buf;
while (dirIt.readdir()) for(;dirIt.isValid();dirIt.next())
{ {
/* check entry type */ /* check entry type */
std::string fname; std::string fname;

View File

@ -1,11 +1,17 @@
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "folderiterator.h" #include "folderiterator.h"
#include "rsstring.h" #include "rsstring.h"
namespace librs { namespace util { namespace librs { namespace util {
FolderIterator::FolderIterator(const std::string& folderName) FolderIterator::FolderIterator(const std::string& folderName)
: mFolderName(folderName)
{ {
#ifdef WINDOWS_SYS #ifdef WINDOWS_SYS
std::wstring utf16Name; std::wstring utf16Name;
@ -18,10 +24,10 @@ FolderIterator::FolderIterator(const std::string& folderName)
handle = FindFirstFileW(utf16Name.c_str(), &fileInfo); handle = FindFirstFileW(utf16Name.c_str(), &fileInfo);
validity = handle != INVALID_HANDLE_VALUE; validity = handle != INVALID_HANDLE_VALUE;
isFirstCall = true;
#else #else
handle = opendir(folderName.c_str()); handle = opendir(folderName.c_str());
validity = handle != NULL; validity = handle != NULL;
next();
#endif #endif
} }
@ -30,19 +36,71 @@ FolderIterator::~FolderIterator()
closedir(); closedir();
} }
bool FolderIterator::readdir() { void FolderIterator::next()
{
do {
if(!readdir())
{
validity = false ;
break ;
}
d_name(mFileName);
} while(mFileName == "." || mFileName == "..") ;
mFullPath = mFolderName + "/" + mFileName ;
struct stat64 buf ;
#ifdef WINDOWS_SYS
std::wstring wfullname;
librs::util::ConvertUtf8ToUtf16(mFullPath, wfullname);
if ( 0 == _wstati64(wfullname.c_str(), &buf))
#else
if ( 0 == stat64(mFullPath.c_str(), &buf))
#endif
{
mFileModTime = buf.st_mtime ;
mStatInfoOk = true;
if (S_ISDIR(buf.st_mode))
{
mType = TYPE_DIR ;
mFileSize = 0 ;
mFileModTime = buf.st_mtime;
}
else if (S_ISREG(buf.st_mode))
{
mType = TYPE_FILE ;
mFileSize = buf.st_size;
mFileModTime = buf.st_mtime;
}
else
{
mType = TYPE_UNKNOWN ;
mFileSize = 0 ;
mFileModTime = 0;
}
}
else
{
mType = TYPE_UNKNOWN ;
mFileSize = 0 ;
mFileModTime = 0;
validity = false ;
}
}
bool FolderIterator::readdir()
{
if(!validity) if(!validity)
return false; return false;
#ifdef WINDOWS_SYS #ifdef WINDOWS_SYS
if(isFirstCall) {
isFirstCall = false;
return true;
}
return FindNextFileW(handle, &fileInfo) != 0; return FindNextFileW(handle, &fileInfo) != 0;
#else #else
ent = ::readdir(handle); ent = ::readdir(handle);
return ent != 0; return ent != NULL;
#endif #endif
} }
@ -65,6 +123,11 @@ bool FolderIterator::d_name(std::string& dest)
return true; return true;
} }
const std::string& FolderIterator::file_fullpath() { return mFullPath ; }
const std::string& FolderIterator::file_name() { return mFileName ; }
uint64_t FolderIterator::file_size() { return mFileSize ; }
time_t FolderIterator::file_modtime() { return mFileModTime ; }
bool FolderIterator::closedir() bool FolderIterator::closedir()
{ {
if(!validity) if(!validity)

View File

@ -2,6 +2,7 @@
#define FOLDERITERATOR_H #define FOLDERITERATOR_H
#include <stdint.h>
#include <iostream> #include <iostream>
#include <cstdio> #include <cstdio>
@ -24,14 +25,24 @@ public:
FolderIterator(const std::string& folderName); FolderIterator(const std::string& folderName);
~FolderIterator(); ~FolderIterator();
bool isValid() const { return validity; } enum { TYPE_UNKNOWN = 0x00,
TYPE_FILE = 0x01,
TYPE_DIR = 0x02
};
bool isValid() const { return validity; }
bool readdir(); bool readdir();
void next();
bool d_name(std::string& dest); bool d_name(std::string& dest);
bool closedir(); bool closedir();
const std::string& file_name() ;
const std::string& file_fullpath() ;
uint64_t file_size() ;
uint64_t file_type() ;
time_t file_modtime() ;
private: private:
bool validity; bool validity;
@ -43,7 +54,15 @@ private:
DIR* handle; DIR* handle;
struct dirent* ent; struct dirent* ent;
#endif #endif
void updateStatsInfo() ;
bool mStatInfoOk ;
time_t mFileModTime ;
uint64_t mFileSize ;
uint8_t mType ;
std::string mFileName ;
std::string mFullPath ;
std::string mFolderName ;
}; };

View File

@ -290,7 +290,7 @@ int RsIntroServer::checkForNewCerts()
mCertCheckTime = now; mCertCheckTime = now;
struct stat64 buf; struct stat64 buf;
while(dirIt.readdir()) for(;dirIt.isValid();dirIt.next())
{ {
/* check entry type */ /* check entry type */
std::string fname; std::string fname;