2016-07-24 23:48:22 -04:00
# include <set>
2016-08-27 08:09:26 -04:00
# include "serialiser/rstlvbinary.h"
2016-07-31 09:59:58 -04:00
# include "util/rsdir.h"
2016-08-06 13:04:54 -04:00
# include "util/rsstring.h"
2016-07-21 00:16:12 -04:00
# include "directory_storage.h"
2016-08-26 10:29:02 -04:00
# include "filelist_io.h"
2016-07-21 00:16:12 -04:00
2016-08-16 17:44:48 -04:00
# define DEBUG_DIRECTORY_STORAGE 1
2016-07-24 23:48:22 -04:00
/******************************************************************************************************************/
/* Internal File Hierarchy Storage */
/******************************************************************************************************************/
template < class T > typename std : : set < T > : : iterator erase_from_set ( typename std : : set < T > & s , const typename std : : set < T > : : iterator & it )
{
typename std : : set < T > : : iterator tmp ( it ) ;
+ + tmp ;
s . erase ( it ) ;
return tmp ;
}
// This class handles the file hierarchy
// A Mutex is used to ensure total coherence at this level. So only abstracted operations are allowed,
// so that the hierarchy stays completely coherent between calls.
2016-07-21 00:16:12 -04:00
class InternalFileHierarchyStorage
{
2016-08-27 08:09:26 -04:00
public :
2016-07-21 00:16:12 -04:00
class FileStorageNode
{
public :
2016-07-27 15:22:59 -04:00
static const uint32_t TYPE_UNKNOWN = 0x0000 ;
static const uint32_t TYPE_FILE = 0x0001 ;
static const uint32_t TYPE_DIR = 0x0002 ;
2016-07-23 22:14:43 -04:00
2016-07-24 23:48:22 -04:00
virtual ~ FileStorageNode ( ) { }
2016-07-21 00:16:12 -04:00
virtual uint32_t type ( ) const = 0 ;
2016-08-11 08:07:45 -04:00
DirectoryStorage : : EntryIndex parent_index ;
uint32_t row ;
2016-07-21 00:16:12 -04:00
} ;
class FileEntry : public FileStorageNode
{
public :
2016-07-28 03:29:15 -04:00
FileEntry ( const std : : string & name , uint64_t size , time_t modtime ) : file_name ( name ) , file_size ( size ) , file_modtime ( modtime ) { }
2016-07-21 00:16:12 -04:00
virtual uint32_t type ( ) const { return FileStorageNode : : TYPE_FILE ; }
2016-07-24 23:48:22 -04:00
virtual ~ FileEntry ( ) { }
2016-07-21 00:16:12 -04:00
2016-07-24 23:48:22 -04:00
// local stuff
std : : string file_name ;
uint64_t file_size ;
RsFileHash file_hash ;
time_t file_modtime ;
2016-07-21 00:16:12 -04:00
} ;
class DirEntry : public FileStorageNode
{
public :
2016-08-26 10:29:02 -04:00
DirEntry ( const std : : string & name ) : dir_name ( name ) , dir_modtime ( 0 ) , most_recent_time ( 0 ) , dir_update_time ( 0 ) { }
2016-07-24 23:48:22 -04:00
virtual ~ DirEntry ( ) { }
2016-07-21 00:16:12 -04:00
virtual uint32_t type ( ) const { return FileStorageNode : : TYPE_DIR ; }
2016-07-24 23:48:22 -04:00
// local stuff
std : : string dir_name ;
2016-08-11 08:07:45 -04:00
std : : string dir_parent_path ;
2016-07-24 23:48:22 -04:00
std : : vector < DirectoryStorage : : EntryIndex > subdirs ;
std : : vector < DirectoryStorage : : EntryIndex > subfiles ;
2016-08-11 08:07:45 -04:00
2016-08-22 01:49:45 -04:00
time_t dir_modtime ; // this accounts for deleted files, etc.
time_t most_recent_time ; // recursive most recent modification time, including files and subdirs in the entire hierarchy below.
2016-08-26 10:29:02 -04:00
time_t dir_update_time ; // last time the information was updated for that directory. Includes subdirs indexes and subfile info.
2016-07-21 00:16:12 -04:00
} ;
2016-07-24 23:48:22 -04:00
// class stuff
InternalFileHierarchyStorage ( ) : mRoot ( 0 )
{
2016-08-11 08:07:45 -04:00
mNodes . push_back ( new DirEntry ( " " ) ) ;
mNodes . back ( ) - > row = 0 ;
2016-08-16 17:44:48 -04:00
mNodes . back ( ) - > parent_index = 0 ;
2016-08-11 08:07:45 -04:00
}
int parentRow ( DirectoryStorage : : EntryIndex e )
{
if ( ! checkIndex ( e , FileStorageNode : : TYPE_DIR | FileStorageNode : : TYPE_FILE ) | | e = = 0 )
return - 1 ;
return mNodes [ mNodes [ e ] - > parent_index ] - > row ;
2016-07-24 23:48:22 -04:00
}
// high level modification routines
2016-07-27 15:22:59 -04:00
bool isIndexValid ( DirectoryStorage : : EntryIndex e ) const
2016-07-24 23:48:22 -04:00
{
return e < mNodes . size ( ) & & mNodes [ e ] ! = NULL ;
}
bool updateSubDirectoryList ( const DirectoryStorage : : EntryIndex & indx , const std : : set < std : : string > & subdirs )
{
2016-07-27 15:22:59 -04:00
if ( ! checkIndex ( indx , FileStorageNode : : TYPE_DIR ) )
return false ;
2016-07-24 23:48:22 -04:00
DirEntry & d ( * static_cast < DirEntry * > ( mNodes [ indx ] ) ) ;
std : : set < std : : string > should_create ( subdirs ) ;
for ( uint32_t i = 0 ; i < d . subdirs . size ( ) ; )
if ( subdirs . find ( static_cast < DirEntry * > ( mNodes [ d . subdirs [ i ] ] ) - > dir_name ) = = subdirs . end ( ) )
2016-08-13 04:15:02 -04:00
{
2016-08-16 07:46:55 -04:00
std : : cerr < < " [directory storage] Removing subdirectory " < < static_cast < DirEntry * > ( mNodes [ d . subdirs [ i ] ] ) - > dir_name < < " with index " < < d . subdirs [ i ] < < std : : endl ;
2016-08-13 04:15:02 -04:00
if ( ! removeDirectory ( d . subdirs [ i ] ) )
i + + ;
}
2016-07-24 23:48:22 -04:00
else
{
2016-08-16 07:46:55 -04:00
std : : cerr < < " [directory storage] Keeping existing subdirectory " < < static_cast < DirEntry * > ( mNodes [ d . subdirs [ i ] ] ) - > dir_name < < " with index " < < d . subdirs [ i ] < < std : : endl ;
2016-07-24 23:48:22 -04:00
should_create . erase ( static_cast < DirEntry * > ( mNodes [ d . subdirs [ i ] ] ) - > dir_name ) ;
+ + i ;
}
for ( std : : set < std : : string > : : const_iterator it ( should_create . begin ( ) ) ; it ! = should_create . end ( ) ; + + it )
{
2016-08-16 07:46:55 -04:00
std : : cerr < < " [directory storage] adding new subdirectory " < < * it < < " at index " < < mNodes . size ( ) < < std : : endl ;
2016-07-24 23:48:22 -04:00
d . subdirs . push_back ( mNodes . size ( ) ) ;
2016-08-11 08:07:45 -04:00
mNodes . push_back ( new DirEntry ( * it ) ) ;
mNodes . back ( ) - > row = mNodes . size ( ) - 1 ;
mNodes . back ( ) - > parent_index = indx ;
2016-07-24 23:48:22 -04:00
}
return true ;
}
bool removeDirectory ( const DirectoryStorage : : EntryIndex & indx )
{
// check that it's a directory
2016-07-27 15:22:59 -04:00
if ( ! checkIndex ( indx , FileStorageNode : : TYPE_DIR ) )
return false ;
2016-07-24 23:48:22 -04:00
if ( indx = = 0 )
2016-07-27 15:22:59 -04:00
return nodeAccessError ( " checkIndex() : Cannot remove top level directory " ) ;
2016-07-24 23:48:22 -04:00
// remove from parent
DirEntry & d ( * static_cast < DirEntry * > ( mNodes [ indx ] ) ) ;
DirEntry & parent_dir ( * static_cast < DirEntry * > ( mNodes [ d . parent_index ] ) ) ;
for ( uint32_t i = 0 ; i < parent_dir . subdirs . size ( ) ; + + i )
if ( parent_dir . subdirs [ i ] = = indx )
return recursRemoveDirectory ( indx ) ;
return nodeAccessError ( " removeDirectory() : inconsistency ! ! " ) ;
}
2016-07-27 15:22:59 -04:00
bool checkIndex ( DirectoryStorage : : EntryIndex indx , uint8_t type ) const
2016-07-24 23:48:22 -04:00
{
2016-07-27 15:22:59 -04:00
if ( mNodes . empty ( ) | | indx = = DirectoryStorage : : NO_INDEX | | indx > = mNodes . size ( ) | | mNodes [ indx ] = = NULL )
return nodeAccessError ( " checkIndex() : Node does not exist " ) ;
2016-08-16 17:44:48 -04:00
if ( ! ( mNodes [ indx ] - > type ( ) & type ) )
2016-07-27 15:22:59 -04:00
return nodeAccessError ( " checkIndex() : Node is of wrong type " ) ;
return true ;
}
2016-07-24 23:48:22 -04:00
2016-07-28 03:29:15 -04:00
bool updateSubFilesList ( const DirectoryStorage : : EntryIndex & indx , const std : : map < std : : string , DirectoryStorage : : FileTS > & subfiles , std : : map < std : : string , DirectoryStorage : : FileTS > & new_files )
2016-07-27 15:22:59 -04:00
{
if ( ! checkIndex ( indx , FileStorageNode : : TYPE_DIR ) )
return false ;
2016-07-24 23:48:22 -04:00
DirEntry & d ( * static_cast < DirEntry * > ( mNodes [ indx ] ) ) ;
new_files = subfiles ;
2016-07-28 03:29:15 -04:00
// remove from new_files the ones that already exist and have a modf time that is not older.
2016-07-24 23:48:22 -04:00
for ( uint32_t i = 0 ; i < d . subfiles . size ( ) ; )
2016-07-28 03:29:15 -04:00
{
FileEntry & f ( * static_cast < FileEntry * > ( mNodes [ d . subfiles [ i ] ] ) ) ;
std : : map < std : : string , DirectoryStorage : : FileTS > : : const_iterator it = subfiles . find ( f . file_name ) ;
if ( it = = subfiles . end ( ) ) // file does not exist anymore => delete
2016-07-24 23:48:22 -04:00
{
2016-08-16 07:46:55 -04:00
std : : cerr < < " [directory storage] removing non existing file " < < f . file_name < < " at index " < < d . subfiles [ i ] < < std : : endl ;
delete mNodes [ d . subfiles [ i ] ] ;
mNodes [ d . subfiles [ i ] ] = NULL ;
2016-07-24 23:48:22 -04:00
d . subfiles [ i ] = d . subfiles [ d . subfiles . size ( ) - 1 ] ;
d . subfiles . pop_back ( ) ;
2016-07-28 03:29:15 -04:00
continue ;
2016-07-24 23:48:22 -04:00
}
2016-07-28 03:29:15 -04:00
if ( it - > second . modtime ! = f . file_modtime | | it - > second . size ! = f . file_size ) // file is newer and/or has different size
2016-07-28 04:49:49 -04:00
{
2016-07-28 03:29:15 -04:00
f . file_hash . clear ( ) ; // hash needs recomputing
2016-07-28 04:49:49 -04:00
f . file_modtime = it - > second . modtime ;
f . file_size = it - > second . size ;
}
2016-07-24 23:48:22 -04:00
else
2016-07-28 03:29:15 -04:00
new_files . erase ( f . file_name ) ;
+ + i ;
}
2016-07-24 23:48:22 -04:00
2016-07-28 03:29:15 -04:00
for ( std : : map < std : : string , DirectoryStorage : : FileTS > : : const_iterator it ( new_files . begin ( ) ) ; it ! = new_files . end ( ) ; + + it )
2016-07-24 23:48:22 -04:00
{
2016-08-16 07:46:55 -04:00
std : : cerr < < " [directory storage] adding new file " < < it - > first < < " at index " < < mNodes . size ( ) < < std : : endl ;
2016-07-24 23:48:22 -04:00
d . subfiles . push_back ( mNodes . size ( ) ) ;
2016-07-28 03:29:15 -04:00
mNodes . push_back ( new FileEntry ( it - > first , it - > second . size , it - > second . modtime ) ) ;
2016-08-11 08:07:45 -04:00
mNodes . back ( ) - > row = mNodes . size ( ) - 1 ;
mNodes . back ( ) - > parent_index = indx ;
2016-07-24 23:48:22 -04:00
}
return true ;
}
2016-07-27 15:22:59 -04:00
bool updateHash ( const DirectoryStorage : : EntryIndex & file_index , const RsFileHash & hash )
{
if ( ! checkIndex ( file_index , FileStorageNode : : TYPE_FILE ) )
2016-08-16 07:46:55 -04:00
{
std : : cerr < < " [directory storage] (EE) cannot update file at index " < < file_index < < " . Not a valid index, or not a file. " < < std : : endl ;
2016-07-27 15:22:59 -04:00
return false ;
2016-08-16 07:46:55 -04:00
}
std : : cerr < < " [directory storage] updating hash at index " < < file_index < < " , hash= " < < hash < < std : : endl ;
2016-07-27 15:22:59 -04:00
2016-08-22 01:49:45 -04:00
RsFileHash & old_hash ( static_cast < FileEntry * > ( mNodes [ file_index ] ) - > file_hash ) ;
old_hash = hash ;
2016-07-27 15:22:59 -04:00
return true ;
}
2016-07-28 03:29:15 -04:00
bool updateFile ( const DirectoryStorage : : EntryIndex & file_index , const RsFileHash & hash , const std : : string & fname , uint64_t size , const time_t modf_time )
2016-07-27 15:22:59 -04:00
{
if ( ! checkIndex ( file_index , FileStorageNode : : TYPE_FILE ) )
2016-08-16 07:46:55 -04:00
{
std : : cerr < < " [directory storage] (EE) cannot update file at index " < < file_index < < " . Not a valid index, or not a file. " < < std : : endl ;
2016-07-27 15:22:59 -04:00
return false ;
2016-08-16 07:46:55 -04:00
}
2016-07-27 15:22:59 -04:00
FileEntry & fe ( * static_cast < FileEntry * > ( mNodes [ file_index ] ) ) ;
2016-08-16 07:46:55 -04:00
std : : cerr < < " [directory storage] updating file entry at index " < < file_index < < " , name= " < < fe . file_name < < " size= " < < fe . file_size < < " , hash= " < < fe . file_hash < < std : : endl ;
2016-07-27 15:22:59 -04:00
fe . file_hash = hash ;
fe . file_size = size ;
fe . file_modtime = modf_time ;
return true ;
}
2016-08-27 08:09:26 -04:00
bool updateDirEntry ( const DirectoryStorage : : EntryIndex & indx , const std : : string & dir_name , time_t most_recent_time , time_t dir_modtime , const std : : vector < DirectoryStorage : : EntryIndex > & subdirs_array , const std : : vector < DirectoryStorage : : EntryIndex > & 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 ] ) ) ;
d . most_recent_time = most_recent_time ;
d . dir_modtime = dir_modtime ;
d . dir_update_time = time ( NULL ) ;
d . subfiles = subfiles_array ;
d . subdirs = subdirs_array ;
// check that all subdirs already exist. If not, create.
for ( uint32_t i = 0 ; i < subdirs_array . size ( ) ; + + i )
{
if ( subdirs_array [ i ] > = mNodes . size ( ) )
mNodes . resize ( subdirs_array [ i ] + 1 , NULL ) ;
FileStorageNode * & node ( mNodes [ subdirs_array [ i ] ] ) ;
if ( node ! = NULL & & node - > type ( ) ! = FileStorageNode : : TYPE_DIR )
{
delete node ;
node = NULL ;
}
if ( node = = NULL )
node = new DirEntry ( " " ) ;
( ( DirEntry * & ) node ) - > dir_parent_path = d . dir_parent_path + " / " + dir_name ;
node - > row = i ;
}
for ( uint32_t i = 0 ; i < subfiles_array . size ( ) ; + + i )
{
if ( subfiles_array [ i ] > = mNodes . size ( ) )
mNodes . resize ( subfiles_array [ i ] + 1 , NULL ) ;
FileStorageNode * & node ( mNodes [ subfiles_array [ i ] ] ) ;
if ( node ! = NULL & & node - > type ( ) ! = FileStorageNode : : TYPE_FILE )
{
delete node ;
node = NULL ;
}
if ( node = = NULL )
node = new FileEntry ( " " , 0 , 0 ) ;
node - > row = subdirs_array . size ( ) + i ;
}
// we should also update the row of each subfile and each subdir
}
2016-08-26 10:29:02 -04:00
bool getDirUpdateTS ( const DirectoryStorage : : EntryIndex & index , time_t & recurs_max_modf_TS , time_t & local_update_TS )
{
if ( ! checkIndex ( index , FileStorageNode : : TYPE_DIR ) )
{
std : : cerr < < " [directory storage] (EE) cannot update TS for index " < < index < < " . Not a valid index or not a directory. " < < std : : endl ;
return false ;
}
DirEntry & d ( * static_cast < DirEntry * > ( mNodes [ index ] ) ) ;
recurs_max_modf_TS = d . most_recent_time ;
local_update_TS = d . dir_update_time ;
return true ;
}
bool setDirUpdateTS ( const DirectoryStorage : : EntryIndex & index , time_t & recurs_max_modf_TS , time_t & local_update_TS )
{
if ( ! checkIndex ( index , FileStorageNode : : TYPE_DIR ) )
{
std : : cerr < < " [directory storage] (EE) cannot update TS for index " < < index < < " . Not a valid index or not a directory. " < < std : : endl ;
return false ;
}
DirEntry & d ( * static_cast < DirEntry * > ( mNodes [ index ] ) ) ;
d . most_recent_time = recurs_max_modf_TS ;
d . dir_update_time = local_update_TS ;
return true ;
}
2016-07-24 23:48:22 -04:00
2016-08-22 01:49:45 -04:00
// Do a complete recursive sweep over sub-directories and files, and update the lst modf TS. This could be also performed by a cleanup method.
time_t recursUpdateLastModfTime ( const DirectoryStorage : : EntryIndex & dir_index )
{
DirEntry & d ( * static_cast < DirEntry * > ( mNodes [ dir_index ] ) ) ;
time_t largest_modf_time = d . dir_modtime ;
for ( uint32_t i = 0 ; i < d . subfiles . size ( ) ; + + i )
largest_modf_time = std : : max ( largest_modf_time , static_cast < FileEntry * > ( mNodes [ d . subfiles [ i ] ] ) - > file_modtime ) ;
for ( uint32_t i = 0 ; i < d . subdirs . size ( ) ; + + i )
largest_modf_time = std : : max ( largest_modf_time , recursUpdateLastModfTime ( d . subdirs [ i ] ) ) ;
d . most_recent_time = largest_modf_time ;
return largest_modf_time ;
}
2016-07-21 00:16:12 -04:00
// file/dir access and modification
2016-07-23 22:14:43 -04:00
bool findSubDirectory ( DirectoryStorage : : EntryIndex e , const std : : string & s ) const ; // returns true when s is the name of a sub-directory in the given entry e
2016-07-21 00:16:12 -04:00
2016-07-24 23:48:22 -04:00
uint32_t mRoot ;
2016-07-21 00:16:12 -04:00
std : : vector < FileStorageNode * > mNodes ; // uses pointers to keep information about valid/invalid objects.
2016-07-24 23:48:22 -04:00
void compress ( ) ; // use empty space in the vector, mostly due to deleted entries. This is a complicated operation, mostly due to
// all the indirections used. Nodes need to be moved, renamed, etc. The operation discards all file entries that
// are not referenced.
2016-07-21 00:16:12 -04:00
friend class DirectoryStorage ; // only class that can use this.
2016-08-11 08:07:45 -04:00
friend class LocalDirectoryStorage ; // only class that can use this.
2016-07-24 23:48:22 -04:00
2016-07-27 15:22:59 -04:00
// Low level stuff. Should normally not be used externally.
const DirEntry * getDirEntry ( DirectoryStorage : : EntryIndex indx ) const
{
if ( ! checkIndex ( indx , FileStorageNode : : TYPE_DIR ) )
return NULL ;
return static_cast < DirEntry * > ( mNodes [ indx ] ) ;
}
const FileEntry * getFileEntry ( DirectoryStorage : : EntryIndex indx ) const
{
if ( ! checkIndex ( indx , FileStorageNode : : TYPE_FILE ) )
return NULL ;
2016-07-24 23:48:22 -04:00
2016-07-27 15:22:59 -04:00
return static_cast < FileEntry * > ( mNodes [ indx ] ) ;
}
2016-08-11 08:07:45 -04:00
uint32_t getType ( DirectoryStorage : : EntryIndex indx ) const
{
if ( checkIndex ( indx , FileStorageNode : : TYPE_FILE ) )
return FileStorageNode : : TYPE_FILE ;
else if ( checkIndex ( indx , FileStorageNode : : TYPE_DIR ) )
return FileStorageNode : : TYPE_DIR ;
else
return FileStorageNode : : TYPE_UNKNOWN ;
}
2016-07-24 23:48:22 -04:00
DirectoryStorage : : EntryIndex getSubFileIndex ( DirectoryStorage : : EntryIndex parent_index , uint32_t file_tab_index )
{
2016-07-27 15:22:59 -04:00
if ( ! checkIndex ( parent_index , FileStorageNode : : TYPE_DIR ) )
2016-07-24 23:48:22 -04:00
return DirectoryStorage : : NO_INDEX ;
if ( static_cast < DirEntry * > ( mNodes [ parent_index ] ) - > subfiles . size ( ) < = file_tab_index )
return DirectoryStorage : : NO_INDEX ;
return static_cast < DirEntry * > ( mNodes [ parent_index ] ) - > subfiles [ file_tab_index ] ;
}
DirectoryStorage : : EntryIndex getSubDirIndex ( DirectoryStorage : : EntryIndex parent_index , uint32_t dir_tab_index )
{
2016-07-27 15:22:59 -04:00
if ( ! checkIndex ( parent_index , FileStorageNode : : TYPE_DIR ) )
2016-07-24 23:48:22 -04:00
return DirectoryStorage : : NO_INDEX ;
if ( static_cast < DirEntry * > ( mNodes [ parent_index ] ) - > subdirs . size ( ) < = dir_tab_index )
return DirectoryStorage : : NO_INDEX ;
2016-07-27 18:48:28 -04:00
return static_cast < DirEntry * > ( mNodes [ parent_index ] ) - > subdirs [ dir_tab_index ] ;
2016-07-24 23:48:22 -04:00
}
2016-08-20 10:23:11 -04:00
bool searchHash ( const RsFileHash & hash , std : : list < DirectoryStorage : : EntryIndex > & results )
{
std : : map < RsFileHash , DirectoryStorage : : EntryIndex > : : const_iterator it = mHashes . find ( hash ) ;
if ( it ! = mHashes . end ( ) )
{
results . clear ( ) ;
results . push_back ( it - > second ) ;
return true ;
}
else
return false ;
}
2016-08-26 10:29:02 -04:00
bool check ( std : : string & error_string ) const // checks consistency of storage.
2016-07-24 23:48:22 -04:00
{
2016-08-26 10:29:02 -04:00
// recurs go through all entries, check that all
std : : vector < uint32_t > hits ( mNodes . size ( ) , 0 ) ; // count hits of children. Should be 1 for all in the end. Otherwise there's an error.
hits [ 0 ] = 1 ; // because 0 is never the child of anyone
for ( uint32_t i = 0 ; i < mNodes . size ( ) ; + + i )
if ( mNodes [ i ] - > type ( ) = = FileStorageNode : : TYPE_DIR )
{
// stamp the kids
const DirEntry & de = * static_cast < DirEntry * > ( mNodes [ i ] ) ;
for ( uint32_t j = 0 ; j < de . subdirs . size ( ) ; + + j )
{
if ( de . subdirs [ j ] > = mNodes . size ( ) )
{
error_string = " Node child out of tab! " ;
return false ;
}
if ( hits [ de . subdirs [ j ] ] ! = 0 )
{
error_string = " Double hit on a single node " ;
return false ;
}
hits [ de . subdirs [ j ] ] = 1 ;
}
for ( uint32_t j = 0 ; j < de . subfiles . size ( ) ; + + j )
{
if ( de . subfiles [ j ] > = mNodes . size ( ) )
{
error_string = " Node child out of tab! " ;
return false ;
}
if ( hits [ de . subfiles [ j ] ] ! = 0 )
{
error_string = " Double hit on a single node " ;
return false ;
}
hits [ de . subfiles [ j ] ] = 1 ;
}
}
for ( uint32_t i = 0 ; i < hits . size ( ) ; + + i )
if ( hits [ i ] = = 0 )
{
error_string = " Orphean node! " ;
return false ;
}
return true ;
2016-07-24 23:48:22 -04:00
}
2016-07-27 18:48:28 -04:00
void print ( ) const
2016-07-24 23:48:22 -04:00
{
2016-07-27 18:48:28 -04:00
int nfiles = 0 ;
int ndirs = 0 ;
int nempty = 0 ;
int nunknown = 0 ;
for ( uint32_t i = 0 ; i < mNodes . size ( ) ; + + i )
if ( mNodes [ i ] = = NULL )
{
std : : cerr < < " Node " < < i < < " : empty " < < std : : endl ;
+ + nempty ;
}
else if ( mNodes [ i ] - > type ( ) = = FileStorageNode : : TYPE_DIR )
{
std : : cerr < < " Node " < < i < < " : type= " < < mNodes [ i ] - > type ( ) < < std : : endl ;
+ + ndirs ;
}
else if ( mNodes [ i ] - > type ( ) = = FileStorageNode : : TYPE_FILE )
{
std : : cerr < < " Node " < < i < < " : type= " < < mNodes [ i ] - > type ( ) < < std : : endl ;
+ + nfiles ;
}
else
{
+ + nunknown ;
std : : cerr < < " (EE) Error: unknown type node found! " < < std : : endl ;
}
std : : cerr < < " Total nodes: " < < mNodes . size ( ) < < " ( " < < nfiles < < " files, " < < ndirs < < " dirs, " < < nempty < < " empty slots) " < < std : : endl ;
recursPrint ( 0 , DirectoryStorage : : EntryIndex ( 0 ) ) ;
2016-07-24 23:48:22 -04:00
}
private :
2016-07-27 18:48:28 -04:00
void recursPrint ( int depth , DirectoryStorage : : EntryIndex node ) const
{
std : : string indent ( 2 * depth , ' ' ) ;
2016-08-16 07:46:55 -04:00
if ( mNodes [ node ] = = NULL )
{
std : : cerr < < " EMPTY NODE !! " < < std : : endl ;
return ;
}
2016-07-27 18:48:28 -04:00
DirEntry & d ( * static_cast < DirEntry * > ( mNodes [ node ] ) ) ;
2016-08-22 01:49:45 -04:00
std : : cerr < < indent < < " dir: " < < d . dir_name < < " , modf time: " < < d . dir_modtime < < " , recurs_last_modf_time: " < < d . most_recent_time < < " , subdirs: " ;
2016-08-16 17:44:48 -04:00
for ( int i = 0 ; i < d . subdirs . size ( ) ; + + i )
std : : cerr < < d . subdirs [ i ] < < " " ;
std : : cerr < < std : : endl ;
2016-07-27 18:48:28 -04:00
for ( int i = 0 ; i < d . subdirs . size ( ) ; + + i )
recursPrint ( depth + 1 , d . subdirs [ i ] ) ;
for ( int i = 0 ; i < d . subfiles . size ( ) ; + + i )
{
2016-07-28 03:29:15 -04:00
FileEntry & f ( * static_cast < FileEntry * > ( mNodes [ d . subfiles [ i ] ] ) ) ;
2016-07-28 04:49:49 -04:00
std : : cerr < < indent < < " hash: " < < f . file_hash < < " ts: " < < ( uint64_t ) f . file_modtime < < " " < < f . file_size < < " " < < f . file_name < < std : : endl ;
2016-07-27 18:48:28 -04:00
}
}
2016-07-27 15:22:59 -04:00
static bool nodeAccessError ( const std : : string & s )
2016-07-24 23:48:22 -04:00
{
std : : cerr < < " (EE) InternalDirectoryStructure: ERROR: " < < s < < std : : endl ;
return false ;
}
// Removes the given subdirectory from the parent node and all its pendign subdirs. Files are kept, and will go during the cleaning
// phase. That allows to keep file information when moving them around.
bool recursRemoveDirectory ( DirectoryStorage : : EntryIndex dir )
{
DirEntry & d ( * static_cast < DirEntry * > ( mNodes [ dir ] ) ) ;
for ( uint32_t i = 0 ; i < d . subdirs . size ( ) ; + + i )
recursRemoveDirectory ( d . subdirs [ i ] ) ;
delete mNodes [ dir ] ;
mNodes [ dir ] = NULL ;
return true ;
}
2016-07-31 09:59:58 -04:00
2016-08-20 10:23:11 -04:00
std : : map < RsFileHash , DirectoryStorage : : EntryIndex > mHashes ; // used for fast search access. We should try something faster than std::map. hash_map??
2016-07-21 00:16:12 -04:00
} ;
2016-07-24 23:48:22 -04:00
/******************************************************************************************************************/
/* Iterators */
/******************************************************************************************************************/
DirectoryStorage : : DirIterator : : DirIterator ( DirectoryStorage * s , DirectoryStorage : : EntryIndex i )
{
mStorage = s - > mFileHierarchy ;
mParentIndex = i ;
mDirTabIndex = 0 ;
}
DirectoryStorage : : FileIterator : : FileIterator ( DirectoryStorage * s , DirectoryStorage : : EntryIndex i )
{
mStorage = s - > mFileHierarchy ;
mParentIndex = i ;
mFileTabIndex = 0 ;
}
DirectoryStorage : : DirIterator & DirectoryStorage : : DirIterator : : operator + + ( )
{
+ + mDirTabIndex ;
return * this ;
}
DirectoryStorage : : FileIterator & DirectoryStorage : : FileIterator : : operator + + ( )
{
+ + mFileTabIndex ;
return * this ;
}
2016-07-27 15:22:59 -04:00
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 ; }
RsFileHash DirectoryStorage : : FileIterator : : hash ( ) const { const InternalFileHierarchyStorage : : FileEntry * f = mStorage - > getFileEntry ( * * this ) ; return f ? ( f - > file_hash ) : RsFileHash ( ) ; }
uint64_t DirectoryStorage : : FileIterator : : size ( ) const { const InternalFileHierarchyStorage : : FileEntry * f = mStorage - > getFileEntry ( * * this ) ; return f ? ( f - > file_size ) : 0 ; }
std : : string DirectoryStorage : : FileIterator : : name ( ) const { const InternalFileHierarchyStorage : : FileEntry * f = mStorage - > getFileEntry ( * * this ) ; return f ? ( f - > file_name ) : std : : string ( ) ; }
time_t DirectoryStorage : : FileIterator : : modtime ( ) const { const InternalFileHierarchyStorage : : FileEntry * f = mStorage - > getFileEntry ( * * this ) ; return f ? ( f - > file_modtime ) : 0 ; }
2016-07-24 23:48:22 -04:00
2016-08-11 08:07:45 -04:00
std : : string DirectoryStorage : : DirIterator : : name ( ) const { const InternalFileHierarchyStorage : : DirEntry * d = mStorage - > getDirEntry ( * * this ) ; return d ? ( d - > dir_name ) : std : : string ( ) ; }
2016-07-24 23:48:22 -04:00
/******************************************************************************************************************/
/* Directory Storage */
/******************************************************************************************************************/
2016-08-11 08:07:45 -04:00
DirectoryStorage : : DirectoryStorage ( const std : : string & local_file_name , const RsPeerId & pid )
: mFileName ( local_file_name ) , mPeerId ( pid ) , mDirStorageMtx ( " Directory storage " + local_file_name )
2016-07-27 15:22:59 -04:00
{
2016-08-06 13:04:54 -04:00
RS_STACK_MUTEX ( mDirStorageMtx ) ;
2016-07-27 15:22:59 -04:00
mFileHierarchy = new InternalFileHierarchyStorage ( ) ;
}
DirectoryStorage : : EntryIndex DirectoryStorage : : root ( ) const
2016-07-24 23:48:22 -04:00
{
2016-07-27 15:22:59 -04:00
return EntryIndex ( 0 ) ;
2016-07-24 23:48:22 -04:00
}
2016-08-11 08:07:45 -04:00
int DirectoryStorage : : parentRow ( EntryIndex e ) const
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
return mFileHierarchy - > parentRow ( e ) ;
}
uint32_t DirectoryStorage : : getEntryType ( const EntryIndex & indx )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
switch ( mFileHierarchy - > getType ( indx ) )
{
case InternalFileHierarchyStorage : : FileStorageNode : : TYPE_DIR : return DIR_TYPE_DIR ;
case InternalFileHierarchyStorage : : FileStorageNode : : TYPE_FILE : return DIR_TYPE_FILE ;
default :
return DIR_TYPE_UNKNOWN ;
}
}
2016-08-26 10:29:02 -04:00
bool DirectoryStorage : : getDirUpdateTS ( EntryIndex index , time_t & recurs_max_modf_TS , time_t & local_update_TS )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
return mFileHierarchy - > getDirUpdateTS ( index , recurs_max_modf_TS , local_update_TS ) ;
}
bool DirectoryStorage : : setDirUpdateTS ( EntryIndex index , time_t recurs_max_modf_TS , time_t local_update_TS )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
return mFileHierarchy - > setDirUpdateTS ( index , recurs_max_modf_TS , local_update_TS ) ;
}
2016-07-24 23:48:22 -04:00
2016-07-27 15:22:59 -04:00
bool DirectoryStorage : : updateSubDirectoryList ( const EntryIndex & indx , const std : : set < std : : string > & subdirs )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
2016-08-26 10:29:02 -04:00
bool res = mFileHierarchy - > updateSubDirectoryList ( indx , subdirs ) ;
locked_check ( ) ;
return res ;
2016-07-27 15:22:59 -04:00
}
2016-07-28 03:29:15 -04:00
bool DirectoryStorage : : updateSubFilesList ( const EntryIndex & indx , const std : : map < std : : string , FileTS > & subfiles , std : : map < std : : string , FileTS > & new_files )
2016-07-24 23:48:22 -04:00
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
2016-08-26 10:29:02 -04:00
bool res = mFileHierarchy - > updateSubFilesList ( indx , subfiles , new_files ) ;
locked_check ( ) ;
return res ;
2016-07-24 23:48:22 -04:00
}
2016-07-27 15:22:59 -04:00
bool DirectoryStorage : : removeDirectory ( const EntryIndex & indx )
2016-07-24 23:48:22 -04:00
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
2016-08-26 10:29:02 -04:00
bool res = mFileHierarchy - > removeDirectory ( indx ) ;
locked_check ( ) ;
return res ;
}
void DirectoryStorage : : locked_check ( )
{
std : : string error ;
if ( ! mFileHierarchy - > check ( error ) )
std : : cerr < < " Check error: " < < error < < std : : endl ;
2016-07-24 23:48:22 -04:00
}
2016-07-27 15:22:59 -04:00
bool DirectoryStorage : : updateFile ( const EntryIndex & index , const RsFileHash & hash , const std : : string & fname , uint64_t size , time_t modf_time )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
return mFileHierarchy - > updateFile ( index , hash , fname , size , modf_time ) ;
}
bool DirectoryStorage : : updateHash ( const EntryIndex & index , const RsFileHash & hash )
2016-07-24 23:48:22 -04:00
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
2016-07-27 15:22:59 -04:00
return mFileHierarchy - > updateHash ( index , hash ) ;
2016-07-24 23:48:22 -04:00
}
2016-08-20 10:23:11 -04:00
int DirectoryStorage : : searchHash ( const RsFileHash & hash , std : : list < EntryIndex > & results ) const
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
return mFileHierarchy - > searchHash ( hash , results ) ;
}
2016-07-21 00:16:12 -04:00
// static const uint8_t DIRECTORY_STORAGE_TAG_FILE_HASH = 0x01 ;
// static const uint8_t DIRECTORY_STORAGE_TAG_FILE_NAME = 0x02 ;
// static const uint8_t DIRECTORY_STORAGE_TAG_FILE_SIZE = 0x03 ;
// static const uint8_t DIRECTORY_STORAGE_TAG_DIR_NAME = 0x04 ;
// static const uint8_t DIRECTORY_STORAGE_TAG_MODIF_TS = 0x05 ;
// static const uint8_t DIRECTORY_STORAGE_TAG_RECURS_MODIF_TS = 0x06 ;
void DirectoryStorage : : loadNextTag ( const unsigned char * data , uint32_t & offset , uint8_t & entry_tag , uint32_t & entry_size )
{
entry_tag = data [ offset + + ] ;
}
void DirectoryStorage : : saveNextTag ( unsigned char * data , uint32_t & offset , uint8_t entry_tag , uint32_t entry_size )
{
}
void DirectoryStorage : : load ( const std : : string & local_file_name )
{
// first load the header, than all fields.
}
void DirectoryStorage : : save ( const std : : string & local_file_name )
{
// first write the header, than all fields.
}
2016-07-27 18:48:28 -04:00
void DirectoryStorage : : print ( )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
std : : cerr < < " LocalDirectoryStorage: " < < std : : endl ;
mFileHierarchy - > print ( ) ;
}
2016-08-11 08:07:45 -04:00
bool LocalDirectoryStorage : : getFileInfo ( DirectoryStorage : : EntryIndex i , FileInfo & info )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
# warning todo
return true ;
}
2016-08-16 17:44:48 -04:00
bool DirectoryStorage : : extractData ( const EntryIndex & indx , DirDetails & d )
{
d . children . clear ( ) ;
time_t now = time ( NULL ) ;
std : : cerr < < " LocalDirectoryStorage::extractData(). Index= " < < indx < < std : : endl ;
const InternalFileHierarchyStorage : : DirEntry * dir_entry = mFileHierarchy - > getDirEntry ( indx ) ;
2016-08-19 12:49:42 -04:00
d . ref = ( void * ) ( intptr_t ) indx ;
2016-08-16 17:44:48 -04:00
if ( dir_entry ! = NULL ) /* has children --- fill */
{
# ifdef DEBUG_DIRECTORY_STORAGE
std : : cerr < < " FileIndex::extractData() ref=dir " < < std : : endl ;
# endif
/* extract all the entries */
for ( DirectoryStorage : : DirIterator it ( this , indx ) ; it ; + + it )
{
DirStub stub ;
stub . type = DIR_TYPE_DIR ;
stub . name = it . name ( ) ;
stub . ref = ( void * ) ( intptr_t ) * it ; // this is updated by the caller, who knows which friend we're dealing with
d . children . push_back ( stub ) ;
}
for ( DirectoryStorage : : FileIterator it ( this , indx ) ; it ; + + it )
{
DirStub stub ;
stub . type = DIR_TYPE_FILE ;
stub . name = it . name ( ) ;
stub . ref = ( void * ) ( intptr_t ) * it ;
d . children . push_back ( stub ) ;
}
d . type = DIR_TYPE_DIR ;
d . hash . clear ( ) ;
d . count = dir_entry - > subdirs . size ( ) + dir_entry - > subfiles . size ( ) ;
d . min_age = now - dir_entry - > most_recent_time ;
d . name = dir_entry - > dir_name ;
d . path = dir_entry - > dir_parent_path + " / " + dir_entry - > dir_name ;
d . parent = ( void * ) ( intptr_t ) dir_entry - > parent_index ;
if ( indx = = 0 )
{
d . type = DIR_TYPE_PERSON ;
d . name = mPeerId . toStdString ( ) ;
}
}
else
{
const InternalFileHierarchyStorage : : FileEntry * file_entry = mFileHierarchy - > getFileEntry ( indx ) ;
# ifdef DEBUG_DIRECTORY_STORAGE
std : : cerr < < " FileIndexStore::extractData() ref=file " < < std : : endl ;
# endif
d . type = DIR_TYPE_FILE ;
d . count = file_entry - > file_size ;
d . min_age = now - file_entry - > file_modtime ;
d . name = file_entry - > file_name ;
d . hash = file_entry - > file_hash ;
d . age = now - file_entry - > file_modtime ;
d . parent = ( void * ) ( intptr_t ) file_entry - > parent_index ;
const InternalFileHierarchyStorage : : DirEntry * parent_dir_entry = mFileHierarchy - > getDirEntry ( file_entry - > parent_index ) ;
if ( parent_dir_entry ! = NULL )
d . path = parent_dir_entry - > dir_parent_path + " / " + parent_dir_entry - > dir_name + " / " ;
else
d . path = " " ;
}
d . flags . clear ( ) ;
return true ;
}
2016-07-27 15:22:59 -04:00
/******************************************************************************************************************/
/* Local Directory Storage */
/******************************************************************************************************************/
void LocalDirectoryStorage : : setSharedDirectoryList ( const std : : list < SharedDirInfo > & lst )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
2016-07-31 09:59:58 -04:00
2016-08-06 13:04:54 -04:00
// Chose virtual name if not supplied, and remove duplicates.
std : : set < std : : string > virtual_names ; // maps virtual to real name
std : : list < SharedDirInfo > processed_list ;
2016-07-31 09:59:58 -04:00
for ( std : : list < SharedDirInfo > : : const_iterator it ( lst . begin ( ) ) ; it ! = lst . end ( ) ; + + it )
2016-08-06 13:04:54 -04:00
{
int i = 0 ;
std : : string candidate_virtual_name = it - > virtualname ;
if ( candidate_virtual_name . empty ( ) )
candidate_virtual_name = RsDirUtil : : getTopDir ( it - > filename ) ;
while ( virtual_names . find ( candidate_virtual_name ) ! = virtual_names . end ( ) )
rs_sprintf_append ( candidate_virtual_name , " -%d " , + + i ) ;
SharedDirInfo d ( * it ) ;
d . virtualname = candidate_virtual_name ;
processed_list . push_back ( d ) ;
virtual_names . insert ( candidate_virtual_name ) ;
}
mLocalDirs . clear ( ) ;
for ( std : : list < SharedDirInfo > : : const_iterator it ( processed_list . begin ( ) ) ; it ! = processed_list . end ( ) ; + + it )
mLocalDirs [ it - > filename ] = * it ;
2016-07-27 15:22:59 -04:00
}
void LocalDirectoryStorage : : getSharedDirectoryList ( std : : list < SharedDirInfo > & lst )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
2016-07-31 09:59:58 -04:00
lst . clear ( ) ;
for ( std : : map < std : : string , SharedDirInfo > : : iterator it ( mLocalDirs . begin ( ) ) ; it ! = mLocalDirs . end ( ) ; + + it )
lst . push_back ( it - > second ) ;
}
void LocalDirectoryStorage : : updateShareFlags ( const SharedDirInfo & info )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
std : : map < std : : string , SharedDirInfo > : : iterator it = mLocalDirs . find ( info . virtualname ) ;
if ( it = = mLocalDirs . end ( ) )
{
std : : cerr < < " (EE) LocalDirectoryStorage::updateShareFlags: directory \" " < < info . filename < < " \" not found " < < std : : endl ;
return ;
}
it - > second = info ;
2016-07-27 15:22:59 -04:00
}
2016-07-31 09:59:58 -04:00
bool LocalDirectoryStorage : : convertSharedFilePath ( const std : : string & path , std : : string & fullpath )
{
std : : string shpath = RsDirUtil : : removeRootDir ( path ) ;
std : : string basedir = RsDirUtil : : getRootDir ( path ) ;
std : : string realroot ;
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
realroot = locked_findRealRootFromVirtualFilename ( basedir ) ;
}
if ( realroot . empty ( ) )
return false ;
/* construct full name */
fullpath = realroot + " / " ;
fullpath + = shpath ;
return true ;
}
2016-08-22 01:49:45 -04:00
void LocalDirectoryStorage : : updateTimeStamps ( )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
time_t last_modf_time = mFileHierarchy - > recursUpdateLastModfTime ( EntryIndex ( 0 ) ) ;
std : : cerr < < " LocalDirectoryStorage: global last modf time is " < < last_modf_time < < " (which is " < < time ( NULL ) - last_modf_time < < " secs ago) " < < std : : endl ;
}
2016-07-31 09:59:58 -04:00
std : : string LocalDirectoryStorage : : locked_findRealRootFromVirtualFilename ( const std : : string & virtual_rootdir ) const
{
/**** MUST ALREADY BE LOCKED ****/
std : : map < std : : string , SharedDirInfo > : : const_iterator cit = mLocalDirs . find ( virtual_rootdir ) ;
if ( cit = = mLocalDirs . end ( ) )
{
std : : cerr < < " FileIndexMonitor::locked_findRealRoot() Invalid RootDir: " < < virtual_rootdir < < std : : endl ;
return std : : string ( ) ;
}
return cit - > second . filename ;
}
2016-08-11 08:07:45 -04:00
bool LocalDirectoryStorage : : extractData ( const EntryIndex & indx , DirDetails & d )
2016-07-31 09:59:58 -04:00
{
2016-08-16 17:44:48 -04:00
bool res = DirectoryStorage : : extractData ( indx , d ) ;
2016-08-11 08:07:45 -04:00
2016-08-16 17:44:48 -04:00
if ( ! res )
return false ;
2016-08-11 08:07:45 -04:00
2016-08-16 17:44:48 -04:00
// here we should update the file sharing flags
2016-08-11 08:07:45 -04:00
d . flags . clear ( ) ;
/* find parent pointer, and row */
return true ;
}
2016-08-26 10:29:02 -04:00
bool LocalDirectoryStorage : : serialiseDirEntry ( const EntryIndex & indx , RsTlvBinaryData & bindata )
{
RS_STACK_MUTEX ( mDirStorageMtx ) ;
const InternalFileHierarchyStorage : : DirEntry * dir = mFileHierarchy - > getDirEntry ( indx ) ;
if ( dir = = NULL )
{
std : : cerr < < " (EE) serialiseDirEntry: ERROR. Cannot find entry " < < ( void * ) ( intptr_t ) indx < < std : : endl ;
return false ;
}
unsigned char * section_data = NULL ;
uint32_t section_size = 0 ;
uint32_t section_offset = 0 ;
// 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 ( ! FileListIO : : writeField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_DIR_NAME , dir - > dir_name ) ) return false ;
if ( ! FileListIO : : writeField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_RECURS_MODIF_TS , dir - > most_recent_time ) ) return false ;
2016-08-27 08:09:26 -04:00
if ( ! FileListIO : : writeField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_MODIF_TS , dir - > dir_modtime ) ) return false ;
2016-08-26 10:29:02 -04:00
// serialise number of subdirs and number of subfiles
if ( ! FileListIO : : writeField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_RAW_NUMBER , dir - > subdirs . size ( ) ) ) return false ;
if ( ! FileListIO : : writeField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_RAW_NUMBER , dir - > subfiles . size ( ) ) ) return false ;
// serialise subdirs entry indexes
for ( uint32_t i = 0 ; i < dir - > subdirs . size ( ) ; + + i )
if ( ! FileListIO : : writeField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_ENTRY_INDEX , dir - > subdirs [ i ] ) ) return false ;
// serialise directory subfiles, with info for each of them
for ( uint32_t i = 0 ; i < dir - > subfiles . size ( ) ; + + i )
{
unsigned char * file_section_data = NULL ;
uint32_t file_section_offset = 0 ;
uint32_t file_section_size = 0 ;
const InternalFileHierarchyStorage : : FileEntry * file = mFileHierarchy - > getFileEntry ( dir - > subfiles [ i ] ) ;
if ( file = = NULL )
{
std : : cerr < < " (EE) cannot reach 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_ENTRY_INDEX , dir - > subfiles [ i ] ) ) return false ;
if ( ! FileListIO : : writeField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_FILE_NAME , file - > file_name ) ) return false ;
if ( ! FileListIO : : writeField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_FILE_SIZE , file - > file_size ) ) return false ;
if ( ! FileListIO : : writeField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_FILE_SHA1_HASH , file - > file_hash ) ) return false ;
if ( ! FileListIO : : writeField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_MODIF_TS , file - > file_modtime ) ) 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 ) ) return false ;
free ( file_section_data ) ;
}
std : : cerr < < " Serialised dir entry to send for entry index " < < ( void * ) ( intptr_t ) indx < < " . Data size is " < < section_size < < " bytes " < < std : : endl ;
return true ;
}
/******************************************************************************************************************/
/* Remote Directory Storage */
/******************************************************************************************************************/
bool RemoteDirectoryStorage : : deserialiseDirEntry ( const EntryIndex & indx , const RsTlvBinaryData & bindata )
{
2016-08-27 08:09:26 -04:00
const unsigned char * section_data = ( unsigned char * ) bindata . bin_data ;
uint32_t section_size = bindata . bin_len ;
uint32_t section_offset ;
2016-08-26 10:29:02 -04:00
std : : cerr < < " RemoteDirectoryStorage::deserialiseDirEntry(): deserialising directory content for friend " < < peerId ( ) < < " , and directory " < < indx < < std : : endl ;
2016-08-27 08:09:26 -04:00
std : : string dir_name ;
time_t most_recent_time , dir_modtime ;
if ( ! FileListIO : : readField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_DIR_NAME , dir_name ) ) return false ;
if ( ! FileListIO : : readField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_RECURS_MODIF_TS , most_recent_time ) ) return false ;
if ( ! FileListIO : : readField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_MODIF_TS , dir_modtime ) ) return false ;
// serialise number of subdirs and number of subfiles
uint32_t n_subdirs , n_subfiles ;
if ( ! FileListIO : : readField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_RAW_NUMBER , n_subdirs ) ) return false ;
if ( ! FileListIO : : readField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_RAW_NUMBER , n_subfiles ) ) return false ;
// serialise subdirs entry indexes
std : : vector < EntryIndex > subdirs_array ;
uint32_t subdir_index ;
for ( uint32_t i = 0 ; i < n_subdirs ; + + i )
{
if ( ! FileListIO : : readField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_ENTRY_INDEX , subdir_index ) ) return false ;
subdirs_array . push_back ( EntryIndex ( subdir_index ) ) ;
}
// deserialise directory subfiles, with info for each of them
std : : vector < EntryIndex > subfiles_array ;
std : : vector < std : : string > subfiles_name ;
std : : vector < uint64_t > subfiles_size ;
std : : vector < RsFileHash > subfiles_hash ;
std : : vector < time_t > subfiles_modtime ;
for ( uint32_t i = 0 ; i < n_subfiles ; + + i )
{
// Read the full data section for the file
unsigned char * file_section_data = NULL ;
uint32_t file_section_size = 0 ;
if ( ! FileListIO : : readField ( section_data , section_size , section_offset , FILE_LIST_IO_TAG_REMOTE_FILE_ENTRY , file_section_data , file_section_size ) ) return false ;
uint32_t file_section_offset = 0 ;
uint32_t entry_index ;
std : : string entry_name ;
uint64_t entry_size ;
RsFileHash entry_hash ;
time_t entry_modtime ;
if ( ! FileListIO : : readField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_ENTRY_INDEX , entry_index ) ) return false ;
if ( ! FileListIO : : readField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_FILE_NAME , entry_name ) ) return false ;
if ( ! FileListIO : : readField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_FILE_SIZE , entry_size ) ) return false ;
if ( ! FileListIO : : readField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_FILE_SHA1_HASH , entry_hash ) ) return false ;
if ( ! FileListIO : : readField ( file_section_data , file_section_size , file_section_offset , FILE_LIST_IO_TAG_MODIF_TS , entry_modtime ) ) return false ;
free ( file_section_data ) ;
subfiles_array . push_back ( entry_index ) ;
subfiles_name . push_back ( entry_name ) ;
subfiles_size . push_back ( entry_size ) ;
subfiles_hash . push_back ( entry_hash ) ;
subfiles_modtime . push_back ( entry_modtime ) ;
}
RS_STACK_MUTEX ( mDirStorageMtx ) ;
// first create the entries for each subdir and each subfile.
if ( ! mFileHierarchy - > updateDirEntry ( indx , dir_name , most_recent_time , dir_modtime , subdirs_array , subfiles_array ) )
{
std : : cerr < < " (EE) Cannot update dir entry with index " < < indx < < " : entry does not exist. " < < std : : endl ;
return false ;
}
// then update the subfiles
for ( uint32_t i = 0 ; i < subfiles_array . size ( ) ; + + i )
if ( ! mFileHierarchy - > updateFile ( subfiles_array [ i ] , subfiles_hash [ i ] , subfiles_name [ i ] , subfiles_size [ i ] , subfiles_modtime [ i ] ) )
std : : cerr < < " (EE) Cannot update file with index " < < subfiles_array [ i ] < < " . This is very weird. Entry should have just been created and therefore should exist. Skipping. " < < std : : endl ;
2016-08-26 10:29:02 -04:00
return true ;
}