mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
Merge pull request #2444 from G10h4ck/single_file_share_plus_cleanup
Single file share plus cleanup
This commit is contained in:
commit
58016fff65
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 ;
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 *
|
||||
|
Loading…
Reference in New Issue
Block a user