mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-02-26 01:31:30 -05: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 *
|
* 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 *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Lesser General Public License as *
|
* it under the terms of the GNU Lesser General Public License as *
|
||||||
@ -29,6 +31,7 @@
|
|||||||
#include "dir_hierarchy.h"
|
#include "dir_hierarchy.h"
|
||||||
#include "filelist_io.h"
|
#include "filelist_io.h"
|
||||||
#include "file_sharing_defaults.h"
|
#include "file_sharing_defaults.h"
|
||||||
|
#include "util/cxx17retrocompat.h"
|
||||||
|
|
||||||
#ifdef RS_DEEP_FILES_INDEX
|
#ifdef RS_DEEP_FILES_INDEX
|
||||||
# include "deep_search/filesindex.hpp"
|
# include "deep_search/filesindex.hpp"
|
||||||
@ -70,7 +73,8 @@ InternalFileHierarchyStorage::InternalFileHierarchyStorage() : mRoot(0)
|
|||||||
mTotalFiles = 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))
|
if(!checkIndex(index,FileStorageNode::TYPE_DIR))
|
||||||
return false ;
|
return false ;
|
||||||
@ -79,6 +83,7 @@ bool InternalFileHierarchyStorage::getDirHashFromIndex(const DirectoryStorage::E
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InternalFileHierarchyStorage::getIndexFromDirHash(const RsFileHash& hash,DirectoryStorage::EntryIndex& index)
|
bool InternalFileHierarchyStorage::getIndexFromDirHash(const RsFileHash& hash,DirectoryStorage::EntryIndex& index)
|
||||||
{
|
{
|
||||||
std::map<RsFileHash,DirectoryStorage::EntryIndex>::iterator it = mDirHashes.find(hash) ;
|
std::map<RsFileHash,DirectoryStorage::EntryIndex>::iterator it = mDirHashes.find(hash) ;
|
||||||
@ -88,30 +93,34 @@ bool InternalFileHierarchyStorage::getIndexFromDirHash(const RsFileHash& hash,Di
|
|||||||
|
|
||||||
index = it->second;
|
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.
|
/* make sure the hash actually points to some existing directory. If not,
|
||||||
if(!checkIndex(index, FileStorageNode::TYPE_DIR) || static_cast<DirEntry*>(mNodes[index])->dir_hash != hash)
|
* 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 )
|
||||||
{
|
{
|
||||||
std::cerr << "(II) removing non existing hash from dir hash list: " << hash << std::endl;
|
RS_INFO("removing non existing dir hash: ", hash, " from dir hash list");
|
||||||
|
|
||||||
mDirHashes.erase(it);
|
mDirHashes.erase(it);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool InternalFileHierarchyStorage::getIndexFromFileHash(const RsFileHash& hash,DirectoryStorage::EntryIndex& index)
|
|
||||||
{
|
|
||||||
std::map<RsFileHash,DirectoryStorage::EntryIndex>::iterator it = mFileHashes.find(hash) ;
|
|
||||||
|
|
||||||
if(it == mFileHashes.end())
|
bool InternalFileHierarchyStorage::getIndexFromFileHash(
|
||||||
return false;
|
const RsFileHash& hash, DirectoryStorage::EntryIndex& index )
|
||||||
|
{
|
||||||
|
auto it = std::as_const(mFileHashes).find(hash);
|
||||||
|
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 a lazy update of file hashes: when we need them, we check them.
|
/* make sure the hash actually points to some existing file. If not, remove
|
||||||
if(!checkIndex(it->second, FileStorageNode::TYPE_FILE) || static_cast<FileEntry*>(mNodes[index])->file_hash != hash)
|
* 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 )
|
||||||
{
|
{
|
||||||
std::cerr << "(II) removing non existing hash from file hash list: " << hash << std::endl;
|
RS_INFO("removing non existing file hash: ", hash, " from file hash list");
|
||||||
|
|
||||||
mFileHashes.erase(it);
|
mFileHashes.erase(it);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -155,7 +164,10 @@ bool InternalFileHierarchyStorage::isIndexValid(DirectoryStorage::EntryIndex e)
|
|||||||
return e < mNodes.size() && mNodes[e] != NULL ;
|
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))
|
if(!checkIndex(indx,FileStorageNode::TYPE_DIR))
|
||||||
return false;
|
return false;
|
||||||
@ -284,10 +296,17 @@ bool InternalFileHierarchyStorage::checkIndex(DirectoryStorage::EntryIndex indx,
|
|||||||
return true;
|
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))
|
if(!checkIndex(indx, FileStorageNode::TYPE_DIR))
|
||||||
|
{
|
||||||
|
RS_ERR("indx: ", indx, std::errc::not_a_directory);
|
||||||
|
print_stacktrace();
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DirEntry& d(*static_cast<DirEntry*>(mNodes[indx])) ;
|
DirEntry& d(*static_cast<DirEntry*>(mNodes[indx])) ;
|
||||||
new_files = subfiles ;
|
new_files = subfiles ;
|
||||||
@ -312,9 +331,11 @@ bool InternalFileHierarchyStorage::updateSubFilesList(const DirectoryStorage::En
|
|||||||
continue;
|
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_modtime = it->second.modtime;
|
||||||
f.file_size = it->second.size;
|
f.file_size = it->second.size;
|
||||||
|
|
||||||
@ -342,11 +363,14 @@ bool InternalFileHierarchyStorage::updateSubFilesList(const DirectoryStorage::En
|
|||||||
}
|
}
|
||||||
return true;
|
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))
|
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;
|
RS_ERR( "Cannot update file at index ", file_index,
|
||||||
|
". Not a valid index, or not a file." );
|
||||||
|
print_stacktrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_DIRECTORY_STORAGE
|
#ifdef DEBUG_DIRECTORY_STORAGE
|
||||||
@ -436,13 +460,19 @@ DirectoryStorage::EntryIndex InternalFileHierarchyStorage::allocateNewIndex()
|
|||||||
return mNodes.size()-1 ;
|
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))
|
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;
|
RS_ERR( "cannot update dir at index ", indx, ". Not a valid index, or "
|
||||||
|
"not an existing dir." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirEntry& d(*static_cast<DirEntry*>(mNodes[indx]));
|
DirEntry& d(*static_cast<DirEntry*>(mNodes[indx]));
|
||||||
|
|
||||||
#ifdef DEBUG_DIRECTORY_STORAGE
|
#ifdef DEBUG_DIRECTORY_STORAGE
|
||||||
@ -703,14 +733,14 @@ const InternalFileHierarchyStorage::FileStorageNode *InternalFileHierarchyStorag
|
|||||||
return NULL ;
|
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))
|
if(!checkIndex(indx,FileStorageNode::TYPE_DIR)) return nullptr;
|
||||||
return NULL ;
|
|
||||||
|
|
||||||
return static_cast<DirEntry*>(mNodes[indx]);
|
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))
|
if(!checkIndex(indx,FileStorageNode::TYPE_FILE))
|
||||||
return NULL ;
|
return NULL ;
|
||||||
@ -754,7 +784,10 @@ bool InternalFileHierarchyStorage::searchHash(const RsFileHash& hash,DirectorySt
|
|||||||
class DirectoryStorageExprFileEntry: public RsRegularExpression::ExpFileEntry
|
class DirectoryStorageExprFileEntry: public RsRegularExpression::ExpFileEntry
|
||||||
{
|
{
|
||||||
public:
|
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 const std::string& file_name() const { return mFe.file_name ; }
|
||||||
inline virtual uint64_t file_size() const { return mFe.file_size ; }
|
inline virtual uint64_t file_size() const { return mFe.file_size ; }
|
||||||
@ -768,14 +801,18 @@ private:
|
|||||||
const InternalFileHierarchyStorage::DirEntry& mDe ;
|
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)
|
for(auto& it: std::as_const(mFileHashes))
|
||||||
if(mNodes[it->second] != NULL && exp->eval(
|
if(mNodes[it.second])
|
||||||
DirectoryStorageExprFileEntry(*static_cast<const FileEntry*>(mNodes[it->second]),
|
if(exp->eval(
|
||||||
*static_cast<const DirEntry*>(mNodes[mNodes[it->second]->parent_index])
|
DirectoryStorageExprFileEntry(
|
||||||
|
*static_cast<const FileEntry*>(mNodes[it.second]),
|
||||||
|
*static_cast<const DirEntry*>(mNodes[mNodes[it.second]->parent_index])
|
||||||
) ))
|
) ))
|
||||||
results.push_back(it->second);
|
results.push_back(it.second);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -784,26 +821,42 @@ int InternalFileHierarchyStorage::searchTerms(
|
|||||||
const std::list<std::string>& terms,
|
const std::list<std::string>& terms,
|
||||||
std::list<DirectoryStorage::EntryIndex>& results ) const
|
std::list<DirectoryStorage::EntryIndex>& results ) const
|
||||||
{
|
{
|
||||||
// most entries are likely to be files, so we could do a linear search over the entries tab.
|
/* most entries are likely to be files, so we could do a linear search over
|
||||||
// instead we go through the table of hashes.
|
* 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)
|
for(auto& it : std::as_const(mFileHashes))
|
||||||
if(mNodes[it->second] != NULL)
|
|
||||||
{
|
{
|
||||||
const std::string &str1 = static_cast<FileEntry*>(mNodes[it->second])->file_name;
|
// 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)
|
/* 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& termIt : std::as_const(terms))
|
||||||
{
|
{
|
||||||
/* always ignore case */
|
/* always ignore case */
|
||||||
const std::string &str2 = (*iter);
|
if(tFilename.end() != std::search(
|
||||||
|
tFilename.begin(), tFilename.end(),
|
||||||
if(str1.end() != std::search( str1.begin(), str1.end(), str2.begin(), str2.end(), RsRegularExpression::CompareCharIC() ))
|
termIt.begin(), termIt.end(),
|
||||||
|
RsRegularExpression::CompareCharIC() ))
|
||||||
{
|
{
|
||||||
results.push_back(it->second);
|
results.push_back(it.second);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -958,7 +1011,8 @@ void InternalFileHierarchyStorage::recursPrint(int depth,DirectoryStorage::Entry
|
|||||||
|
|
||||||
bool InternalFileHierarchyStorage::nodeAccessError(const std::string& s)
|
bool InternalFileHierarchyStorage::nodeAccessError(const std::string& s)
|
||||||
{
|
{
|
||||||
std::cerr << "(EE) InternalDirectoryStructure: ERROR: " << s << std::endl;
|
RS_ERR(s);
|
||||||
|
print_stacktrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
* *
|
* *
|
||||||
* libretroshare: retroshare core library *
|
* 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 *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Lesser General Public License as *
|
* it under the terms of the GNU Lesser General Public License as *
|
||||||
@ -30,6 +32,7 @@
|
|||||||
#include "directory_storage.h"
|
#include "directory_storage.h"
|
||||||
#include "dir_hierarchy.h"
|
#include "dir_hierarchy.h"
|
||||||
#include "filelist_io.h"
|
#include "filelist_io.h"
|
||||||
|
#include "util/cxx17retrocompat.h"
|
||||||
|
|
||||||
#ifdef RS_DEEP_FILES_INDEX
|
#ifdef RS_DEEP_FILES_INDEX
|
||||||
# include "deep_search/filesindex.hpp"
|
# include "deep_search/filesindex.hpp"
|
||||||
@ -67,8 +70,11 @@ DirectoryStorage::FileIterator& DirectoryStorage::FileIterator::operator++()
|
|||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
DirectoryStorage::EntryIndex DirectoryStorage::FileIterator::operator*() const { return mStorage->getSubFileIndex(mParentIndex,mFileTabIndex) ; }
|
DirectoryStorage::EntryIndex DirectoryStorage::FileIterator::operator*() const
|
||||||
DirectoryStorage::EntryIndex DirectoryStorage::DirIterator ::operator*() const { return mStorage->getSubDirIndex(mParentIndex,mDirTabIndex) ; }
|
{ 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::FileIterator::operator bool() const { return **this != DirectoryStorage::NO_INDEX; }
|
||||||
DirectoryStorage::DirIterator ::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 ;
|
mChanged = true ;
|
||||||
return res ;
|
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) ;
|
RS_STACK_MUTEX(mDirStorageMtx) ;
|
||||||
bool res = mFileHierarchy->updateSubFilesList(indx,subfiles,new_files) ;
|
bool res = mFileHierarchy->updateSubFilesList(indx,subfiles,new_files) ;
|
||||||
@ -348,7 +356,8 @@ int LocalDirectoryStorage::searchHash(const RsFileHash& hash, RsFileHash& real_h
|
|||||||
return false ;
|
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 ;
|
std::set<std::string> dirs_with_new_virtualname ;
|
||||||
bool dirs_with_changed_flags = false ;
|
bool dirs_with_changed_flags = false ;
|
||||||
@ -379,7 +388,9 @@ void LocalDirectoryStorage::setSharedDirectoryList(const std::list<SharedDirInfo
|
|||||||
virtual_names.insert(candidate_virtual_name) ;
|
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 ;
|
std::map<std::string,SharedDirInfo> new_dirs ;
|
||||||
|
|
||||||
@ -617,46 +628,76 @@ bool LocalDirectoryStorage::getFileSharingPermissions(const EntryIndex& indx,Fil
|
|||||||
return locked_getFileSharingPermissions(indx,flags,parent_groups) ;
|
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();
|
flags.clear();
|
||||||
parent_groups.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)
|
rs_view_ptr<const FileStorageNode> n = mFileHierarchy->getNode(indx);
|
||||||
|
if(!n)
|
||||||
|
{
|
||||||
|
RS_ERR("Node for index: ", indx, "not found");
|
||||||
|
print_stacktrace();
|
||||||
return false;
|
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) ;
|
|
||||||
|
|
||||||
if(e == NULL)
|
|
||||||
break ;
|
|
||||||
|
|
||||||
if(e->parent_index == 0)
|
|
||||||
{
|
|
||||||
base_dir = e->dir_name ;
|
|
||||||
break ;
|
|
||||||
}
|
|
||||||
i = e->parent_index ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!base_dir.empty())
|
// Climb down node tree up to root + 1
|
||||||
|
EntryIndex curIndex = indx;
|
||||||
|
while (n->parent_index)
|
||||||
{
|
{
|
||||||
std::map<std::string,SharedDirInfo>::const_iterator it = mLocalDirs.find(base_dir) ;
|
curIndex = n->parent_index;
|
||||||
|
n = mFileHierarchy->getNode(curIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use base name to retrieve sharing permissions
|
||||||
|
if(!tBaseName.empty())
|
||||||
|
{
|
||||||
|
auto it = std::as_const(mLocalDirs).find(tBaseName);
|
||||||
|
|
||||||
if(it == mLocalDirs.end())
|
if(it == mLocalDirs.end())
|
||||||
{
|
{
|
||||||
std::cerr << "(II) base directory \"" << base_dir << "\" not found in shared dir list." << std::endl;
|
RS_ERR( "base name \"", tBaseName,
|
||||||
|
"\" for index: ", indx, " not found in shared dir list." );
|
||||||
|
print_stacktrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = it->second.shareflags;
|
flags = it->second.shareflags;
|
||||||
parent_groups = it->second.parent_groups;
|
parent_groups = it->second.parent_groups;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RS_ERR("base name for indx: ", indx, " is empty");
|
||||||
|
print_stacktrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -705,18 +746,22 @@ std::string LocalDirectoryStorage::locked_getVirtualPath(EntryIndex indx) const
|
|||||||
return it->second.virtualname + "/" + res;
|
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
|
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
|
||||||
std::cerr << "Serialising Dir entry " << std::hex << indx << " for client id " << client_id << std::endl;
|
std::cerr << "Serialising Dir entry " << std::hex << indx << " for client id " << client_id << std::endl;
|
||||||
#endif
|
#endif
|
||||||
if(dir == NULL)
|
|
||||||
|
if(!dir)
|
||||||
{
|
{
|
||||||
std::cerr << "(EE) serialiseDirEntry: ERROR. Cannot find entry " << (void*)(intptr_t)indx << std::endl;
|
RS_ERR("Cannot find entry ", indx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,18 +770,28 @@ bool LocalDirectoryStorage::serialiseDirEntry(const EntryIndex& indx,RsTlvBinary
|
|||||||
FileStorageFlags node_flags;
|
FileStorageFlags node_flags;
|
||||||
std::list<RsNodeGroupId> node_groups;
|
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 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)
|
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)))
|
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;
|
RsFileHash hash;
|
||||||
if(!mFileHierarchy->getDirHashFromIndex(dir->subdirs[i],hash))
|
if(!mFileHierarchy->getDirHashFromIndex(dir->subdirs[i],hash))
|
||||||
{
|
{
|
||||||
std::cerr << "(EE) Cannot get hash from subdir index " << dir->subdirs[i] << ". Weird bug." << std::endl ;
|
RS_ERR( "Cannot get hash from subdir index: ",
|
||||||
|
dir->subdirs[i], ". Weird bug." );
|
||||||
|
print_stacktrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
allowed_subdirs.push_back(hash);
|
allowed_subdirs.push_back(hash);
|
||||||
|
|
||||||
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
|
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
|
||||||
std::cerr << " pushing subdir " << hash << ", array position=" << i << " indx=" << dir->subdirs[i] << std::endl;
|
std::cerr << " pushing subdir " << hash << ", array position=" << i << " indx=" << dir->subdirs[i] << std::endl;
|
||||||
#endif
|
#endif
|
||||||
@ -746,50 +801,77 @@ bool LocalDirectoryStorage::serialiseDirEntry(const EntryIndex& indx,RsTlvBinary
|
|||||||
std::cerr << " not pushing subdir " << hash << ", array position=" << i << " indx=" << dir->subdirs[i] << ": permission denied for this peer." << std::endl;
|
std::cerr << " not pushing subdir " << hash << ", array position=" << i << " indx=" << dir->subdirs[i] << ": permission denied for this peer." << std::endl;
|
||||||
#endif
|
#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;
|
uint32_t allowed_subfiles = 0;
|
||||||
|
|
||||||
for(uint32_t i=0; i<dir->subfiles.size(); ++i)
|
for(uint32_t i=0; i<dir->subfiles.size(); ++i)
|
||||||
{
|
{
|
||||||
const InternalFileHierarchyStorage::FileEntry *file = mFileHierarchy->getFileEntry(dir->subfiles[i]) ;
|
const InternalFileHierarchyStorage::FileEntry* file =
|
||||||
if(file != NULL && !file->file_hash.isNull())
|
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++;
|
allowed_subfiles++;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *section_data = (unsigned char *)rs_malloc(FL_BASE_TMP_SECTION_SIZE) ;
|
unsigned char* section_data = (unsigned char *)
|
||||||
|
rs_malloc(FL_BASE_TMP_SECTION_SIZE);
|
||||||
if(!section_data)
|
if(!section_data) return false;
|
||||||
return false ;
|
|
||||||
|
|
||||||
uint32_t section_size = FL_BASE_TMP_SECTION_SIZE;
|
uint32_t section_size = FL_BASE_TMP_SECTION_SIZE;
|
||||||
uint32_t section_offset = 0;
|
uint32_t section_offset = 0;
|
||||||
|
|
||||||
// we need to send:
|
/* we need to send:
|
||||||
// - the name of the directory, its TS
|
* - the name of the directory, its TS
|
||||||
// - the index entry for each subdir (the updte TS are exchanged at a higher level)
|
* - the index entry for each subdir (the updte TS are exchanged at a
|
||||||
// - the file info for each subfile
|
* higher level)
|
||||||
//
|
* - the file info for each subfile */
|
||||||
|
|
||||||
std::string virtual_dir_name = locked_getVirtualDirName(indx);
|
std::string virtual_dir_name = locked_getVirtualDirName(indx);
|
||||||
|
|
||||||
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_DIR_NAME ,virtual_dir_name )) { free(section_data); return false ;}
|
/* Manual serialization AGAIN! This is terrible and should be ported to the
|
||||||
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 ;}
|
* new serialization system ASAP! */
|
||||||
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 ;}
|
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 number of subdirs and number of subfiles
|
// serialise number of subdirs and number of subfiles
|
||||||
|
if(!FileListIO::writeField(
|
||||||
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 ;}
|
section_data, section_size, section_offset,
|
||||||
if(!FileListIO::writeField(section_data,section_size,section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t)allowed_subfiles )) { free(section_data); return false ;}
|
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; }
|
||||||
|
|
||||||
// serialise subdirs entry indexes
|
// serialise subdirs entry indexes
|
||||||
|
|
||||||
for(uint32_t i=0; i<allowed_subdirs.size(); ++i)
|
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 ;}
|
if(!FileListIO::writeField(
|
||||||
|
section_data, section_size, section_offset,
|
||||||
|
FILE_LIST_IO_TAG_ENTRY_INDEX, allowed_subdirs[i] ))
|
||||||
|
{ free(section_data); return false; }
|
||||||
|
|
||||||
// serialise directory subfiles, with info for each of them
|
// serialise directory subfiles, with info for each of them
|
||||||
|
|
||||||
unsigned char *file_section_data = (unsigned char *)rs_malloc(FL_BASE_TMP_SECTION_SIZE) ;
|
unsigned char* file_section_data =
|
||||||
|
(unsigned char *) rs_malloc(FL_BASE_TMP_SECTION_SIZE);
|
||||||
if(!file_section_data)
|
if(!file_section_data)
|
||||||
{
|
{
|
||||||
free(section_data);
|
free(section_data);
|
||||||
@ -802,22 +884,60 @@ bool LocalDirectoryStorage::serialiseDirEntry(const EntryIndex& indx,RsTlvBinary
|
|||||||
{
|
{
|
||||||
uint32_t file_section_offset = 0;
|
uint32_t file_section_offset = 0;
|
||||||
|
|
||||||
const InternalFileHierarchyStorage::FileEntry *file = mFileHierarchy->getFileEntry(dir->subfiles[i]) ;
|
const InternalFileHierarchyStorage::FileEntry* file =
|
||||||
|
mFileHierarchy->getFileEntry(dir->subfiles[i]);
|
||||||
|
|
||||||
if(file == NULL || file->file_hash.isNull())
|
if(file == nullptr || file->file_hash.isNull())
|
||||||
{
|
{
|
||||||
std::cerr << "(II) skipping unhashed or Null file entry " << dir->subfiles[i] << " to get/send file info." << std::endl;
|
RS_INFO( "skipping unhashed or Null file entry ",
|
||||||
|
dir->subfiles[i], " to get/send file info." );
|
||||||
continue;
|
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(indx == 0)
|
||||||
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(!locked_getFileSharingPermissions(
|
||||||
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 ;}
|
dir->subfiles[i], node_flags, node_groups ))
|
||||||
|
{
|
||||||
|
RS_ERR( "Failure getting sharing permission for single file: ",
|
||||||
|
dir->subfiles[i] );
|
||||||
|
print_stacktrace();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!( rsPeers->computePeerPermissionFlags(
|
||||||
|
client_id, node_flags, node_groups ) &
|
||||||
|
RS_FILE_HINTS_BROWSABLE ))
|
||||||
|
{
|
||||||
|
RS_INFO( "Skipping single file shared without browse "
|
||||||
|
"permission" );
|
||||||
|
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
|
// now write the whole string into a single section in the file
|
||||||
|
if(!FileListIO::writeField(
|
||||||
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 ;}
|
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
|
#ifdef DEBUG_LOCAL_DIRECTORY_STORAGE
|
||||||
std::cerr << " pushing subfile " << file->hash << ", array position=" << i << " indx=" << dir->subfiles[i] << std::endl;
|
std::cerr << " pushing subfile " << file->hash << ", array position=" << i << " indx=" << dir->subfiles[i] << std::endl;
|
||||||
@ -829,7 +949,8 @@ bool LocalDirectoryStorage::serialiseDirEntry(const EntryIndex& indx,RsTlvBinary
|
|||||||
std::cerr << "Serialised dir entry to send for entry index " << (void*)(intptr_t)indx << ". Data size is " << section_size << " bytes" << std::endl;
|
std::cerr << "Serialised dir entry to send for entry index " << (void*)(intptr_t)indx << ". Data size is " << section_size << " bytes" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bindata.bin_data = realloc(section_data,section_offset) ; // This discards the possibly unused trailing bytes in the end of section_data
|
// 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;
|
bindata.bin_len = section_offset;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
* *
|
* *
|
||||||
* libretroshare: retroshare core library *
|
* 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 *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Lesser General Public License as *
|
* 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/>. *
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||||
* *
|
* *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "util/cxx17retrocompat.h"
|
||||||
#include "util/folderiterator.h"
|
#include "util/folderiterator.h"
|
||||||
#include "util/rstime.h"
|
#include "util/rstime.h"
|
||||||
#include "rsserver/p3face.h"
|
#include "rsserver/p3face.h"
|
||||||
|
|
||||||
#include "directory_storage.h"
|
#include "directory_storage.h"
|
||||||
#include "directory_updater.h"
|
#include "directory_updater.h"
|
||||||
#include "file_sharing_defaults.h"
|
#include "file_sharing_defaults.h"
|
||||||
|
#include "util/rsdebuglevel3.h"
|
||||||
|
|
||||||
//#define DEBUG_LOCAL_DIR_UPDATER 1
|
//#define DEBUG_LOCAL_DIR_UPDATER 1
|
||||||
|
|
||||||
@ -123,51 +127,99 @@ bool LocalDirectoryUpdater::sweepSharedDirectories(bool& some_files_not_ready)
|
|||||||
{
|
{
|
||||||
if(mHashSalt.isNull())
|
if(mHashSalt.isNull())
|
||||||
{
|
{
|
||||||
std::cerr << "(EE) no salt value in LocalDirectoryUpdater. Is that a bug?" << std::endl;
|
RS_ERR("no salt value in LocalDirectoryUpdater");
|
||||||
|
print_stacktrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mIsChecking = true;
|
mIsChecking = true;
|
||||||
|
|
||||||
RsServer::notify()->notifyListPreChange(NOTIFY_LIST_DIRLIST_LOCAL, 0);
|
RsServer::notify()->notifyListPreChange(NOTIFY_LIST_DIRLIST_LOCAL, 0);
|
||||||
#ifdef DEBUG_LOCAL_DIR_UPDATER
|
|
||||||
std::cerr << "[directory storage] LocalDirectoryUpdater::sweep()" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// recursive update algorithm works that way:
|
/* recursive update algorithm works that way:
|
||||||
// - the external loop starts on the shared directory list and goes through sub-directories
|
* - the external loop starts on the shared directory list and goes through
|
||||||
// - at the same time, it updates the local list of shared directories. A single sweep is performed over the whole directory structure.
|
* sub-directories
|
||||||
// - the information that is costly to compute (the hash) is store externally into a separate structure.
|
* - at the same time, it updates the local list of shared directories.
|
||||||
// - doing so, changing directory names or moving files between directories does not cause a re-hash of the content.
|
* 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;
|
std::list<SharedDirInfo> shared_directory_list;
|
||||||
mSharedDirectories->getSharedDirectoryList(shared_directory_list);
|
mSharedDirectories->getSharedDirectoryList(shared_directory_list);
|
||||||
|
|
||||||
std::set<std::string> sub_dir_list;
|
std::set<std::string> sub_dir_list;
|
||||||
|
|
||||||
// We re-check that each dir actually exists. It might have been removed from the disk.
|
/* Support also single files sharing as it make much more sense on some
|
||||||
|
* platforms like Android */
|
||||||
|
std::map<std::string, DirectoryStorage::FileTS> singleFilesMap;
|
||||||
|
|
||||||
for(std::list<SharedDirInfo>::const_iterator real_dir_it(shared_directory_list.begin());real_dir_it!=shared_directory_list.end();++real_dir_it)
|
/* We re-check that each dir actually exists. It might have been removed
|
||||||
if(RsDirUtil::checkDirectory( (*real_dir_it).filename ) )
|
* from the disk. Accept also single files not just directories. */
|
||||||
sub_dir_list.insert( (*real_dir_it).filename ) ;
|
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);
|
||||||
|
|
||||||
// make sure that entries in stored_dir_it are the same than paths in real_dir_it, and in the same order.
|
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." );
|
||||||
|
}
|
||||||
|
|
||||||
mSharedDirectories->updateSubDirectoryList(mSharedDirectories->root(),sub_dir_list,mHashSalt) ;
|
{
|
||||||
|
const auto tRoot = mSharedDirectories->root();
|
||||||
|
std::map<std::string, DirectoryStorage::FileTS> needsUpdate;
|
||||||
|
mSharedDirectories->updateSubFilesList(
|
||||||
|
tRoot, singleFilesMap, needsUpdate);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 );
|
||||||
|
|
||||||
// now for each of them, go recursively and match both files and dirs
|
// now for each of them, go recursively and match both files and dirs
|
||||||
|
|
||||||
std::set<std::string> existing_dirs;
|
std::set<std::string> existing_dirs;
|
||||||
|
for( DirectoryStorage::DirIterator stored_dir_it(
|
||||||
for(DirectoryStorage::DirIterator stored_dir_it(mSharedDirectories,mSharedDirectories->root()) ; stored_dir_it;++stored_dir_it)
|
mSharedDirectories, mSharedDirectories->root() );
|
||||||
|
stored_dir_it; ++stored_dir_it )
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_LOCAL_DIR_UPDATER
|
RS_DBG4("recursing into \"", stored_dir_it.name());
|
||||||
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
|
existing_dirs.insert(RsDirUtil::removeSymLinks(stored_dir_it.name()));
|
||||||
// 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);
|
RsServer::notify()->notifyListChange(NOTIFY_LIST_DIRLIST_LOCAL, 0);
|
||||||
@ -176,130 +228,135 @@ bool LocalDirectoryUpdater::sweepSharedDirectories(bool& some_files_not_ready)
|
|||||||
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
|
RS_DBG4("parsing directory \"", cumulated_path, "\" index: ", indx);
|
||||||
std::cerr << "[directory storage] parsing directory " << cumulated_path << ", index=" << indx << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// make sure list of subdirs is the same
|
/* make sure list of subdirs is the same
|
||||||
// make sure list of subfiles is the same
|
* make sure list of subfiles is the same
|
||||||
// request all hashes to the hashcache
|
* request all hashes to the hashcache */
|
||||||
|
|
||||||
librs::util::FolderIterator dirIt(cumulated_path,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;
|
rstime_t dir_local_mod_time;
|
||||||
if(!mSharedDirectories->getDirectoryLocalModTime(indx,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;
|
RS_ERR("Cannot get local mod time for dir index: ", indx);
|
||||||
|
print_stacktrace();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rstime_t now = time(NULL) ;
|
rstime_t now = time(nullptr);
|
||||||
|
/* the > is because we may have changed the virtual name, and therefore the
|
||||||
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.
|
* TS wont match. We only want to detect when the directory has changed on
|
||||||
// we only want to detect when the directory has changed on the disk
|
* the disk */
|
||||||
|
if(mNeedsFullRecheck || dirIt.dir_modtime() > dir_local_mod_time)
|
||||||
{
|
{
|
||||||
// collect subdirs and subfiles
|
// collect subdirs and subfiles
|
||||||
|
|
||||||
std::map<std::string, DirectoryStorage::FileTS> subfiles;
|
std::map<std::string, DirectoryStorage::FileTS> subfiles;
|
||||||
std::set<std::string> subdirs;
|
std::set<std::string> subdirs;
|
||||||
|
|
||||||
for( ; dirIt.isValid(); dirIt.next() )
|
for( ; dirIt.isValid(); dirIt.next() )
|
||||||
if(filterFile(dirIt.file_name()))
|
if(filterFile(dirIt.file_name()))
|
||||||
{
|
{
|
||||||
switch(dirIt.file_type())
|
const auto fType = dirIt.file_type();
|
||||||
|
switch(fType)
|
||||||
{
|
{
|
||||||
case librs::util::FolderIterator::TYPE_FILE:
|
case librs::util::FolderIterator::TYPE_FILE:
|
||||||
|
if(now >= dirIt.file_modtime() + MIN_TIME_AFTER_LAST_MODIFICATION)
|
||||||
if(dirIt.file_modtime() + MIN_TIME_AFTER_LAST_MODIFICATION < now)
|
|
||||||
{
|
{
|
||||||
subfiles[dirIt.file_name()].modtime = dirIt.file_modtime();
|
subfiles[dirIt.file_name()].modtime = dirIt.file_modtime();
|
||||||
subfiles[dirIt.file_name()].size = dirIt.file_size();
|
subfiles[dirIt.file_name()].size = dirIt.file_size();
|
||||||
#ifdef DEBUG_LOCAL_DIR_UPDATER
|
RS_DBG4("adding sub-file \"", dirIt.file_name(), "\"");
|
||||||
std::cerr << " adding sub-file \"" << dirIt.file_name() << "\"" << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
some_files_not_ready = true;
|
some_files_not_ready = true;
|
||||||
|
RS_INFO( "file: \"", dirIt.file_fullpath(), "\" is "
|
||||||
std::cerr << "(WW) file " << dirIt.file_fullpath() << " is probably being written to. Keeping it for later." << std::endl;
|
"probably being written to. Keep it for later");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case librs::util::FolderIterator::TYPE_DIR:
|
case librs::util::FolderIterator::TYPE_DIR:
|
||||||
{
|
{
|
||||||
bool dir_is_accepted = true;
|
bool dir_is_accepted = true;
|
||||||
|
/* 64 is here as a safe limit, to make infinite loops
|
||||||
if( (mMaxShareDepth > 0u && current_depth > mMaxShareDepth) || (mMaxShareDepth==0 && current_depth >= 64)) // 64 is here as a safe limit, to make loops impossible.
|
* 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;
|
dir_is_accepted = false;
|
||||||
|
|
||||||
if(dir_is_accepted && mFollowSymLinks && mIgnoreDuplicates)
|
if(dir_is_accepted && mFollowSymLinks && mIgnoreDuplicates)
|
||||||
{
|
{
|
||||||
std::string real_path = RsDirUtil::removeSymLinks(cumulated_path + "/" + dirIt.file_name()) ;
|
std::string real_path = RsDirUtil::removeSymLinks(
|
||||||
|
cumulated_path + "/" + dirIt.file_name() );
|
||||||
|
|
||||||
if(existing_directories.end() != existing_directories.find(real_path))
|
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;
|
RS_WARN( "Directory: \"", cumulated_path,
|
||||||
|
"\" has real path: \"", real_path,
|
||||||
|
"\" which already belongs to another "
|
||||||
|
"shared directory. Ignoring" );
|
||||||
dir_is_accepted = false;
|
dir_is_accepted = false;
|
||||||
}
|
}
|
||||||
else
|
else existing_directories.insert(real_path);
|
||||||
existing_directories.insert(real_path) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dir_is_accepted)
|
if(dir_is_accepted) subdirs.insert(dirIt.file_name());
|
||||||
subdirs.insert(dirIt.file_name());
|
|
||||||
|
RS_DBG4("adding sub-dir \"", dirIt.file_name(), "\"");
|
||||||
|
|
||||||
#ifdef DEBUG_LOCAL_DIR_UPDATER
|
|
||||||
std::cerr << " adding sub-dir \"" << dirIt.file_name() << "\"" << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
std::cerr << "(EE) Dir entry of unknown type with path \"" << cumulated_path << "/" << dirIt.file_name() << "\"" << std::endl;
|
RS_ERR( "Got Dir entry of unknown type:", fType,
|
||||||
|
"with path \"", cumulated_path, "/",
|
||||||
|
dirIt.file_name(), "\"" );
|
||||||
|
print_stacktrace();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// update folder modificatoin time, which is the only way to detect e.g. removed or renamed files.
|
|
||||||
|
|
||||||
|
/* update folder modificatoin time, which is the only way to detect
|
||||||
|
* e.g. removed or renamed files. */
|
||||||
mSharedDirectories->setDirectoryLocalModTime(indx,dirIt.dir_modtime());
|
mSharedDirectories->setDirectoryLocalModTime(indx,dirIt.dir_modtime());
|
||||||
|
|
||||||
// update file and dir lists for current directory.
|
// update file and dir lists for current directory.
|
||||||
|
|
||||||
mSharedDirectories->updateSubDirectoryList(indx,subdirs,mHashSalt);
|
mSharedDirectories->updateSubDirectoryList(indx,subdirs,mHashSalt);
|
||||||
|
|
||||||
std::map<std::string, DirectoryStorage::FileTS> new_files;
|
std::map<std::string, DirectoryStorage::FileTS> new_files;
|
||||||
mSharedDirectories->updateSubFilesList(indx, subfiles, new_files);
|
mSharedDirectories->updateSubFilesList(indx, subfiles, new_files);
|
||||||
|
|
||||||
// now go through list of subfiles and request the hash to hashcache
|
// now go through list of subfiles and request the hash to hashcache
|
||||||
|
for( DirectoryStorage::FileIterator dit(mSharedDirectories,indx);
|
||||||
for(DirectoryStorage::FileIterator dit(mSharedDirectories,indx);dit;++dit)
|
dit; ++dit )
|
||||||
{
|
{
|
||||||
// ask about the hash. If not present, ask HashCache. If not present, or different, the callback will update it.
|
/* ask about the hash. If not present, ask HashCache.
|
||||||
|
* If not present, or different, the callback will update it. */
|
||||||
RsFileHash hash;
|
RsFileHash hash;
|
||||||
|
|
||||||
// mSharedDirectories does two things: store H(F), and compute H(H(F)), which is used in FT. The later is always needed.
|
/* 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))
|
if( mHashCache->requestHash(
|
||||||
|
cumulated_path + "/" + dit.name(),
|
||||||
|
dit.size(), dit.modtime(), hash, this, *dit ) )
|
||||||
mSharedDirectories->updateHash(*dit, hash, hash != dit.hash());
|
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
|
// go through the list of sub-dirs and recursively update
|
||||||
|
for( DirectoryStorage::DirIterator stored_dir_it(mSharedDirectories, indx);
|
||||||
for(DirectoryStorage::DirIterator stored_dir_it(mSharedDirectories,indx) ; stored_dir_it; ++stored_dir_it)
|
stored_dir_it; ++stored_dir_it )
|
||||||
{
|
recursUpdateSharedDir( cumulated_path + "/" + stored_dir_it.name(),
|
||||||
#ifdef DEBUG_LOCAL_DIR_UPDATER
|
*stored_dir_it, existing_directories,
|
||||||
std::cerr << " recursing into " << stored_dir_it.name() << std::endl;
|
current_depth+1, some_files_not_ready );
|
||||||
#endif
|
|
||||||
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
|
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)
|
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)
|
void LocalDirectoryUpdater::setFileWatchPeriod(int seconds)
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
* *
|
* *
|
||||||
* libretroshare: retroshare core library *
|
* 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 *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Lesser General Public License as *
|
* it under the terms of the GNU Lesser General Public License as *
|
||||||
@ -30,7 +32,7 @@
|
|||||||
#include "retroshare/rsids.h"
|
#include "retroshare/rsids.h"
|
||||||
#include "retroshare/rspeers.h"
|
#include "retroshare/rspeers.h"
|
||||||
#include "retroshare/rsinit.h"
|
#include "retroshare/rsinit.h"
|
||||||
|
#include "util/cxx17retrocompat.h"
|
||||||
#include "rsserver/p3face.h"
|
#include "rsserver/p3face.h"
|
||||||
|
|
||||||
#define P3FILELISTS_DEBUG() std::cerr << time(NULL) << " : FILE_LISTS : " << __FUNCTION__ << " : "
|
#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.
|
// 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)
|
/* Case where the pointer is NULL, which means we're at the top of the list
|
||||||
// or at the top of our own list of shared directories, depending on the flags.
|
* 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:
|
if (ref == nullptr)
|
||||||
// 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.ref = nullptr;
|
||||||
d.type = DIR_TYPE_ROOT;
|
d.type = DIR_TYPE_ROOT;
|
||||||
d.parent = NULL;
|
d.parent = nullptr;
|
||||||
d.prow = -1;
|
d.prow = -1;
|
||||||
d.name = "root";
|
d.name = "root";
|
||||||
d.hash.clear() ;
|
d.hash.clear() ;
|
||||||
@ -1079,10 +1086,11 @@ int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags
|
|||||||
|
|
||||||
if(flags & RS_FILE_HINTS_LOCAL)
|
if(flags & RS_FILE_HINTS_LOCAL)
|
||||||
{
|
{
|
||||||
void *p;
|
void *p = nullptr;
|
||||||
|
|
||||||
{
|
{
|
||||||
convertEntryIndexToPointer<sizeof(void*)>(0,0,p); // root of own directories
|
// root of own directories
|
||||||
|
convertEntryIndexToPointer<sizeof(void*)>(0, 0, p);
|
||||||
DirStub stub;
|
DirStub stub;
|
||||||
stub.type = DIR_TYPE_PERSON;
|
stub.type = DIR_TYPE_PERSON;
|
||||||
stub.name = mServCtrl->getOwnId().toStdString();
|
stub.name = mServCtrl->getOwnId().toStdString();
|
||||||
@ -1092,9 +1100,11 @@ int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags
|
|||||||
|
|
||||||
if(mExtraFiles->size() > 0)
|
if(mExtraFiles->size() > 0)
|
||||||
{
|
{
|
||||||
convertEntryIndexToPointer<sizeof(void*)>(0,1,p); // local shared files from extra list
|
// local shared files from extra list
|
||||||
|
convertEntryIndexToPointer<sizeof(void*)>(0, 1, p);
|
||||||
DirStub stub;
|
DirStub stub;
|
||||||
stub.type = DIR_TYPE_PERSON; // not totally exact, but used as a trick.
|
// not totally exact, but used as a trick.
|
||||||
|
stub.type = DIR_TYPE_PERSON;
|
||||||
stub.name = "[Extra List]";
|
stub.name = "[Extra List]";
|
||||||
stub.ref = p;
|
stub.ref = p;
|
||||||
|
|
||||||
@ -1132,9 +1142,10 @@ int p3FileDatabase::RequestDirDetails(void *ref, DirDetails& d, FileSearchFlags
|
|||||||
convertPointerToEntryIndex<sizeof(void*)>(ref,e,fi);
|
convertPointerToEntryIndex<sizeof(void*)>(ref,e,fi);
|
||||||
|
|
||||||
// check consistency
|
// check consistency
|
||||||
if( (fi == 0 && !(flags & RS_FILE_HINTS_LOCAL)) || (fi > 1 && (flags & RS_FILE_HINTS_LOCAL)))
|
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;
|
RS_ERR("Remote request on local index or local request on remote index");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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==NULL || !storage->extractData(e,d))
|
if(!storage || !storage->extractData(e,d))
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_FILE_HIERARCHY
|
RS_WARN( "request on index; ", e, ", for directory ID:",
|
||||||
P3FILELISTS_DEBUG() << "(WW) request on index " << e << ", for directory ID=" << ((storage==NULL)?("[NULL]"):(storage->peerId().toStdString())) << " failed. This should not happen." << std::endl;
|
( (!storage)? ("[NULL]") : (storage->peerId().toStdString()) ),
|
||||||
#endif
|
" failed" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update indexes. This is a bit hacky, but does the job. The cast to intptr_t is the proper way to convert
|
/* update indexes. This is a bit hacky, but does the job. The cast to
|
||||||
// a pointer into an int.
|
* intptr_t is the proper way to convert a pointer into an int. */
|
||||||
|
|
||||||
convertEntryIndexToPointer<sizeof(void*)>((intptr_t)d.ref,fi,d.ref);
|
convertEntryIndexToPointer<sizeof(void*)>((intptr_t)d.ref,fi,d.ref);
|
||||||
|
|
||||||
for(uint32_t i=0; i<d.children.size(); ++i)
|
for(uint32_t i=0; i<d.children.size(); ++i)
|
||||||
convertEntryIndexToPointer<sizeof(void*)>((intptr_t)d.children[i].ref,fi,d.children[i].ref);
|
convertEntryIndexToPointer<sizeof(void*)>(
|
||||||
|
(intptr_t) d.children[i].ref, fi, d.children[i].ref );
|
||||||
|
|
||||||
if(e == 0) // root
|
if(e == 0) // root
|
||||||
{
|
{
|
||||||
@ -1307,7 +1321,9 @@ uint32_t p3FileDatabase::watchPeriod()
|
|||||||
return mLocalDirWatcher->fileWatchPeriod();
|
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)
|
if(flags & RS_FILE_HINTS_LOCAL)
|
||||||
{
|
{
|
||||||
@ -1319,10 +1335,10 @@ int p3FileDatabase::SearchKeywords(const std::list<std::string>& keywords, std::
|
|||||||
|
|
||||||
mLocalSharedDirs->searchTerms(keywords,firesults) ;
|
mLocalSharedDirs->searchTerms(keywords,firesults) ;
|
||||||
|
|
||||||
for(std::list<EntryIndex>::iterator it(firesults.begin());it!=firesults.end();++it)
|
for(auto& it: std::as_const(firesults))
|
||||||
{
|
{
|
||||||
void *p=NULL;
|
void *p = nullptr;
|
||||||
convertEntryIndexToPointer<sizeof(void*)>(*it,0,p);
|
convertEntryIndexToPointer<sizeof(void*)>(it, 0, p);
|
||||||
pointers.push_back(p);
|
pointers.push_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1476,7 +1492,9 @@ bool p3FileDatabase::search(
|
|||||||
return false;
|
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();
|
results.clear();
|
||||||
|
|
||||||
@ -1484,22 +1502,26 @@ int p3FileDatabase::filterResults(const std::list<void*>& firesults,std::list<Di
|
|||||||
|
|
||||||
/* translate/filter results */
|
/* translate/filter results */
|
||||||
|
|
||||||
for(std::list<void*>::const_iterator rit(firesults.begin()); rit != firesults.end(); ++rit)
|
for(void* rit: std::as_const(firesults))
|
||||||
{
|
{
|
||||||
DirDetails cdetails;
|
DirDetails cdetails;
|
||||||
|
|
||||||
if(!RequestDirDetails (*rit,cdetails,RS_FILE_HINTS_LOCAL))
|
if(!RequestDirDetails(rit, cdetails, RS_FILE_HINTS_LOCAL))
|
||||||
{
|
{
|
||||||
P3FILELISTS_ERROR() << "(EE) Cannot get dir details for entry " << *rit << std::endl;
|
RS_ERR("Cannot retrieve dir details for entry: ", rit);
|
||||||
|
print_stacktrace();
|
||||||
continue ;
|
continue ;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_P3FILELISTS
|
|
||||||
P3FILELISTS_DEBUG() << "Filtering candidate " << *rit << ", flags=" << cdetails.flags << ", peer=" << peer_id ;
|
RS_DBG( "Filtering candidate: ", rit,
|
||||||
#endif
|
", name: ", cdetails.name, ", path: ", cdetails.path,
|
||||||
|
", flags: ", cdetails.flags, ", peer: ", peer_id );
|
||||||
|
|
||||||
if(!peer_id.isNull())
|
if(!peer_id.isNull())
|
||||||
{
|
{
|
||||||
FileSearchFlags permission_flags = rsPeers->computePeerPermissionFlags(peer_id,cdetails.flags,cdetails.parent_groups) ;
|
FileSearchFlags permission_flags =
|
||||||
|
rsPeers->computePeerPermissionFlags(
|
||||||
|
peer_id, cdetails.flags, cdetails.parent_groups );
|
||||||
|
|
||||||
if (cdetails.type == DIR_TYPE_FILE && ( permission_flags & flags ))
|
if (cdetails.type == DIR_TYPE_FILE && ( permission_flags & flags ))
|
||||||
{
|
{
|
||||||
@ -1518,6 +1540,18 @@ int p3FileDatabase::filterResults(const std::list<void*>& firesults,std::list<Di
|
|||||||
results.push_back(cdetails);
|
results.push_back(cdetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
return !results.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1598,17 +1632,16 @@ void p3FileDatabase::handleDirSyncRequest(RsFileListsSyncRequestItem *item)
|
|||||||
{
|
{
|
||||||
RS_STACK_MUTEX(mFLSMtx);
|
RS_STACK_MUTEX(mFLSMtx);
|
||||||
|
|
||||||
#ifdef DEBUG_P3FILELISTS
|
RS_DBG( "Received directory sync request from peer ", item->PeerId(),
|
||||||
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;
|
". hash=", item->entry_hash, ", flags=", item->flags,
|
||||||
#endif
|
", 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))
|
if(!mLocalSharedDirs->getIndexFromDirHash(item->entry_hash,entry_index))
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_P3FILELISTS
|
RS_DBG("Cannot find entry index for hash ", item->entry_hash,
|
||||||
P3FILELISTS_DEBUG() << " (EE) Cannot find entry index for hash " << item->entry_hash << ": cannot respond to sync request." << std::endl;
|
" cannot respond to sync request." );
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1622,47 +1655,60 @@ void p3FileDatabase::handleDirSyncRequest(RsFileListsSyncRequestItem *item)
|
|||||||
|
|
||||||
if(entry_type != DIR_TYPE_DIR)
|
if(entry_type != DIR_TYPE_DIR)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_P3FILELISTS
|
RS_DBG( "Directory does not exist anymore, or is not a directory, "
|
||||||
P3FILELISTS_DEBUG() << " Directory does not exist anymore, or is not a directory, or permission denied. Answering with proper flags." << std::endl;
|
"or permission denied. Answering with proper flags." );
|
||||||
#endif
|
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE |
|
||||||
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE | RsFileListsItem::FLAGS_ENTRY_WAS_REMOVED ;
|
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)))
|
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;
|
RS_ERR("cannot get file permissions for entry index: ", entry_index,
|
||||||
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE | RsFileListsItem::FLAGS_ENTRY_WAS_REMOVED ;
|
", or permission denied." );
|
||||||
|
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE |
|
||||||
|
RsFileListsItem::FLAGS_ENTRY_WAS_REMOVED;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rstime_t local_recurs_max_time;
|
rstime_t local_recurs_max_time;
|
||||||
mLocalSharedDirs->getDirectoryRecursModTime(entry_index,local_recurs_max_time) ;
|
mLocalSharedDirs->getDirectoryRecursModTime(
|
||||||
|
entry_index, local_recurs_max_time );
|
||||||
|
|
||||||
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.
|
/* 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)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_P3FILELISTS
|
RS_DBG( "Directory is more recent than what the friend knows. "
|
||||||
P3FILELISTS_DEBUG() << " Directory is more recent than what the friend knows. Sending full dir content as response." << std::endl;
|
"Sending full dir content as response.");
|
||||||
#endif
|
|
||||||
|
|
||||||
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE | RsFileListsItem::FLAGS_SYNC_DIR_CONTENT;
|
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE |
|
||||||
|
RsFileListsItem::FLAGS_SYNC_DIR_CONTENT;
|
||||||
ritem->last_known_recurs_modf_TS = local_recurs_max_time;
|
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.
|
/* We supply the peer id, in order to possibly remove some
|
||||||
mLocalSharedDirs->serialiseDirEntry(entry_index,ritem->directory_content_data,item->PeerId()) ;
|
* subdirs, if entries are not allowed to be seen by this peer.
|
||||||
|
*/
|
||||||
|
mLocalSharedDirs->serialiseDirEntry(
|
||||||
|
entry_index, ritem->directory_content_data,
|
||||||
|
item->PeerId() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_P3FILELISTS
|
RS_DBG3( "Directory is up to date w.r.t. what the friend knows."
|
||||||
P3FILELISTS_DEBUG() << " Directory is up to date w.r.t. what the friend knows. Sending ACK." << std::endl;
|
" Sending ACK." );
|
||||||
#endif
|
|
||||||
|
|
||||||
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE | RsFileListsItem::FLAGS_ENTRY_UP_TO_DATE ;
|
ritem->flags = RsFileListsItem::FLAGS_SYNC_RESPONSE |
|
||||||
|
RsFileListsItem::FLAGS_ENTRY_UP_TO_DATE;
|
||||||
ritem->last_known_recurs_modf_TS = local_recurs_max_time;
|
ritem->last_known_recurs_modf_TS = local_recurs_max_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sends the response.
|
// sends the response.
|
||||||
|
|
||||||
splitAndSendItem(ritem);
|
splitAndSendItem(ritem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
* *
|
* *
|
||||||
* libretroshare: retroshare core library *
|
* 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 *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Lesser General Public License as *
|
* it under the terms of the GNU Lesser General Public License as *
|
||||||
@ -876,7 +878,9 @@ int ftServer::SearchKeywords(std::list<std::string> keywords, std::list<DirDetai
|
|||||||
{
|
{
|
||||||
return mFileDatabase->SearchKeywords(keywords, results,flags,RsPeerId());
|
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);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
* *
|
* *
|
||||||
* libretroshare: retroshare core library *
|
* 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 *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Lesser General Public License as *
|
* it under the terms of the GNU Lesser General Public License as *
|
||||||
@ -26,6 +28,10 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include "rsserver/p3face.h"
|
#include "rsserver/p3face.h"
|
||||||
#include "crypto/rscrypto.h"
|
#include "crypto/rscrypto.h"
|
||||||
@ -39,13 +45,7 @@
|
|||||||
#include "ft/ftcontroller.h"
|
#include "ft/ftcontroller.h"
|
||||||
|
|
||||||
#include "p3turtle.h"
|
#include "p3turtle.h"
|
||||||
|
#include "util/cxx17retrocompat.h"
|
||||||
#include <iostream>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "util/rsdebug.h"
|
#include "util/rsdebug.h"
|
||||||
#include "util/rsprint.h"
|
#include "util/rsprint.h"
|
||||||
#include "util/rsrandom.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 */
|
/* call to core */
|
||||||
std::list<DirDetails> initialResults;
|
std::list<DirDetails> initialResults;
|
||||||
@ -1988,17 +1989,19 @@ void RsTurtleStringSearchRequestItem::search(std::list<TurtleFileInfo>& result)
|
|||||||
std::cerr << "Performing rsFiles->search()" << std::endl ;
|
std::cerr << "Performing rsFiles->search()" << std::endl ;
|
||||||
#endif
|
#endif
|
||||||
// now, search!
|
// 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
|
#ifdef P3TURTLE_DEBUG
|
||||||
std::cerr << initialResults.size() << " matches found." << std::endl ;
|
std::cerr << initialResults.size() << " matches found." << std::endl ;
|
||||||
#endif
|
#endif
|
||||||
result.clear() ;
|
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
|
// retain only file type
|
||||||
if (it->type == DIR_TYPE_DIR)
|
if (it.type == DIR_TYPE_DIR)
|
||||||
{
|
{
|
||||||
#ifdef P3TURTLE_DEBUG
|
#ifdef P3TURTLE_DEBUG
|
||||||
std::cerr << " Skipping directory " << it->name << std::endl ;
|
std::cerr << " Skipping directory " << it->name << std::endl ;
|
||||||
@ -2007,9 +2010,9 @@ void RsTurtleStringSearchRequestItem::search(std::list<TurtleFileInfo>& result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TurtleFileInfo i;
|
TurtleFileInfo i;
|
||||||
i.hash = it->hash ;
|
i.hash = it.hash;
|
||||||
i.size = it->size ;
|
i.size = it.size;
|
||||||
i.name = it->name ;
|
i.name = it.name;
|
||||||
|
|
||||||
result.push_back(i);
|
result.push_back(i);
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,11 @@
|
|||||||
namespace librs { namespace util {
|
namespace librs { namespace util {
|
||||||
|
|
||||||
|
|
||||||
FolderIterator::FolderIterator(const std::string& folderName, bool allow_symlinks, bool allow_files_from_the_future)
|
FolderIterator::FolderIterator(
|
||||||
: mFolderName(folderName),mAllowSymLinks(allow_symlinks),mAllowFilesFromTheFuture(allow_files_from_the_future)
|
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 ;
|
is_open = false ;
|
||||||
validity = false ;
|
validity = false ;
|
||||||
|
@ -44,7 +44,9 @@ namespace librs { namespace util {
|
|||||||
class FolderIterator
|
class FolderIterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FolderIterator(const std::string& folderName,bool allow_symlinks,bool allow_files_from_the_future = true);
|
FolderIterator(
|
||||||
|
const std::string& folderName, bool allow_symlinks,
|
||||||
|
bool allow_files_from_the_future = true );
|
||||||
~FolderIterator();
|
~FolderIterator();
|
||||||
|
|
||||||
enum { TYPE_UNKNOWN = 0x00,
|
enum { TYPE_UNKNOWN = 0x00,
|
||||||
|
@ -458,6 +458,36 @@ bool RsDirUtil::checkFile(const std::string& filename,uint64_t& file_size,bool d
|
|||||||
return true;
|
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)
|
bool RsDirUtil::checkDirectory(const std::string& dir)
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
* libretroshare: retroshare core library *
|
* libretroshare: retroshare core library *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2004-2007 Robert Fernie <retroshare@lunamutt.com> *
|
* Copyright (C) 2004-2007 Robert Fernie <retroshare@lunamutt.com> *
|
||||||
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
|
* Copyright (C) 2020-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||||
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
|
* Copyright (C) 2020-2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||||
* *
|
* *
|
||||||
* This program is free software: you can redistribute it and/or modify *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Lesser General Public License as *
|
* it under the terms of the GNU Lesser General Public License as *
|
||||||
@ -27,11 +27,13 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
class RsThread;
|
class RsThread;
|
||||||
|
|
||||||
#include <retroshare/rstypes.h>
|
#include "retroshare/rstypes.h"
|
||||||
|
#include "util/rsmemory.h"
|
||||||
|
|
||||||
#ifndef WINDOWS_SYS
|
#ifndef WINDOWS_SYS
|
||||||
typedef int rs_lock_handle_t;
|
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);
|
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 '/'
|
/** Splits the path into parent directory and file. File can be empty if
|
||||||
// if full_path does not contain a directory, then dir will be "." and file will be full_path.
|
* 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 splitDirFromFile( const std::string& full_path,
|
||||||
|
std::string& dir, std::string& file );
|
||||||
|
|
||||||
bool copyFile(const std::string& source,const std::string& dest);
|
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 removeFile(const std::string& file);
|
||||||
bool fileExists(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);
|
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 checkDirectory(const std::string& dir);
|
||||||
bool checkCreateDirectory(const std::string& dir);
|
bool checkCreateDirectory(const std::string& dir);
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
* *
|
* *
|
||||||
* libretroshare: retroshare core library *
|
* 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 *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Lesser General Public License as *
|
* it under the terms of the GNU Lesser General Public License as *
|
||||||
|
Loading…
x
Reference in New Issue
Block a user