Merge pull request #2444 from G10h4ck/single_file_share_plus_cleanup

Single file share plus cleanup
This commit is contained in:
G10h4ck 2021-10-19 15:45:32 +02:00 committed by GitHub
commit 58016fff65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 870 additions and 534 deletions

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2016 by Mr.Alice <mralice@users.sourceforge.net> *
* Copyright (C) 2016 Mr.Alice <mralice@users.sourceforge.net> *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -29,6 +31,7 @@
#include "dir_hierarchy.h"
#include "filelist_io.h"
#include "file_sharing_defaults.h"
#include "util/cxx17retrocompat.h"
#ifdef RS_DEEP_FILES_INDEX
# include "deep_search/filesindex.hpp"
@ -70,7 +73,8 @@ InternalFileHierarchyStorage::InternalFileHierarchyStorage() : mRoot(0)
mTotalFiles = 0 ;
}
bool InternalFileHierarchyStorage::getDirHashFromIndex(const DirectoryStorage::EntryIndex& index,RsFileHash& hash) const
bool InternalFileHierarchyStorage::getDirHashFromIndex(
const DirectoryStorage::EntryIndex& index, RsFileHash& hash ) const
{
if(!checkIndex(index,FileStorageNode::TYPE_DIR))
return false ;
@ -79,6 +83,7 @@ bool InternalFileHierarchyStorage::getDirHashFromIndex(const DirectoryStorage::E
return true;
}
bool InternalFileHierarchyStorage::getIndexFromDirHash(const RsFileHash& hash,DirectoryStorage::EntryIndex& index)
{
std::map<RsFileHash,DirectoryStorage::EntryIndex>::iterator it = mDirHashes.find(hash) ;
@ -88,35 +93,39 @@ bool InternalFileHierarchyStorage::getIndexFromDirHash(const RsFileHash& hash,Di
index = it->second;
// make sure the hash actually points to some existing file. If not, remove it. This is a lazy update of dir hashes: when we need them, we check them.
if(!checkIndex(index, FileStorageNode::TYPE_DIR) || static_cast<DirEntry*>(mNodes[index])->dir_hash != hash)
{
std::cerr << "(II) removing non existing hash from dir hash list: " << hash << std::endl;
mDirHashes.erase(it) ;
return false ;
}
/* make sure the hash actually points to some existing directory. If not,
* remove it. This is an opportunistic update of dir hashes: when we need
* them, we check them. */
if( !checkIndex(index, FileStorageNode::TYPE_DIR) ||
static_cast<DirEntry*>(mNodes[index])->dir_hash != hash )
{
RS_INFO("removing non existing dir hash: ", hash, " from dir hash list");
mDirHashes.erase(it);
return false;
}
return true;
}
bool InternalFileHierarchyStorage::getIndexFromFileHash(const RsFileHash& hash,DirectoryStorage::EntryIndex& index)
bool InternalFileHierarchyStorage::getIndexFromFileHash(
const RsFileHash& hash, DirectoryStorage::EntryIndex& index )
{
std::map<RsFileHash,DirectoryStorage::EntryIndex>::iterator it = mFileHashes.find(hash) ;
auto it = std::as_const(mFileHashes).find(hash);
if(it == mFileHashes.end()) return false;
if(it == mFileHashes.end())
return false;
index = it->second;
index = it->second;
/* make sure the hash actually points to some existing file. If not, remove
* it. This is an opportunistic update of file hashes: when we need them,
* we check them. */
if( !checkIndex(it->second, FileStorageNode::TYPE_FILE) ||
static_cast<FileEntry*>(mNodes[index])->file_hash != hash )
{
RS_INFO("removing non existing file hash: ", hash, " from file hash list");
mFileHashes.erase(it);
return false;
}
// make sure the hash actually points to some existing file. If not, remove it. This is a lazy update of file hashes: when we need them, we check them.
if(!checkIndex(it->second, FileStorageNode::TYPE_FILE) || static_cast<FileEntry*>(mNodes[index])->file_hash != hash)
{
std::cerr << "(II) removing non existing hash from file hash list: " << hash << std::endl;
mFileHashes.erase(it) ;
return false ;
}
return true;
return true;
}
bool InternalFileHierarchyStorage::getChildIndex(DirectoryStorage::EntryIndex e,int row,DirectoryStorage::EntryIndex& c) const
@ -155,10 +164,13 @@ bool InternalFileHierarchyStorage::isIndexValid(DirectoryStorage::EntryIndex e)
return e < mNodes.size() && mNodes[e] != NULL ;
}
bool InternalFileHierarchyStorage::updateSubDirectoryList(const DirectoryStorage::EntryIndex& indx, const std::set<std::string>& subdirs, const RsFileHash& random_hash_seed)
bool InternalFileHierarchyStorage::updateSubDirectoryList(
const DirectoryStorage::EntryIndex& indx,
const std::set<std::string>& subdirs,
const RsFileHash& random_hash_seed )
{
if(!checkIndex(indx,FileStorageNode::TYPE_DIR))
return false;
if(!checkIndex(indx,FileStorageNode::TYPE_DIR))
return false;
DirEntry& d(*static_cast<DirEntry*>(mNodes[indx])) ;
@ -284,10 +296,17 @@ bool InternalFileHierarchyStorage::checkIndex(DirectoryStorage::EntryIndex indx,
return true;
}
bool InternalFileHierarchyStorage::updateSubFilesList(const DirectoryStorage::EntryIndex& indx,const std::map<std::string,DirectoryStorage::FileTS>& subfiles,std::map<std::string,DirectoryStorage::FileTS>& new_files)
bool InternalFileHierarchyStorage::updateSubFilesList(
const DirectoryStorage::EntryIndex& indx,
const std::map<std::string,DirectoryStorage::FileTS>& subfiles,
std::map<std::string,DirectoryStorage::FileTS>& new_files )
{
if(!checkIndex(indx,FileStorageNode::TYPE_DIR))
return false;
if(!checkIndex(indx, FileStorageNode::TYPE_DIR))
{
RS_ERR("indx: ", indx, std::errc::not_a_directory);
print_stacktrace();
return false;
}
DirEntry& d(*static_cast<DirEntry*>(mNodes[indx])) ;
new_files = subfiles ;
@ -312,9 +331,11 @@ bool InternalFileHierarchyStorage::updateSubFilesList(const DirectoryStorage::En
continue;
}
if(it->second.modtime != f.file_modtime || it->second.size != f.file_size) // file is newer and/or has different size
// file is newer and/or has different size
if(it->second.modtime != f.file_modtime || it->second.size != f.file_size)
{
f.file_hash.clear(); // hash needs recomputing
// hash needs recomputing
f.file_hash.clear();
f.file_modtime = it->second.modtime;
f.file_size = it->second.size;
@ -342,13 +363,16 @@ bool InternalFileHierarchyStorage::updateSubFilesList(const DirectoryStorage::En
}
return true;
}
bool InternalFileHierarchyStorage::updateHash(const DirectoryStorage::EntryIndex& file_index,const RsFileHash& hash)
bool InternalFileHierarchyStorage::updateHash(
const DirectoryStorage::EntryIndex& file_index, const RsFileHash& hash )
{
if(!checkIndex(file_index,FileStorageNode::TYPE_FILE))
{
std::cerr << "[directory storage] (EE) cannot update file at index " << file_index << ". Not a valid index, or not a file." << std::endl;
return false;
}
if(!checkIndex(file_index, FileStorageNode::TYPE_FILE))
{
RS_ERR( "Cannot update file at index ", file_index,
". Not a valid index, or not a file." );
print_stacktrace();
return false;
}
#ifdef DEBUG_DIRECTORY_STORAGE
std::cerr << "[directory storage] updating hash at index " << file_index << ", hash=" << hash << std::endl;
#endif
@ -436,14 +460,20 @@ DirectoryStorage::EntryIndex InternalFileHierarchyStorage::allocateNewIndex()
return mNodes.size()-1 ;
}
bool InternalFileHierarchyStorage::updateDirEntry(const DirectoryStorage::EntryIndex& indx,const std::string& dir_name,rstime_t most_recent_time,rstime_t dir_modtime,const std::vector<RsFileHash>& subdirs_hash,const std::vector<FileEntry>& subfiles_array)
bool InternalFileHierarchyStorage::updateDirEntry(
const DirectoryStorage::EntryIndex& indx, const std::string& dir_name,
rstime_t most_recent_time, rstime_t dir_modtime,
const std::vector<RsFileHash>& subdirs_hash,
const std::vector<FileEntry>& subfiles_array )
{
if(!checkIndex(indx,FileStorageNode::TYPE_DIR))
{
std::cerr << "[directory storage] (EE) cannot update dir at index " << indx << ". Not a valid index, or not an existing dir." << std::endl;
return false;
}
DirEntry& d(*static_cast<DirEntry*>(mNodes[indx])) ;
if(!checkIndex(indx,FileStorageNode::TYPE_DIR))
{
RS_ERR( "cannot update dir at index ", indx, ". Not a valid index, or "
"not an existing dir." );
return false;
}
DirEntry& d(*static_cast<DirEntry*>(mNodes[indx]));
#ifdef DEBUG_DIRECTORY_STORAGE
std::cerr << "Updating dir entry: name=\"" << dir_name << "\", most_recent_time=" << most_recent_time << ", modtime=" << dir_modtime << std::endl;
@ -703,14 +733,14 @@ const InternalFileHierarchyStorage::FileStorageNode *InternalFileHierarchyStorag
return NULL ;
}
const InternalFileHierarchyStorage::DirEntry *InternalFileHierarchyStorage::getDirEntry(DirectoryStorage::EntryIndex indx) const
const InternalFileHierarchyStorage::DirEntry*
InternalFileHierarchyStorage::getDirEntry(DirectoryStorage::EntryIndex indx) const
{
if(!checkIndex(indx,FileStorageNode::TYPE_DIR))
return NULL ;
return static_cast<DirEntry*>(mNodes[indx]) ;
if(!checkIndex(indx,FileStorageNode::TYPE_DIR)) return nullptr;
return static_cast<DirEntry*>(mNodes[indx]);
}
const InternalFileHierarchyStorage::FileEntry *InternalFileHierarchyStorage::getFileEntry(DirectoryStorage::EntryIndex indx) const
const InternalFileHierarchyStorage::FileEntry*
InternalFileHierarchyStorage::getFileEntry(DirectoryStorage::EntryIndex indx) const
{
if(!checkIndex(indx,FileStorageNode::TYPE_FILE))
return NULL ;
@ -754,7 +784,10 @@ bool InternalFileHierarchyStorage::searchHash(const RsFileHash& hash,DirectorySt
class DirectoryStorageExprFileEntry: public RsRegularExpression::ExpFileEntry
{
public:
DirectoryStorageExprFileEntry(const InternalFileHierarchyStorage::FileEntry& fe,const InternalFileHierarchyStorage::DirEntry& parent) : mFe(fe),mDe(parent) {}
DirectoryStorageExprFileEntry(
const InternalFileHierarchyStorage::FileEntry& fe,
const InternalFileHierarchyStorage::DirEntry& parent ) :
mFe(fe), mDe(parent) {}
inline virtual const std::string& file_name() const { return mFe.file_name ; }
inline virtual uint64_t file_size() const { return mFe.file_size ; }
@ -768,14 +801,18 @@ private:
const InternalFileHierarchyStorage::DirEntry& mDe ;
};
int InternalFileHierarchyStorage::searchBoolExp(RsRegularExpression::Expression * exp, std::list<DirectoryStorage::EntryIndex> &results) const
int InternalFileHierarchyStorage::searchBoolExp(
RsRegularExpression::Expression* exp,
std::list<DirectoryStorage::EntryIndex>& results ) const
{
for(std::map<RsFileHash,DirectoryStorage::EntryIndex>::const_iterator it(mFileHashes.begin());it!=mFileHashes.end();++it)
if(mNodes[it->second] != NULL && exp->eval(
DirectoryStorageExprFileEntry(*static_cast<const FileEntry*>(mNodes[it->second]),
*static_cast<const DirEntry*>(mNodes[mNodes[it->second]->parent_index])
)))
results.push_back(it->second);
for(auto& it: std::as_const(mFileHashes))
if(mNodes[it.second])
if(exp->eval(
DirectoryStorageExprFileEntry(
*static_cast<const FileEntry*>(mNodes[it.second]),
*static_cast<const DirEntry*>(mNodes[mNodes[it.second]->parent_index])
) ))
results.push_back(it.second);
return 0;
}
@ -784,27 +821,43 @@ int InternalFileHierarchyStorage::searchTerms(
const std::list<std::string>& terms,
std::list<DirectoryStorage::EntryIndex>& results ) const
{
// most entries are likely to be files, so we could do a linear search over the entries tab.
// instead we go through the table of hashes.
/* most entries are likely to be files, so we could do a linear search over
* the entries tab. Instead we go through the table of hashes.*/
for(std::map<RsFileHash,DirectoryStorage::EntryIndex>::const_iterator it(mFileHashes.begin());it!=mFileHashes.end();++it)
if(mNodes[it->second] != NULL)
{
const std::string &str1 = static_cast<FileEntry*>(mNodes[it->second])->file_name;
for(auto& it : std::as_const(mFileHashes))
{
// node may be null for some hash waiting to be deleted
if(mNodes[it.second])
{
rs_view_ptr<FileEntry> tFileEntry =
static_cast<FileEntry*>(mNodes[it.second]);
for(std::list<std::string>::const_iterator iter(terms.begin()); iter != terms.end(); ++iter)
{
/* always ignore case */
const std::string &str2 = (*iter);
/* Most file will just have file name stored, but single file shared
* without a shared dir will contain full path instead of just the
* name, so purify it to perform the search */
std::string tFilename = tFileEntry->file_name;
if(tFileEntry->file_name.find("/") != std::string::npos)
{
std::string _tParentDir;
RsDirUtil::splitDirFromFile(
tFileEntry->file_name, _tParentDir, tFilename );
}
if(str1.end() != std::search( str1.begin(), str1.end(), str2.begin(), str2.end(), RsRegularExpression::CompareCharIC() ))
{
results.push_back(it->second);
break;
}
}
}
return 0 ;
for(auto& termIt : std::as_const(terms))
{
/* always ignore case */
if(tFilename.end() != std::search(
tFilename.begin(), tFilename.end(),
termIt.begin(), termIt.end(),
RsRegularExpression::CompareCharIC() ))
{
results.push_back(it.second);
break;
}
}
}
}
return 0;
}
bool InternalFileHierarchyStorage::check(std::string& error_string) // checks consistency of storage.
@ -958,8 +1011,9 @@ void InternalFileHierarchyStorage::recursPrint(int depth,DirectoryStorage::Entry
bool InternalFileHierarchyStorage::nodeAccessError(const std::string& s)
{
std::cerr << "(EE) InternalDirectoryStructure: ERROR: " << s << std::endl;
return false ;
RS_ERR(s);
print_stacktrace();
return false;
}
// Removes the given subdirectory from the parent node and all its pendign subdirs and files.

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2016 by Mr.Alice <mralice@users.sourceforge.net> *
* Copyright (C) 2016 Mr.Alice <mralice@users.sourceforge.net> *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -30,6 +32,7 @@
#include "directory_storage.h"
#include "dir_hierarchy.h"
#include "filelist_io.h"
#include "util/cxx17retrocompat.h"
#ifdef RS_DEEP_FILES_INDEX
# include "deep_search/filesindex.hpp"
@ -67,8 +70,11 @@ DirectoryStorage::FileIterator& DirectoryStorage::FileIterator::operator++()
return *this;
}
DirectoryStorage::EntryIndex DirectoryStorage::FileIterator::operator*() const { return mStorage->getSubFileIndex(mParentIndex,mFileTabIndex) ; }
DirectoryStorage::EntryIndex DirectoryStorage::DirIterator ::operator*() const { return mStorage->getSubDirIndex(mParentIndex,mDirTabIndex) ; }
DirectoryStorage::EntryIndex DirectoryStorage::FileIterator::operator*() const
{ return mStorage->getSubFileIndex(mParentIndex, mFileTabIndex); }
DirectoryStorage::EntryIndex DirectoryStorage::DirIterator::operator*() const
{ return mStorage->getSubDirIndex(mParentIndex, mDirTabIndex); }
DirectoryStorage::FileIterator::operator bool() const { return **this != DirectoryStorage::NO_INDEX; }
DirectoryStorage::DirIterator ::operator bool() const { return **this != DirectoryStorage::NO_INDEX; }
@ -139,7 +145,9 @@ bool DirectoryStorage::updateSubDirectoryList(const EntryIndex& indx, const std:
mChanged = true ;
return res ;
}
bool DirectoryStorage::updateSubFilesList(const EntryIndex& indx,const std::map<std::string,FileTS>& subfiles,std::map<std::string,FileTS>& new_files)
bool DirectoryStorage::updateSubFilesList(
const EntryIndex& indx, const std::map<std::string,FileTS>& subfiles,
std::map<std::string,FileTS>& new_files )
{
RS_STACK_MUTEX(mDirStorageMtx) ;
bool res = mFileHierarchy->updateSubFilesList(indx,subfiles,new_files) ;
@ -348,7 +356,8 @@ int LocalDirectoryStorage::searchHash(const RsFileHash& hash, RsFileHash& real_h
return false ;
}
void LocalDirectoryStorage::setSharedDirectoryList(const std::list<SharedDirInfo>& lst)
void LocalDirectoryStorage::setSharedDirectoryList(
const std::list<SharedDirInfo>& lst )
{
std::set<std::string> dirs_with_new_virtualname ;
bool dirs_with_changed_flags = false ;
@ -379,7 +388,9 @@ void LocalDirectoryStorage::setSharedDirectoryList(const std::list<SharedDirInfo
virtual_names.insert(candidate_virtual_name) ;
}
// now for each member of the processed list, check if it is an existing shared directory that has been changed. If so, we need to update the dir TS of that directory
/* now for each member of the processed list, check if it is an existing
* shared directory that has been changed. If so, we need to update the
* dir TS of that directory */
std::map<std::string,SharedDirInfo> new_dirs ;
@ -529,7 +540,7 @@ bool LocalDirectoryStorage::updateHash(
#endif
ret = (!update_internal_hierarchy) ||
mFileHierarchy->updateHash(index,hash);
mFileHierarchy->updateHash(index, hash);
} // RS_STACK_MUTEX(mDirStorageMtx);
#ifdef RS_DEEP_FILES_INDEX
@ -617,48 +628,78 @@ bool LocalDirectoryStorage::getFileSharingPermissions(const EntryIndex& indx,Fil
return locked_getFileSharingPermissions(indx,flags,parent_groups) ;
}
bool LocalDirectoryStorage::locked_getFileSharingPermissions(const EntryIndex& indx, FileStorageFlags& flags, std::list<RsNodeGroupId> &parent_groups)
bool LocalDirectoryStorage::locked_getFileSharingPermissions(
const EntryIndex& indx, FileStorageFlags& flags,
std::list<RsNodeGroupId>& parent_groups )
{
flags.clear() ;
parent_groups.clear();
flags.clear();
parent_groups.clear();
std::string base_dir;
/* We got a request for root directory no need to do anything more after
* clearing outputs */
if(!indx) return true;
const InternalFileHierarchyStorage::FileStorageNode *n = mFileHierarchy->getNode(indx) ;
using FileStorageNode = InternalFileHierarchyStorage::FileStorageNode;
using EntryIndex = DirectoryStorage::EntryIndex;
if(n == NULL)
return false ;
rs_view_ptr<const FileStorageNode> n = mFileHierarchy->getNode(indx);
if(!n)
{
RS_ERR("Node for index: ", indx, "not found");
print_stacktrace();
return false;
}
for(DirectoryStorage::EntryIndex i=((n->type()==InternalFileHierarchyStorage::FileStorageNode::TYPE_FILE)?((intptr_t)n->parent_index):indx);;)
{
const InternalFileHierarchyStorage::DirEntry *e = mFileHierarchy->getDirEntry(i) ;
// Climb down node tree up to root + 1
EntryIndex curIndex = indx;
while (n->parent_index)
{
curIndex = n->parent_index;
n = mFileHierarchy->getNode(curIndex);
}
if(e == NULL)
break ;
// Retrieve base name
std::string tBaseName;
switch (n->type())
{
// Handle single file shared case
case InternalFileHierarchyStorage::FileStorageNode::TYPE_FILE:
tBaseName = mFileHierarchy->getFileEntry(curIndex)->file_name;
break;
// Handle shared directory case
case InternalFileHierarchyStorage::FileStorageNode::TYPE_DIR:
tBaseName = mFileHierarchy->getDirEntry(curIndex)->dir_name;
break;
default:
RS_ERR("Got unhandled node type: ", n->type());
print_stacktrace();
return false;
}
if(e->parent_index == 0)
{
base_dir = e->dir_name ;
break ;
}
i = e->parent_index ;
}
// Use base name to retrieve sharing permissions
if(!tBaseName.empty())
{
auto it = std::as_const(mLocalDirs).find(tBaseName);
if(!base_dir.empty())
{
std::map<std::string,SharedDirInfo>::const_iterator it = mLocalDirs.find(base_dir) ;
if(it == mLocalDirs.end())
{
RS_ERR( "base name \"", tBaseName,
"\" for index: ", indx, " not found in shared dir list." );
print_stacktrace();
return false;
}
if(it == mLocalDirs.end())
{
std::cerr << "(II) base directory \"" << base_dir << "\" not found in shared dir list." << std::endl;
return false ;
}
flags = it->second.shareflags;
parent_groups = it->second.parent_groups;
}
else
{
RS_ERR("base name for indx: ", indx, " is empty");
print_stacktrace();
return false;
}
flags = it->second.shareflags;
parent_groups = it->second.parent_groups;
}
return true;
return true;
}
std::string LocalDirectoryStorage::locked_getVirtualDirName(EntryIndex indx) const
@ -705,134 +746,214 @@ std::string LocalDirectoryStorage::locked_getVirtualPath(EntryIndex indx) const
return it->second.virtualname + "/" + res;
}
bool LocalDirectoryStorage::serialiseDirEntry(const EntryIndex& indx,RsTlvBinaryData& bindata,const RsPeerId& client_id)
bool LocalDirectoryStorage::serialiseDirEntry(
const EntryIndex& indx, RsTlvBinaryData& bindata,
const RsPeerId& client_id )
{
RS_STACK_MUTEX(mDirStorageMtx) ;
RS_STACK_MUTEX(mDirStorageMtx);
const InternalFileHierarchyStorage::DirEntry *dir = mFileHierarchy->getDirEntry(indx);
const InternalFileHierarchyStorage::DirEntry* dir =
mFileHierarchy->getDirEntry(indx);
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
std::cerr << "Serialising Dir entry " << std::hex << indx << " for client id " << client_id << std::endl;
#endif
if(dir == NULL)
{
std::cerr << "(EE) serialiseDirEntry: ERROR. Cannot find entry " << (void*)(intptr_t)indx << std::endl;
return false;
}
// compute list of allowed subdirs
std::vector<RsFileHash> allowed_subdirs ;
FileStorageFlags node_flags ;
std::list<RsNodeGroupId> node_groups ;
if(!dir)
{
RS_ERR("Cannot find entry ", indx);
return false;
}
// for each subdir, compute the node flags and groups, then ask rsPeers to compute the mask that result from these flags for the particular peer supplied in parameter
// compute list of allowed subdirs
std::vector<RsFileHash> allowed_subdirs;
FileStorageFlags node_flags;
std::list<RsNodeGroupId> node_groups;
/* for each subdir, compute the node flags and groups, then ask rsPeers to
* compute the mask that result from these flags for the particular peer
* supplied in parameter */
for(uint32_t i=0;i<dir->subdirs.size();++i)
if(indx != 0 || (
locked_getFileSharingPermissions(
dir->subdirs[i], node_flags, node_groups ) &&
( rsPeers->computePeerPermissionFlags(
client_id, node_flags, node_groups ) &
RS_FILE_HINTS_BROWSABLE ) ))
{
RsFileHash hash;
if(!mFileHierarchy->getDirHashFromIndex(dir->subdirs[i],hash))
{
RS_ERR( "Cannot get hash from subdir index: ",
dir->subdirs[i], ". Weird bug." );
print_stacktrace();
return false;
}
allowed_subdirs.push_back(hash);
for(uint32_t i=0;i<dir->subdirs.size();++i)
if(indx != 0 || (locked_getFileSharingPermissions(dir->subdirs[i],node_flags,node_groups) && (rsPeers->computePeerPermissionFlags(client_id,node_flags,node_groups) & RS_FILE_HINTS_BROWSABLE)))
{
RsFileHash hash ;
if(!mFileHierarchy->getDirHashFromIndex(dir->subdirs[i],hash))
{
std::cerr << "(EE) Cannot get hash from subdir index " << dir->subdirs[i] << ". Weird bug." << std::endl ;
return false;
}
allowed_subdirs.push_back(hash) ;
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
std::cerr << " pushing subdir " << hash << ", array position=" << i << " indx=" << dir->subdirs[i] << std::endl;
#endif
}
}
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
else
std::cerr << " not pushing subdir " << hash << ", array position=" << i << " indx=" << dir->subdirs[i] << ": permission denied for this peer." << std::endl;
#endif
// now count the files that do not have a null hash (meaning the hash has indeed been computed)
/* now count the files that do not have a null hash (meaning the hash has
* indeed been computed), also in case files are shared singularly (without
* a shared directory) so they are child of root check browsability
* permission */
uint32_t allowed_subfiles = 0;
for(uint32_t i=0; i<dir->subfiles.size(); ++i)
{
const InternalFileHierarchyStorage::FileEntry* file =
mFileHierarchy->getFileEntry(dir->subfiles[i]);
if(file != nullptr && !file->file_hash.isNull()
&& ( indx !=0 || (
locked_getFileSharingPermissions(
dir->subfiles[i], node_flags, node_groups ) &&
rsPeers->computePeerPermissionFlags(
client_id, node_flags, node_groups ) &
RS_FILE_HINTS_BROWSABLE ) ))
allowed_subfiles++;
}
uint32_t allowed_subfiles = 0 ;
unsigned char* section_data = (unsigned char *)
rs_malloc(FL_BASE_TMP_SECTION_SIZE);
if(!section_data) return false;
for(uint32_t i=0;i<dir->subfiles.size();++i)
{
const InternalFileHierarchyStorage::FileEntry *file = mFileHierarchy->getFileEntry(dir->subfiles[i]) ;
if(file != NULL && !file->file_hash.isNull())
allowed_subfiles++ ;
}
uint32_t section_size = FL_BASE_TMP_SECTION_SIZE;
uint32_t section_offset = 0;
unsigned char *section_data = (unsigned char *)rs_malloc(FL_BASE_TMP_SECTION_SIZE) ;
/* we need to send:
* - the name of the directory, its TS
* - the index entry for each subdir (the updte TS are exchanged at a
* higher level)
* - the file info for each subfile */
if(!section_data)
return false ;
std::string virtual_dir_name = locked_getVirtualDirName(indx);
uint32_t section_size = FL_BASE_TMP_SECTION_SIZE;
uint32_t section_offset = 0;
/* Manual serialization AGAIN! This is terrible and should be ported to the
* new serialization system ASAP! */
if(!FileListIO::writeField(
section_data, section_size, section_offset,
FILE_LIST_IO_TAG_DIR_NAME, virtual_dir_name ))
{ free(section_data); return false; }
if(!FileListIO::writeField(
section_data, section_size, section_offset,
FILE_LIST_IO_TAG_RECURS_MODIF_TS,
(uint32_t)dir->dir_most_recent_time ))
{ free(section_data); return false; }
if(!FileListIO::writeField(
section_data, section_size, section_offset,
FILE_LIST_IO_TAG_MODIF_TS, (uint32_t)dir->dir_modtime ))
{ free(section_data); return false;}
// we need to send:
// - the name of the directory, its TS
// - the index entry for each subdir (the updte TS are exchanged at a higher level)
// - the file info for each subfile
//
std::string virtual_dir_name = locked_getVirtualDirName(indx) ;
// serialise number of subdirs and number of subfiles
if(!FileListIO::writeField(
section_data, section_size, section_offset,
FILE_LIST_IO_TAG_RAW_NUMBER, (uint32_t)allowed_subdirs.size() ))
{ free(section_data); return false; }
if(!FileListIO::writeField(
section_data, section_size, section_offset,
FILE_LIST_IO_TAG_RAW_NUMBER, (uint32_t)allowed_subfiles ))
{ free(section_data); return false; }
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_DIR_NAME ,virtual_dir_name )) { free(section_data); return false ;}
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_RECURS_MODIF_TS,(uint32_t)dir->dir_most_recent_time)) { free(section_data); return false ;}
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_MODIF_TS ,(uint32_t)dir->dir_modtime )) { free(section_data); return false ;}
// serialise subdirs entry indexes
for(uint32_t i=0; i<allowed_subdirs.size(); ++i)
if(!FileListIO::writeField(
section_data, section_size, section_offset,
FILE_LIST_IO_TAG_ENTRY_INDEX, allowed_subdirs[i] ))
{ free(section_data); return false; }
// serialise number of subdirs and number of subfiles
// serialise directory subfiles, with info for each of them
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t)allowed_subdirs.size() )) { free(section_data); return false ;}
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t)allowed_subfiles )) { free(section_data); return false ;}
unsigned char* file_section_data =
(unsigned char *) rs_malloc(FL_BASE_TMP_SECTION_SIZE);
if(!file_section_data)
{
free(section_data);
return false;
}
// serialise subdirs entry indexes
uint32_t file_section_size = FL_BASE_TMP_SECTION_SIZE;
for(uint32_t i=0;i<allowed_subdirs.size();++i)
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_ENTRY_INDEX ,allowed_subdirs[i] )) { free(section_data); return false ;}
for(uint32_t i=0; i<dir->subfiles.size(); ++i)
{
uint32_t file_section_offset = 0;
// serialise directory subfiles, with info for each of them
const InternalFileHierarchyStorage::FileEntry* file =
mFileHierarchy->getFileEntry(dir->subfiles[i]);
unsigned char *file_section_data = (unsigned char *)rs_malloc(FL_BASE_TMP_SECTION_SIZE) ;
if(file == nullptr || file->file_hash.isNull())
{
RS_INFO( "skipping unhashed or Null file entry ",
dir->subfiles[i], " to get/send file info." );
continue;
}
if(!file_section_data)
{
free(section_data);
return false ;
}
if(indx == 0)
{
if(!locked_getFileSharingPermissions(
dir->subfiles[i], node_flags, node_groups ))
{
RS_ERR( "Failure getting sharing permission for single file: ",
dir->subfiles[i] );
print_stacktrace();
continue;
}
uint32_t file_section_size = FL_BASE_TMP_SECTION_SIZE ;
if(!( rsPeers->computePeerPermissionFlags(
client_id, node_flags, node_groups ) &
RS_FILE_HINTS_BROWSABLE ))
{
RS_INFO( "Skipping single file shared without browse "
"permission" );
continue;
}
}
for(uint32_t i=0;i<dir->subfiles.size();++i)
{
uint32_t file_section_offset = 0 ;
if(!FileListIO::writeField(
file_section_data, file_section_size, file_section_offset,
FILE_LIST_IO_TAG_FILE_NAME, file->file_name ))
{ free(section_data); free(file_section_data); return false; }
if(!FileListIO::writeField(
file_section_data, file_section_size, file_section_offset,
FILE_LIST_IO_TAG_FILE_SIZE, file->file_size ))
{ free(section_data); free(file_section_data); return false; }
if(!FileListIO::writeField(
file_section_data, file_section_size, file_section_offset,
FILE_LIST_IO_TAG_FILE_SHA1_HASH, file->file_hash ))
{ free(section_data); free(file_section_data); return false; }
if(!FileListIO::writeField(
file_section_data, file_section_size, file_section_offset,
FILE_LIST_IO_TAG_MODIF_TS, (uint32_t)file->file_modtime ))
{ free(section_data); free(file_section_data); return false; }
const InternalFileHierarchyStorage::FileEntry *file = mFileHierarchy->getFileEntry(dir->subfiles[i]) ;
if(file == NULL || file->file_hash.isNull())
{
std::cerr << "(II) skipping unhashed or Null file entry " << dir->subfiles[i] << " to get/send file info." << std::endl;
continue ;
}
if(!FileListIO::writeField(file_section_data,file_section_size,file_section_offset,FILE_LIST_IO_TAG_FILE_NAME ,file->file_name )) { free(section_data);free(file_section_data);return false ;}
if(!FileListIO::writeField(file_section_data,file_section_size,file_section_offset,FILE_LIST_IO_TAG_FILE_SIZE ,file->file_size )) { free(section_data);free(file_section_data);return false ;}
if(!FileListIO::writeField(file_section_data,file_section_size,file_section_offset,FILE_LIST_IO_TAG_FILE_SHA1_HASH,file->file_hash )) { free(section_data);free(file_section_data);return false ;}
if(!FileListIO::writeField(file_section_data,file_section_size,file_section_offset,FILE_LIST_IO_TAG_MODIF_TS ,(uint32_t)file->file_modtime)) { free(section_data);free(file_section_data);return false ;}
// now write the whole string into a single section in the file
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_REMOTE_FILE_ENTRY,file_section_data,file_section_offset)) { free(section_data); free(file_section_data);return false ;}
// now write the whole string into a single section in the file
if(!FileListIO::writeField(
section_data, section_size, section_offset,
FILE_LIST_IO_TAG_REMOTE_FILE_ENTRY,
file_section_data, file_section_offset ))
{ free(section_data); free(file_section_data); return false; }
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
std::cerr << " pushing subfile " << file->hash << ", array position=" << i << " indx=" << dir->subfiles[i] << std::endl;
#endif
}
free(file_section_data) ;
}
free(file_section_data);
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
std::cerr << "Serialised dir entry to send for entry index " << (void*)(intptr_t)indx << ". Data size is " << section_size << " bytes" << std::endl;
#endif
bindata.bin_data = realloc(section_data,section_offset) ; // This discards the possibly unused trailing bytes in the end of section_data
bindata.bin_len = section_offset ;
// Discards the possibly unused trailing bytes in the end of section_data
bindata.bin_data = realloc(section_data,section_offset);
bindata.bin_len = section_offset;
return true ;
return true;
}

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2016 by Mr.Alice <mralice@users.sourceforge.net> *
* Copyright (C) 2016 Mr.Alice <mralice@users.sourceforge.net> *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -19,13 +21,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
******************************************************************************/
#include "util/cxx17retrocompat.h"
#include "util/folderiterator.h"
#include "util/rstime.h"
#include "rsserver/p3face.h"
#include "directory_storage.h"
#include "directory_updater.h"
#include "file_sharing_defaults.h"
#include "util/rsdebuglevel3.h"
//#define DEBUG_LOCAL_DIR_UPDATER 1
@ -121,185 +125,238 @@ void LocalDirectoryUpdater::forceUpdate(bool add_safe_delay)
bool LocalDirectoryUpdater::sweepSharedDirectories(bool& some_files_not_ready)
{
if(mHashSalt.isNull())
{
std::cerr << "(EE) no salt value in LocalDirectoryUpdater. Is that a bug?" << std::endl;
return false;
}
if(mHashSalt.isNull())
{
RS_ERR("no salt value in LocalDirectoryUpdater");
print_stacktrace();
return false;
}
mIsChecking = true ;
mIsChecking = true;
RsServer::notify()->notifyListPreChange(NOTIFY_LIST_DIRLIST_LOCAL, 0);
#ifdef DEBUG_LOCAL_DIR_UPDATER
std::cerr << "[directory storage] LocalDirectoryUpdater::sweep()" << std::endl;
#endif
RsServer::notify()->notifyListPreChange(NOTIFY_LIST_DIRLIST_LOCAL, 0);
// recursive update algorithm works that way:
// - 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.
// - the information that is costly to compute (the hash) is store externally into a separate structure.
// - 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 ;
mSharedDirectories->getSharedDirectoryList(shared_directory_list);
/* recursive update algorithm works that way:
* - 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.
* - the information that is costly to compute (the hash) is stored
* externally into a separate structure.
* - 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;
mSharedDirectories->getSharedDirectoryList(shared_directory_list);
std::set<std::string> sub_dir_list;
std::set<std::string> sub_dir_list ;
/* Support also single files sharing as it make much more sense on some
* platforms like Android */
std::map<std::string, DirectoryStorage::FileTS> singleFilesMap;
// We re-check that each dir actually exists. It might have been removed from the disk.
/* We re-check that each dir actually exists. It might have been removed
* from the disk. Accept also single files not just directories. */
for(auto& realDir: std::as_const(shared_directory_list))
{
const auto& fPath = realDir.filename;
if(RsDirUtil::checkDirectory(fPath))
sub_dir_list.insert(fPath);
else if (RsDirUtil::fileExists(fPath))
{
rstime_t lastWrite= RsDirUtil::lastWriteTime(fPath);
if(time(nullptr) >= lastWrite + MIN_TIME_AFTER_LAST_MODIFICATION)
{
uint64_t fSize = 0;
RsDirUtil::checkFile(fPath,fSize);
for(std::list<SharedDirInfo>::const_iterator real_dir_it(shared_directory_list.begin());real_dir_it!=shared_directory_list.end();++real_dir_it)
if(RsDirUtil::checkDirectory( (*real_dir_it).filename ) )
sub_dir_list.insert( (*real_dir_it).filename ) ;
singleFilesMap[fPath].modtime = lastWrite;
singleFilesMap[fPath].size = fSize;
}
else
{
some_files_not_ready = true;
RS_INFO( "file: \"", fPath, "\" is "
"probably being written to. Keep it for later");
}
}
else RS_WARN( "Got non existent file \"", fPath,
"\" in shared directories list. Ignored." );
}
// make sure that entries in stored_dir_it are the same than paths in real_dir_it, and in the same order.
{
const auto tRoot = mSharedDirectories->root();
std::map<std::string, DirectoryStorage::FileTS> needsUpdate;
mSharedDirectories->updateSubFilesList(
tRoot, singleFilesMap, needsUpdate);
mSharedDirectories->updateSubDirectoryList(mSharedDirectories->root(),sub_dir_list,mHashSalt) ;
for( DirectoryStorage::FileIterator storedSingleFilesIt(
mSharedDirectories, mSharedDirectories->root() );
storedSingleFilesIt; ++storedSingleFilesIt )
{
const auto& it = storedSingleFilesIt;
RsFileHash hash;
if( mHashCache->requestHash(
it.name(), it.size(), it.modtime(), hash,
this, *it ) )
mSharedDirectories->updateHash(*it, hash, it.hash() != hash);
}
}
// now for each of them, go recursively and match both files and dirs
/* 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, mHashSalt );
std::set<std::string> existing_dirs ;
// now for each of them, go recursively and match both files and dirs
std::set<std::string> existing_dirs;
for( DirectoryStorage::DirIterator stored_dir_it(
mSharedDirectories, mSharedDirectories->root() );
stored_dir_it; ++stored_dir_it )
{
RS_DBG4("recursing into \"", stored_dir_it.name());
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
existing_dirs.insert(RsDirUtil::removeSymLinks(stored_dir_it.name()));
recursUpdateSharedDir(
stored_dir_it.name(), *stored_dir_it,
existing_dirs, 1, some_files_not_ready );
/* 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. */
}
recursUpdateSharedDir(stored_dir_it.name(), *stored_dir_it,existing_dirs,1,some_files_not_ready) ; // 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);
mIsChecking = false;
RsServer::notify()->notifyListChange(NOTIFY_LIST_DIRLIST_LOCAL, 0);
mIsChecking = false ;
return true ;
return true;
}
void LocalDirectoryUpdater::recursUpdateSharedDir(const std::string& cumulated_path, DirectoryStorage::EntryIndex indx,std::set<std::string>& existing_directories,uint32_t current_depth,bool& some_files_not_ready)
void LocalDirectoryUpdater::recursUpdateSharedDir(
const std::string& cumulated_path, DirectoryStorage::EntryIndex indx,
std::set<std::string>& existing_directories, uint32_t current_depth,
bool& some_files_not_ready )
{
#ifdef DEBUG_LOCAL_DIR_UPDATER
std::cerr << "[directory storage] parsing directory " << cumulated_path << ", index=" << indx << std::endl;
#endif
RS_DBG4("parsing directory \"", cumulated_path, "\" index: ", indx);
// make sure list of subdirs is the same
// make sure list of subfiles is the same
// request all hashes to the hashcache
/* 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,mFollowSymLinks,false); // disallow symbolic links and files from the future.
// disallow symbolic links and files from the future.
librs::util::FolderIterator dirIt(cumulated_path, mFollowSymLinks, false);
rstime_t dir_local_mod_time ;
if(!mSharedDirectories->getDirectoryLocalModTime(indx,dir_local_mod_time))
{
std::cerr << "(EE) Cannot get local mod time for dir index " << indx << std::endl;
return;
}
rstime_t dir_local_mod_time;
if(!mSharedDirectories->getDirectoryLocalModTime(indx,dir_local_mod_time))
{
RS_ERR("Cannot get local mod time for dir index: ", indx);
print_stacktrace();
return;
}
rstime_t now = time(NULL) ;
rstime_t now = time(nullptr);
/* the > is because we may have changed the virtual name, and therefore the
* TS wont match. We only want to detect when the directory has changed on
* the disk */
if(mNeedsFullRecheck || dirIt.dir_modtime() > dir_local_mod_time)
{
// collect subdirs and subfiles
std::map<std::string, DirectoryStorage::FileTS> subfiles;
std::set<std::string> subdirs;
if(mNeedsFullRecheck || dirIt.dir_modtime() > dir_local_mod_time) // the > is because we may have changed the virtual name, and therefore the TS wont match.
// we only want to detect when the directory has changed on the disk
{
// collect subdirs and subfiles
for( ; dirIt.isValid(); dirIt.next() )
if(filterFile(dirIt.file_name()))
{
const auto fType = dirIt.file_type();
switch(fType)
{
case librs::util::FolderIterator::TYPE_FILE:
if(now >= dirIt.file_modtime() + MIN_TIME_AFTER_LAST_MODIFICATION)
{
subfiles[dirIt.file_name()].modtime = dirIt.file_modtime();
subfiles[dirIt.file_name()].size = dirIt.file_size();
RS_DBG4("adding sub-file \"", dirIt.file_name(), "\"");
}
else
{
some_files_not_ready = true;
RS_INFO( "file: \"", dirIt.file_fullpath(), "\" is "
"probably being written to. Keep it for later");
}
break;
case librs::util::FolderIterator::TYPE_DIR:
{
bool dir_is_accepted = true;
/* 64 is here as a safe limit, to make infinite loops
* impossible.
* TODO: Make it a visible constexpr in the header */
if( (mMaxShareDepth > 0u && current_depth > mMaxShareDepth)
|| (mMaxShareDepth == 0 && current_depth >= 64) )
dir_is_accepted = false;
std::map<std::string,DirectoryStorage::FileTS> subfiles ;
std::set<std::string> subdirs ;
if(dir_is_accepted && mFollowSymLinks && mIgnoreDuplicates)
{
std::string real_path = RsDirUtil::removeSymLinks(
cumulated_path + "/" + dirIt.file_name() );
for(;dirIt.isValid();dirIt.next())
if(filterFile(dirIt.file_name()))
{
switch(dirIt.file_type())
{
case librs::util::FolderIterator::TYPE_FILE:
if( existing_directories.end() !=
existing_directories.find(real_path) )
{
RS_WARN( "Directory: \"", cumulated_path,
"\" has real path: \"", real_path,
"\" which already belongs to another "
"shared directory. Ignoring" );
dir_is_accepted = false;
}
else existing_directories.insert(real_path);
}
if(dirIt.file_modtime() + MIN_TIME_AFTER_LAST_MODIFICATION < now)
{
subfiles[dirIt.file_name()].modtime = dirIt.file_modtime() ;
subfiles[dirIt.file_name()].size = dirIt.file_size();
#ifdef DEBUG_LOCAL_DIR_UPDATER
std::cerr << " adding sub-file \"" << dirIt.file_name() << "\"" << std::endl;
#endif
}
else
{
some_files_not_ready = true ;
if(dir_is_accepted) subdirs.insert(dirIt.file_name());
std::cerr << "(WW) file " << dirIt.file_fullpath() << " is probably being written to. Keeping it for later." << std::endl;
}
RS_DBG4("adding sub-dir \"", dirIt.file_name(), "\"");
break;
break;
}
default:
RS_ERR( "Got Dir entry of unknown type:", fType,
"with path \"", cumulated_path, "/",
dirIt.file_name(), "\"" );
print_stacktrace();
break;
}
}
case librs::util::FolderIterator::TYPE_DIR:
{
bool dir_is_accepted = true ;
/* update folder modificatoin time, which is the only way to detect
* e.g. removed or renamed files. */
mSharedDirectories->setDirectoryLocalModTime(indx,dirIt.dir_modtime());
if( (mMaxShareDepth > 0u && current_depth > mMaxShareDepth) || (mMaxShareDepth==0 && current_depth >= 64)) // 64 is here as a safe limit, to make loops impossible.
dir_is_accepted = false ;
// update file and dir lists for current directory.
mSharedDirectories->updateSubDirectoryList(indx,subdirs,mHashSalt);
if(dir_is_accepted && mFollowSymLinks && mIgnoreDuplicates)
{
std::string real_path = RsDirUtil::removeSymLinks(cumulated_path + "/" + dirIt.file_name()) ;
std::map<std::string, DirectoryStorage::FileTS> new_files;
mSharedDirectories->updateSubFilesList(indx, subfiles, new_files);
if(existing_directories.end() != existing_directories.find(real_path))
{
std::cerr << "(WW) Directory " << cumulated_path << " has real path " << real_path << " which already belongs to another shared directory. Ignoring" << std::endl;
dir_is_accepted = false ;
}
else
existing_directories.insert(real_path) ;
}
if(dir_is_accepted)
subdirs.insert(dirIt.file_name());
#ifdef DEBUG_LOCAL_DIR_UPDATER
std::cerr << " adding sub-dir \"" << dirIt.file_name() << "\"" << std::endl;
#endif
}
break;
default:
std::cerr << "(EE) Dir entry of unknown type with path \"" << cumulated_path << "/" << dirIt.file_name() << "\"" << std::endl;
}
}
// update folder modificatoin time, which is the only way to detect e.g. removed or renamed files.
mSharedDirectories->setDirectoryLocalModTime(indx,dirIt.dir_modtime()) ;
// update file and dir lists for current directory.
mSharedDirectories->updateSubDirectoryList(indx,subdirs,mHashSalt) ;
std::map<std::string,DirectoryStorage::FileTS> new_files ;
mSharedDirectories->updateSubFilesList(indx,subfiles,new_files) ;
// now go through list of subfiles and request the hash to hashcache
for(DirectoryStorage::FileIterator dit(mSharedDirectories,indx);dit;++dit)
{
// ask about the hash. If not present, ask HashCache. If not present, or different, the callback will update it.
RsFileHash hash ;
// mSharedDirectories does two things: store H(F), and compute H(H(F)), which is used in FT. The later is always needed.
if(mHashCache->requestHash(cumulated_path + "/" + dit.name(),dit.size(),dit.modtime(),hash,this,*dit))
mSharedDirectories->updateHash(*dit,hash,hash != dit.hash());
}
}
#ifdef DEBUG_LOCAL_DIR_UPDATER
else
std::cerr << " directory is unchanged. Keeping existing files and subdirs list." << std::endl;
#endif
// go through the list of sub-dirs and recursively update
for(DirectoryStorage::DirIterator stored_dir_it(mSharedDirectories,indx) ; stored_dir_it; ++stored_dir_it)
// now go through list of subfiles and request the hash to hashcache
for( DirectoryStorage::FileIterator dit(mSharedDirectories,indx);
dit; ++dit )
{
#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,existing_directories,current_depth+1,some_files_not_ready) ;
/* ask about the hash. If not present, ask HashCache.
* If not present, or different, the callback will update it. */
RsFileHash hash;
/* mSharedDirectories does two things: store H(F), and
* compute H(H(F)), which is used in FT.
* The later is always needed. */
if( mHashCache->requestHash(
cumulated_path + "/" + dit.name(),
dit.size(), dit.modtime(), hash, this, *dit ) )
mSharedDirectories->updateHash(*dit, hash, hash != dit.hash());
}
}
// go through the list of sub-dirs and recursively update
for( DirectoryStorage::DirIterator stored_dir_it(mSharedDirectories, indx);
stored_dir_it; ++stored_dir_it )
recursUpdateSharedDir( cumulated_path + "/" + stored_dir_it.name(),
*stored_dir_it, existing_directories,
current_depth+1, some_files_not_ready );
}
bool LocalDirectoryUpdater::filterFile(const std::string& fname) const
@ -347,7 +404,8 @@ void LocalDirectoryUpdater::hash_callback(uint32_t client_param, const std::stri
bool LocalDirectoryUpdater::hash_confirm(uint32_t client_param)
{
return mSharedDirectories->getEntryType(DirectoryStorage::EntryIndex(client_param)) == DIR_TYPE_FILE ;
return mSharedDirectories->getEntryType(
DirectoryStorage::EntryIndex(client_param) ) == DIR_TYPE_FILE;
}
void LocalDirectoryUpdater::setFileWatchPeriod(int seconds)

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2018 by Mr.Alice <mralice@users.sourceforge.net> *
* Copyright (C) 2018 Mr.Alice <mralice@users.sourceforge.net> *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -30,7 +32,7 @@
#include "retroshare/rsids.h"
#include "retroshare/rspeers.h"
#include "retroshare/rsinit.h"
#include "util/cxx17retrocompat.h"
#include "rsserver/p3face.h"
#define P3FILELISTS_DEBUG() std::cerr << time(NULL) << " : FILE_LISTS : " << __FUNCTION__ << " : "
@ -1044,31 +1046,36 @@ void p3FileDatabase::getExtraFilesDirDetails(void *ref,DirectoryStorage::EntryIn
}
// This function converts a pointer into directory details, to be used by the AbstractItemModel for browsing the files.
int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags flags) const
int p3FileDatabase::RequestDirDetails(
void* ref, DirDetails& d, FileSearchFlags flags ) const
{
RS_STACK_MUTEX(mFLSMtx) ;
RS_STACK_MUTEX(mFLSMtx);
d.children.clear();
d.children.clear();
// Case where the pointer is NULL, which means we're at the top of the list of shared directories for all friends (including us)
// or at the top of our own list of shared directories, depending on the flags.
/* Case where the pointer is NULL, which means we're at the top of the list
* of shared directories for all friends (including us) or at the top of our
* own list of shared directories, depending on the flags.
*
* Friend index is used as follows:
* 0 : own id
* 1...n : other friends
*
* entry_index: starts at 0.
*
* The point is: we cannot use (0,0) because it encodes to NULL. No existing
* combination should encode to NULL.
* So we need to properly convert the friend index into 0 or into a friend
* tab index in mRemoteDirectories.
*
* We should also check the consistency between flags and the content of ref.
*/
// Friend index is used as follows:
// 0 : own id
// 1...n : other friends
//
// entry_index: starts at 0.
//
// The point is: we cannot use (0,0) because it encodes to NULL. No existing combination should encode to NULL.
// So we need to properly convert the friend index into 0 or into a friend tab index in mRemoteDirectories.
//
// We should also check the consistency between flags and the content of ref.
if (ref == NULL)
{
d.ref = NULL ;
d.type = DIR_TYPE_ROOT;
d.parent = NULL;
if (ref == nullptr)
{
d.ref = nullptr;
d.type = DIR_TYPE_ROOT;
d.parent = nullptr;
d.prow = -1;
d.name = "root";
d.hash.clear() ;
@ -1078,12 +1085,13 @@ int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags
d.max_mtime = 0 ;
if(flags & RS_FILE_HINTS_LOCAL)
{
void *p;
{
void *p = nullptr;
{
convertEntryIndexToPointer<sizeof(void*)>(0,0,p); // root of own directories
DirStub stub;
{
// root of own directories
convertEntryIndexToPointer<sizeof(void*)>(0, 0, p);
DirStub stub;
stub.type = DIR_TYPE_PERSON;
stub.name = mServCtrl->getOwnId().toStdString();
stub.ref = p;
@ -1092,9 +1100,11 @@ int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags
if(mExtraFiles->size() > 0)
{
convertEntryIndexToPointer<sizeof(void*)>(0,1,p); // local shared files from extra list
DirStub stub;
stub.type = DIR_TYPE_PERSON; // not totally exact, but used as a trick.
// local shared files from extra list
convertEntryIndexToPointer<sizeof(void*)>(0, 1, p);
DirStub stub;
// not totally exact, but used as a trick.
stub.type = DIR_TYPE_PERSON;
stub.name = "[Extra List]";
stub.ref = p;
@ -1127,18 +1137,19 @@ int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags
}
uint32_t fi;
DirectoryStorage::EntryIndex e ;
DirectoryStorage::EntryIndex e;
convertPointerToEntryIndex<sizeof(void*)>(ref,e,fi);
// check consistency
if( (fi == 0 && !(flags & RS_FILE_HINTS_LOCAL)) || (fi > 1 && (flags & RS_FILE_HINTS_LOCAL)))
{
P3FILELISTS_ERROR() << "(EE) remote request on local index or local request on remote index. This should not happen." << std::endl;
return false ;
}
// check consistency
if( (fi == 0 && !(flags & RS_FILE_HINTS_LOCAL)) ||
(fi > 1 && (flags & RS_FILE_HINTS_LOCAL)))
{
RS_ERR("Remote request on local index or local request on remote index");
return false;
}
if((flags & RS_FILE_HINTS_LOCAL) && fi == 1) // extra list
if((flags & RS_FILE_HINTS_LOCAL) && fi == 1) // extra list
{
getExtraFilesDirDetails(ref,e,d);
@ -1150,25 +1161,28 @@ int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags
}
DirectoryStorage *storage = (flags & RS_FILE_HINTS_LOCAL)? ((DirectoryStorage*)mLocalSharedDirs) : ((DirectoryStorage*)mRemoteDirectories[fi-1]);
DirectoryStorage* storage =
(flags & RS_FILE_HINTS_LOCAL) ?
((DirectoryStorage*) mLocalSharedDirs) :
((DirectoryStorage*) mRemoteDirectories[fi-1]);
// Case where the index is the top of a single person. Can be us, or a friend.
/* Case where the index is the top of a single person.
* Can be us, or a friend. */
if(!storage || !storage->extractData(e,d))
{
RS_WARN( "request on index; ", e, ", for directory ID:",
( (!storage)? ("[NULL]") : (storage->peerId().toStdString()) ),
" failed" );
return false;
}
if(storage==NULL || !storage->extractData(e,d))
{
#ifdef DEBUG_FILE_HIERARCHY
P3FILELISTS_DEBUG() << "(WW) request on index " << e << ", for directory ID=" << ((storage==NULL)?("[NULL]"):(storage->peerId().toStdString())) << " failed. This should not happen." << std::endl;
#endif
return false ;
}
/* update indexes. This is a bit hacky, but does the job. The cast to
* intptr_t is the proper way to convert a pointer into an int. */
convertEntryIndexToPointer<sizeof(void*)>((intptr_t)d.ref,fi,d.ref);
// update indexes. This is a bit hacky, but does the job. The cast to intptr_t is the proper way to convert
// a pointer into an int.
convertEntryIndexToPointer<sizeof(void*)>((intptr_t)d.ref,fi,d.ref) ;
for(uint32_t i=0;i<d.children.size();++i)
convertEntryIndexToPointer<sizeof(void*)>((intptr_t)d.children[i].ref,fi,d.children[i].ref);
for(uint32_t i=0; i<d.children.size(); ++i)
convertEntryIndexToPointer<sizeof(void*)>(
(intptr_t) d.children[i].ref, fi, d.children[i].ref );
if(e == 0) // root
{
@ -1178,9 +1192,9 @@ int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags
else
{
if(d.parent == 0) // child of root node
d.prow = (flags & RS_FILE_HINTS_LOCAL)?0:(fi-1);
d.prow = (flags & RS_FILE_HINTS_LOCAL) ? 0 : (fi-1);
else
d.prow = storage->parentRow(e) ;
d.prow = storage->parentRow(e);
convertEntryIndexToPointer<sizeof(void*)>((intptr_t)d.parent,fi,d.parent) ;
}
@ -1307,7 +1321,9 @@ uint32_t p3FileDatabase::watchPeriod()
return mLocalDirWatcher->fileWatchPeriod();
}
int p3FileDatabase::SearchKeywords(const std::list<std::string>& keywords, std::list<DirDetails>& results,FileSearchFlags flags,const RsPeerId& client_peer_id)
int p3FileDatabase::SearchKeywords(
const std::list<std::string>& keywords, std::list<DirDetails>& results,
FileSearchFlags flags, const RsPeerId& client_peer_id )
{
if(flags & RS_FILE_HINTS_LOCAL)
{
@ -1319,15 +1335,15 @@ int p3FileDatabase::SearchKeywords(const std::list<std::string>& keywords, std::
mLocalSharedDirs->searchTerms(keywords,firesults) ;
for(std::list<EntryIndex>::iterator it(firesults.begin());it!=firesults.end();++it)
{
void *p=NULL;
convertEntryIndexToPointer<sizeof(void*)>(*it,0,p);
pointers.push_back(p) ;
}
for(auto& it: std::as_const(firesults))
{
void *p = nullptr;
convertEntryIndexToPointer<sizeof(void*)>(it, 0, p);
pointers.push_back(p);
}
}
filterResults(pointers,results,flags,client_peer_id) ;
filterResults(pointers, results, flags, client_peer_id);
}
if(flags & RS_FILE_HINTS_REMOTE)
@ -1476,7 +1492,9 @@ bool p3FileDatabase::search(
return false;
}
int p3FileDatabase::filterResults(const std::list<void*>& firesults,std::list<DirDetails>& results,FileSearchFlags flags,const RsPeerId& peer_id) const
int p3FileDatabase::filterResults(
const std::list<void*>& firesults, std::list<DirDetails>& results,
FileSearchFlags flags, const RsPeerId& peer_id ) const
{
results.clear();
@ -1484,29 +1502,33 @@ int p3FileDatabase::filterResults(const std::list<void*>& firesults,std::list<Di
/* translate/filter results */
for(std::list<void*>::const_iterator rit(firesults.begin()); rit != firesults.end(); ++rit)
{
DirDetails cdetails ;
for(void* rit: std::as_const(firesults))
{
DirDetails cdetails;
if(!RequestDirDetails (*rit,cdetails,RS_FILE_HINTS_LOCAL))
{
P3FILELISTS_ERROR() << "(EE) Cannot get dir details for entry " << *rit << std::endl;
continue ;
}
if(!RequestDirDetails(rit, cdetails, RS_FILE_HINTS_LOCAL))
{
RS_ERR("Cannot retrieve dir details for entry: ", rit);
print_stacktrace();
continue ;
}
RS_DBG( "Filtering candidate: ", rit,
", name: ", cdetails.name, ", path: ", cdetails.path,
", flags: ", cdetails.flags, ", peer: ", peer_id );
if(!peer_id.isNull())
{
FileSearchFlags permission_flags =
rsPeers->computePeerPermissionFlags(
peer_id, cdetails.flags, cdetails.parent_groups );
if (cdetails.type == DIR_TYPE_FILE && ( permission_flags & flags ))
{
cdetails.id.clear();
results.push_back(cdetails);
#ifdef DEBUG_P3FILELISTS
P3FILELISTS_DEBUG() << "Filtering candidate " << *rit << ", flags=" << cdetails.flags << ", peer=" << peer_id ;
#endif
if(!peer_id.isNull())
{
FileSearchFlags permission_flags = rsPeers->computePeerPermissionFlags(peer_id,cdetails.flags,cdetails.parent_groups) ;
if (cdetails.type == DIR_TYPE_FILE && ( permission_flags & flags ))
{
cdetails.id.clear() ;
results.push_back(cdetails);
#ifdef DEBUG_P3FILELISTS
std::cerr << ": kept" << std::endl ;
std::cerr << ": kept" << std::endl ;
#endif
}
#ifdef DEBUG_P3FILELISTS
@ -1518,7 +1540,19 @@ int p3FileDatabase::filterResults(const std::list<void*>& firesults,std::list<Di
results.push_back(cdetails);
}
return !results.empty() ;
for(auto& res: results)
{
/* Most file will just have file name stored, but single file shared
* without a shared dir will contain full path instead of just the
* name, so purify it to perform the search */
if(res.name.find("/") != std::string::npos )
{
std::string _tDirPath;
RsDirUtil::splitDirFromFile(res.name, _tDirPath, res.name);
}
}
return !results.empty();
}
bool p3FileDatabase::convertSharedFilePath(const std::string& path,std::string& fullpath)
@ -1592,78 +1626,90 @@ void p3FileDatabase::tickSend()
void p3FileDatabase::handleDirSyncRequest(RsFileListsSyncRequestItem *item)
{
RsFileListsSyncResponseItem *ritem = new RsFileListsSyncResponseItem;
RsFileListsSyncResponseItem* ritem = new RsFileListsSyncResponseItem;
// look at item TS. If local is newer, send the full directory content.
{
RS_STACK_MUTEX(mFLSMtx) ;
// look at item TS. If local is newer, send the full directory content.
{
RS_STACK_MUTEX(mFLSMtx);
#ifdef DEBUG_P3FILELISTS
P3FILELISTS_DEBUG() << "Received directory sync request from peer " << item->PeerId() << ". hash=" << item->entry_hash << ", flags=" << (void*)(intptr_t)item->flags << ", request id: " << std::hex << item->request_id << std::dec << ", last known TS: " << item->last_known_recurs_modf_TS << std::endl;
#endif
RS_DBG( "Received directory sync request from peer ", item->PeerId(),
". hash=", item->entry_hash, ", flags=", item->flags,
", request id: ", item->request_id, ", last known TS: ",
item->last_known_recurs_modf_TS );
EntryIndex entry_index = DirectoryStorage::NO_INDEX;
EntryIndex entry_index = DirectoryStorage::NO_INDEX;
if(!mLocalSharedDirs->getIndexFromDirHash(item->entry_hash,entry_index))
{
RS_DBG("Cannot find entry index for hash ", item->entry_hash,
" cannot respond to sync request." );
return;
}
if(!mLocalSharedDirs->getIndexFromDirHash(item->entry_hash,entry_index))
{
#ifdef DEBUG_P3FILELISTS
P3FILELISTS_DEBUG() << " (EE) Cannot find entry index for hash " << item->entry_hash << ": cannot respond to sync request." << std::endl;
#endif
return;
}
uint32_t entry_type = mLocalSharedDirs->getEntryType(entry_index);
ritem->PeerId(item->PeerId());
ritem->request_id = item->request_id;
ritem->entry_hash = item->entry_hash;
uint32_t entry_type = mLocalSharedDirs->getEntryType(entry_index) ;
ritem->PeerId(item->PeerId()) ;
ritem->request_id = item->request_id;
ritem->entry_hash = item->entry_hash ;
std::list<RsNodeGroupId> node_groups;
FileStorageFlags node_flags;
std::list<RsNodeGroupId> node_groups;
FileStorageFlags node_flags;
if(entry_type != DIR_TYPE_DIR)
{
RS_DBG( "Directory does not exist anymore, or is not a directory, "
"or permission denied. Answering with proper flags." );
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE |
RsFileListsItem::FLAGS_ENTRY_WAS_REMOVED;
}
else if( entry_index != 0 &&
(!mLocalSharedDirs->getFileSharingPermissions(
entry_index, node_flags,node_groups ) ||
!(rsPeers->computePeerPermissionFlags(
item->PeerId(), node_flags, node_groups ) &
RS_FILE_HINTS_BROWSABLE)) )
{
RS_ERR("cannot get file permissions for entry index: ", entry_index,
", or permission denied." );
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE |
RsFileListsItem::FLAGS_ENTRY_WAS_REMOVED;
}
else
{
rstime_t local_recurs_max_time;
mLocalSharedDirs->getDirectoryRecursModTime(
entry_index, local_recurs_max_time );
if(entry_type != DIR_TYPE_DIR)
{
#ifdef DEBUG_P3FILELISTS
P3FILELISTS_DEBUG() << " Directory does not exist anymore, or is not a directory, or permission denied. Answering with proper flags." << std::endl;
#endif
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE | RsFileListsItem::FLAGS_ENTRY_WAS_REMOVED ;
}
else if(entry_index != 0 && (!mLocalSharedDirs->getFileSharingPermissions(entry_index,node_flags,node_groups) || !(rsPeers->computePeerPermissionFlags(item->PeerId(),node_flags,node_groups) & RS_FILE_HINTS_BROWSABLE)))
{
P3FILELISTS_ERROR() << "(EE) cannot get file permissions for entry index " << (void*)(intptr_t)entry_index << ", or permission denied." << std::endl;
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE | RsFileListsItem::FLAGS_ENTRY_WAS_REMOVED ;
}
else
{
rstime_t local_recurs_max_time ;
mLocalSharedDirs->getDirectoryRecursModTime(entry_index,local_recurs_max_time) ;
/* normally, should be "<", but since we provided the TS it should
* be equal, so != is more robust. */
if(item->last_known_recurs_modf_TS != local_recurs_max_time)
{
RS_DBG( "Directory is more recent than what the friend knows. "
"Sending full dir content as response.");
if(item->last_known_recurs_modf_TS != local_recurs_max_time) // normally, should be "<", but since we provided the TS it should be equal, so != is more robust.
{
#ifdef DEBUG_P3FILELISTS
P3FILELISTS_DEBUG() << " Directory is more recent than what the friend knows. Sending full dir content as response." << std::endl;
#endif
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE |
RsFileListsItem::FLAGS_SYNC_DIR_CONTENT;
ritem->last_known_recurs_modf_TS = local_recurs_max_time;
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE | RsFileListsItem::FLAGS_SYNC_DIR_CONTENT;
ritem->last_known_recurs_modf_TS = local_recurs_max_time;
/* We supply the peer id, in order to possibly remove some
* subdirs, if entries are not allowed to be seen by this peer.
*/
mLocalSharedDirs->serialiseDirEntry(
entry_index, ritem->directory_content_data,
item->PeerId() );
}
else
{
RS_DBG3( "Directory is up to date w.r.t. what the friend knows."
" Sending ACK." );
// We supply the peer id, in order to possibly remove some subdirs, if entries are not allowed to be seen by this peer.
mLocalSharedDirs->serialiseDirEntry(entry_index,ritem->directory_content_data,item->PeerId()) ;
}
else
{
#ifdef DEBUG_P3FILELISTS
P3FILELISTS_DEBUG() << " Directory is up to date w.r.t. what the friend knows. Sending ACK." << std::endl;
#endif
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE |
RsFileListsItem::FLAGS_ENTRY_UP_TO_DATE;
ritem->last_known_recurs_modf_TS = local_recurs_max_time;
}
}
}
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE | RsFileListsItem::FLAGS_ENTRY_UP_TO_DATE ;
ritem->last_known_recurs_modf_TS = local_recurs_max_time ;
}
}
}
// sends the response.
splitAndSendItem(ritem) ;
// sends the response.
splitAndSendItem(ritem);
}
void p3FileDatabase::splitAndSendItem(RsFileListsSyncResponseItem *ritem)

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2008 by Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2008 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2018-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020-2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -876,9 +878,11 @@ int ftServer::SearchKeywords(std::list<std::string> keywords, std::list<DirDetai
{
return mFileDatabase->SearchKeywords(keywords, results,flags,RsPeerId());
}
int ftServer::SearchKeywords(std::list<std::string> keywords, std::list<DirDetails> &results,FileSearchFlags flags,const RsPeerId& peer_id)
int ftServer::SearchKeywords(
std::list<std::string> keywords, std::list<DirDetails> &results,
FileSearchFlags flags, const RsPeerId& peer_id )
{
return mFileDatabase->SearchKeywords(keywords, results,flags,peer_id);
return mFileDatabase->SearchKeywords(keywords, results, flags, peer_id);
}
int ftServer::SearchBoolExp(RsRegularExpression::Expression * exp, std::list<DirDetails> &results,FileSearchFlags flags)

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2009-2018 by Cyril Soler <csoler@users.sourceforge.net> *
* Copyright (C) 2009-2018 Cyril Soler <csoler@users.sourceforge.net> *
* Copyright (C) 2018-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -26,6 +28,10 @@
#include <stdexcept>
#include <stdlib.h>
#include <assert.h>
#include <iostream>
#include <cerrno>
#include <cmath>
#include <cstdio>
#include "rsserver/p3face.h"
#include "crypto/rscrypto.h"
@ -39,13 +45,7 @@
#include "ft/ftcontroller.h"
#include "p3turtle.h"
#include <iostream>
#include <errno.h>
#include <cmath>
#include <stdio.h>
#include "util/cxx17retrocompat.h"
#include "util/rsdebug.h"
#include "util/rsprint.h"
#include "util/rsrandom.h"
@ -1975,7 +1975,8 @@ void p3turtle::handleTunnelResult(RsTurtleTunnelOkItem *item)
//
void RsTurtleStringSearchRequestItem::search(std::list<TurtleFileInfo>& result) const
void RsTurtleStringSearchRequestItem::search(
std::list<TurtleFileInfo>& result ) const
{
/* call to core */
std::list<DirDetails> initialResults;
@ -1988,17 +1989,19 @@ void RsTurtleStringSearchRequestItem::search(std::list<TurtleFileInfo>& result)
std::cerr << "Performing rsFiles->search()" << std::endl ;
#endif
// now, search!
rsFiles->SearchKeywords(words, initialResults,RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_SEARCHABLE,PeerId());
rsFiles->SearchKeywords(
words, initialResults,
RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_SEARCHABLE, PeerId() );
#ifdef P3TURTLE_DEBUG
std::cerr << initialResults.size() << " matches found." << std::endl ;
#endif
result.clear() ;
for(std::list<DirDetails>::const_iterator it(initialResults.begin());it!=initialResults.end();++it)
for(auto& it: std::as_const(initialResults))
{
// retain only file type
if (it->type == DIR_TYPE_DIR)
if (it.type == DIR_TYPE_DIR)
{
#ifdef P3TURTLE_DEBUG
std::cerr << " Skipping directory " << it->name << std::endl ;
@ -2006,12 +2009,12 @@ void RsTurtleStringSearchRequestItem::search(std::list<TurtleFileInfo>& result)
continue;
}
TurtleFileInfo i ;
i.hash = it->hash ;
i.size = it->size ;
i.name = it->name ;
TurtleFileInfo i;
i.hash = it.hash;
i.size = it.size;
i.name = it.name;
result.push_back(i) ;
result.push_back(i);
}
}
void RsTurtleRegExpSearchRequestItem::search(std::list<TurtleFileInfo>& result) const

View File

@ -38,8 +38,11 @@
namespace librs { namespace util {
FolderIterator::FolderIterator(const std::string& folderName, bool allow_symlinks, bool allow_files_from_the_future)
: mFolderName(folderName),mAllowSymLinks(allow_symlinks),mAllowFilesFromTheFuture(allow_files_from_the_future)
FolderIterator::FolderIterator(
const std::string& folderName, bool allow_symlinks,
bool allow_files_from_the_future ):
mFolderName(folderName), mAllowSymLinks(allow_symlinks),
mAllowFilesFromTheFuture(allow_files_from_the_future)
{
is_open = false ;
validity = false ;

View File

@ -44,8 +44,10 @@ namespace librs { namespace util {
class FolderIterator
{
public:
FolderIterator(const std::string& folderName,bool allow_symlinks,bool allow_files_from_the_future = true);
~FolderIterator();
FolderIterator(
const std::string& folderName, bool allow_symlinks,
bool allow_files_from_the_future = true );
~FolderIterator();
enum { TYPE_UNKNOWN = 0x00,
TYPE_FILE = 0x01,

View File

@ -458,6 +458,36 @@ bool RsDirUtil::checkFile(const std::string& filename,uint64_t& file_size,bool d
return true;
}
rstime_t RsDirUtil::lastWriteTime(
const std::string& path,
std::error_condition& errc )
{
if(!fileExists(path))
{
errc = std::errc::no_such_file_or_directory;
return 0;
}
#ifdef WINDOWS_SYS
struct _stati64 buf;
std::wstring wPath;
librs::util::ConvertUtf8ToUtf16(path, wPath);
if ( 0 == _wstati64(wPath.c_str(), &buf))
#else
struct stat64 buf;
if ( 0 == stat64(path.c_str(), &buf))
#endif
{
/* errc output param is guaranted to be meaningful only if an error
* happens so is not strictly necessary but we clean it anyway just
* in case */
errc = std::error_condition();
return buf.st_mtime;
}
errc = std::error_condition(errno, std::generic_category());
return 0;
}
bool RsDirUtil::checkDirectory(const std::string& dir)
{

View File

@ -4,8 +4,8 @@
* libretroshare: retroshare core library *
* *
* Copyright (C) 2004-2007 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* Copyright (C) 2020-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020-2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -27,11 +27,13 @@
#include <string>
#include <list>
#include <set>
#include <stdint.h>
#include <cstdint>
#include <system_error>
class RsThread;
#include <retroshare/rstypes.h>
#include "retroshare/rstypes.h"
#include "util/rsmemory.h"
#ifndef WINDOWS_SYS
typedef int rs_lock_handle_t;
@ -79,10 +81,11 @@ const char *scanf_string_for_uint(int bytes) ;
int breakupDirList(const std::string& path, std::list<std::string> &subdirs);
// Splits the path into parent directory and file. File can be empty if full_path is a dir ending with '/'
// if full_path does not contain a directory, then dir will be "." and file will be full_path.
bool splitDirFromFile(const std::string& full_path,std::string& dir, std::string& file);
/** Splits the path into parent directory and file. File can be empty if
* full_path is a dir ending with '/' if full_path does not contain a directory,
* then dir will be "." and file will be full_path */
bool splitDirFromFile( const std::string& full_path,
std::string& dir, std::string& file );
bool copyFile(const std::string& source,const std::string& dest);
@ -92,6 +95,17 @@ bool moveFile(const std::string& source, const std::string& dest);
bool removeFile(const std::string& file);
bool fileExists(const std::string& file);
bool checkFile(const std::string& filename,uint64_t& file_size,bool disallow_empty_file = false);
/**
* @brief Retrieve file last modification time
* @param path path of the file
* @param errc optional storage for error details
* @return 0 on error, file modification time represented as unix epoch otherwise.
*/
rstime_t lastWriteTime(
const std::string& path,
std::error_condition& errc = RS_DEFAULT_STORAGE_PARAM(std::error_condition) );
bool checkDirectory(const std::string& dir);
bool checkCreateDirectory(const std::string& dir);

View File

@ -3,7 +3,8 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2013-2013 by Cyril Soler <csoler@users.sourceforge.net> *
* Copyright 2013 Cyril Soler <csoler@users.sourceforge.net> *
* Copyright 2018 Gioacchino Mazzurco <gio@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *