2016-09-12 18:01:26 -04:00
/*
* RetroShare Directory watching system .
*
* file_sharing / directory_updater . cc
*
* Copyright 2016 Mr . Alice
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " retroshare.project@gmail.com " .
*
*/
2016-07-23 22:14:43 -04:00
# include "util/folderiterator.h"
2016-08-06 13:04:54 -04:00
# include "rsserver/p3face.h"
2016-07-23 22:14:43 -04:00
2016-07-20 16:11:26 -04:00
# include "directory_storage.h"
# include "directory_updater.h"
2016-09-01 15:04:48 -04:00
# include "file_sharing_defaults.h"
2016-07-20 16:11:26 -04:00
2016-09-18 16:05:27 -04:00
//#define DEBUG_LOCAL_DIR_UPDATER 1
2016-07-23 22:14:43 -04:00
2016-08-20 10:23:11 -04:00
//=============================================================================================================//
// Local Directory Updater //
//=============================================================================================================//
2016-07-28 04:49:49 -04:00
2016-07-27 18:48:28 -04:00
LocalDirectoryUpdater : : LocalDirectoryUpdater ( HashStorage * hc , LocalDirectoryStorage * lds )
: mHashCache ( hc ) , mSharedDirectories ( lds )
2016-07-21 00:16:12 -04:00
{
2016-07-28 04:49:49 -04:00
mLastSweepTime = 0 ;
2016-08-22 01:49:45 -04:00
mLastTSUpdateTime = 0 ;
2016-09-01 15:04:48 -04:00
mDelayBetweenDirectoryUpdates = DELAY_BETWEEN_DIRECTORY_UPDATES ;
2016-09-18 12:34:39 -04:00
mIsEnabled = false ;
2016-11-24 17:42:56 -05:00
mFollowSymLinks = FOLLOW_SYMLINKS_DEFAULT ;
2016-12-02 13:02:41 -05:00
// Can be left to false, but setting it to true will force to re-hash any file that has been left unhashed in the last session.
mNeedsFullRecheck = true ;
2016-09-18 12:34:39 -04:00
}
bool LocalDirectoryUpdater : : isEnabled ( ) const
{
return mIsEnabled ;
}
void LocalDirectoryUpdater : : setEnabled ( bool b )
{
if ( mIsEnabled = = b )
return ;
2016-11-07 04:09:28 -05:00
if ( ! b )
2016-09-18 12:34:39 -04:00
shutdown ( ) ;
2016-11-07 04:09:28 -05:00
else if ( ! isRunning ( ) )
start ( " fs dir updater " ) ;
2016-09-18 12:34:39 -04:00
mIsEnabled = b ;
2016-07-28 04:49:49 -04:00
}
void LocalDirectoryUpdater : : data_tick ( )
{
time_t now = time ( NULL ) ;
2016-09-18 12:34:39 -04:00
if ( now > mDelayBetweenDirectoryUpdates + mLastSweepTime )
2016-07-28 04:49:49 -04:00
{
sweepSharedDirectories ( ) ;
2016-11-25 14:50:10 -05:00
2016-12-02 13:02:41 -05:00
mNeedsFullRecheck = false ;
2016-07-28 04:49:49 -04:00
mLastSweepTime = now ;
2016-09-18 12:34:39 -04:00
mSharedDirectories - > notifyTSChanged ( ) ;
2016-07-28 04:49:49 -04:00
}
2016-08-22 01:49:45 -04:00
if ( now > DELAY_BETWEEN_LOCAL_DIRECTORIES_TS_UPDATE + mLastTSUpdateTime )
{
mSharedDirectories - > updateTimeStamps ( ) ;
mLastTSUpdateTime = now ;
}
usleep ( 10 * 1000 * 1000 ) ;
2016-07-21 00:16:12 -04:00
}
2016-08-06 13:04:54 -04:00
void LocalDirectoryUpdater : : forceUpdate ( )
{
mLastSweepTime = 0 ;
}
2016-07-28 04:49:49 -04:00
void LocalDirectoryUpdater : : sweepSharedDirectories ( )
2016-07-20 16:11:26 -04:00
{
2016-10-12 17:20:38 -04:00
if ( mHashSalt . isNull ( ) )
{
std : : cerr < < " (EE) no salt value in LocalDirectoryUpdater. Is that a bug? " < < std : : endl ;
return ;
}
2016-08-06 13:04:54 -04:00
RsServer : : notify ( ) - > notifyListPreChange ( NOTIFY_LIST_DIRLIST_LOCAL , 0 ) ;
2016-09-18 16:05:27 -04:00
# ifdef DEBUG_LOCAL_DIR_UPDATER
std : : cerr < < " [directory storage] LocalDirectoryUpdater::sweep() " < < std : : endl ;
# endif
2016-07-23 22:14:43 -04:00
2016-10-12 17:20:38 -04:00
// recursive update algorithm works that way:
// - the external loop starts on the shared directory list and goes through sub-directories
2016-07-21 00:16:12 -04:00
// - at the same time, it updates the local list of shared directories. A single sweep is performed over the whole directory structure.
2016-10-12 17:20:38 -04:00
// - the information that is costly to compute (the hash) is store externally into a separate structure.
// - doing so, changing directory names or moving files between directories does not cause a re-hash of the content.
//
2016-07-21 00:16:12 -04:00
std : : list < SharedDirInfo > shared_directory_list ;
2016-07-27 18:48:28 -04:00
mSharedDirectories - > getSharedDirectoryList ( shared_directory_list ) ;
2016-07-24 23:48:22 -04:00
2016-11-21 10:14:11 -05:00
std : : set < std : : string > sub_dir_list ;
2016-07-21 00:16:12 -04:00
2016-12-01 17:27:15 -05:00
// We re-check that each dir actually exists. It might have been removed from the disk.
2016-07-23 22:14:43 -04:00
for ( std : : list < SharedDirInfo > : : const_iterator real_dir_it ( shared_directory_list . begin ( ) ) ; real_dir_it ! = shared_directory_list . end ( ) ; + + real_dir_it )
2016-12-01 17:27:15 -05:00
if ( RsDirUtil : : checkDirectory ( ( * real_dir_it ) . filename ) )
sub_dir_list . insert ( ( * real_dir_it ) . filename ) ;
2016-07-21 00:16:12 -04:00
// make sure that entries in stored_dir_it are the same than paths in real_dir_it, and in the same order.
2016-10-12 17:20:38 -04:00
mSharedDirectories - > updateSubDirectoryList ( mSharedDirectories - > root ( ) , sub_dir_list , mHashSalt ) ;
2016-07-21 00:16:12 -04:00
// now for each of them, go recursively and match both files and dirs
2016-11-24 17:42:56 -05:00
std : : set < std : : string > existing_dirs ;
2016-08-17 08:48:54 -04:00
for ( DirectoryStorage : : DirIterator stored_dir_it ( mSharedDirectories , mSharedDirectories - > root ( ) ) ; stored_dir_it ; + + stored_dir_it )
2016-07-27 18:48:28 -04:00
{
2016-09-18 16:05:27 -04:00
# ifdef DEBUG_LOCAL_DIR_UPDATER
std : : cerr < < " [directory storage] recursing into " < < stored_dir_it . name ( ) < < std : : endl ;
# endif
2016-08-17 08:48:54 -04:00
2016-11-24 17:42:56 -05:00
recursUpdateSharedDir ( stored_dir_it . name ( ) , * stored_dir_it , existing_dirs ) ; // here we need to use the list that was stored, instead of the shared dir list, because the two
2016-08-17 08:48:54 -04:00
// are not necessarily in the same order.
2016-07-27 18:48:28 -04:00
}
2016-11-25 14:50:10 -05:00
2016-08-06 13:04:54 -04:00
RsServer : : notify ( ) - > notifyListChange ( NOTIFY_LIST_DIRLIST_LOCAL , 0 ) ;
2016-07-21 00:16:12 -04:00
}
2016-11-24 17:42:56 -05:00
void LocalDirectoryUpdater : : recursUpdateSharedDir ( const std : : string & cumulated_path , DirectoryStorage : : EntryIndex indx , std : : set < std : : string > & existing_directories )
2016-07-21 00:16:12 -04:00
{
2016-09-18 16:05:27 -04:00
# ifdef DEBUG_LOCAL_DIR_UPDATER
std : : cerr < < " [directory storage] parsing directory " < < cumulated_path < < " , index= " < < indx < < std : : endl ;
# endif
2016-07-21 00:16:12 -04:00
2016-11-24 17:42:56 -05:00
if ( mFollowSymLinks )
{
std : : string real_path = RsDirUtil : : removeSymLinks ( cumulated_path ) ;
if ( existing_directories . end ( ) ! = existing_directories . find ( real_path ) )
{
2016-11-25 14:33:27 -05:00
std : : cerr < < " (WW) Directory " < < cumulated_path < < " has real path " < < real_path < < " which already belongs to another shared directory. Ignoring " < < std : : endl ;
2016-11-24 17:42:56 -05:00
return ;
}
existing_directories . insert ( real_path ) ;
}
2016-07-23 22:14:43 -04:00
// make sure list of subdirs is the same
2016-07-21 00:16:12 -04:00
// make sure list of subfiles is the same
// request all hashes to the hashcache
2016-11-24 17:42:56 -05:00
librs : : util : : FolderIterator dirIt ( cumulated_path , mFollowSymLinks , false ) ; // disallow symbolic links and files from the future.
2016-07-21 00:16:12 -04:00
2016-10-05 04:59:51 -04:00
time_t dir_local_mod_time ;
if ( ! mSharedDirectories - > getDirectoryLocalModTime ( indx , dir_local_mod_time ) )
{
std : : cerr < < " (EE) Cannot get local mod time for dir index " < < indx < < std : : endl ;
return ;
}
2016-07-21 00:16:12 -04:00
2016-12-02 13:02:41 -05:00
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.
2016-11-25 14:50:10 -05:00
// we only want to detect when the directory has changed on the disk
2016-07-21 00:16:12 -04:00
{
2016-10-05 04:59:51 -04:00
// collect subdirs and subfiles
std : : map < std : : string , DirectoryStorage : : FileTS > subfiles ;
2016-11-21 10:14:11 -05:00
std : : set < std : : string > subdirs ;
2016-10-05 04:59:51 -04:00
for ( ; dirIt . isValid ( ) ; dirIt . next ( ) )
{
switch ( dirIt . file_type ( ) )
{
case librs : : util : : FolderIterator : : TYPE_FILE : subfiles [ dirIt . file_name ( ) ] . modtime = dirIt . file_modtime ( ) ;
subfiles [ dirIt . file_name ( ) ] . size = dirIt . file_size ( ) ;
2016-09-18 16:05:27 -04:00
# ifdef DEBUG_LOCAL_DIR_UPDATER
2016-10-05 04:59:51 -04:00
std : : cerr < < " adding sub-file \" " < < dirIt . file_name ( ) < < " \" " < < std : : endl ;
2016-09-18 16:05:27 -04:00
# endif
2016-10-05 04:59:51 -04:00
break ;
2016-07-23 22:14:43 -04:00
2016-11-21 10:14:11 -05:00
case librs : : util : : FolderIterator : : TYPE_DIR : subdirs . insert ( dirIt . file_name ( ) ) ;
2016-09-18 16:05:27 -04:00
# ifdef DEBUG_LOCAL_DIR_UPDATER
2016-10-05 04:59:51 -04:00
std : : cerr < < " adding sub-dir \" " < < dirIt . file_name ( ) < < " \" " < < std : : endl ;
2016-09-18 16:05:27 -04:00
# endif
2016-10-05 04:59:51 -04:00
break ;
default :
std : : cerr < < " (EE) Dir entry of unknown type with path \" " < < cumulated_path < < " / " < < dirIt . file_name ( ) < < " \" " < < std : : endl ;
}
}
// update folder modificatoin time, which is the only way to detect e.g. removed or renamed files.
2016-09-15 15:45:00 -04:00
2016-10-05 04:59:51 -04:00
mSharedDirectories - > setDirectoryLocalModTime ( indx , dirIt . dir_modtime ( ) ) ;
2016-09-15 15:45:00 -04:00
2016-10-05 04:59:51 -04:00
// update file and dir lists for current directory.
2016-07-21 00:16:12 -04:00
2016-10-12 17:20:38 -04:00
mSharedDirectories - > updateSubDirectoryList ( indx , subdirs , mHashSalt ) ;
2016-07-24 23:48:22 -04:00
2016-10-05 04:59:51 -04:00
std : : map < std : : string , DirectoryStorage : : FileTS > new_files ;
mSharedDirectories - > updateSubFilesList ( indx , subfiles , new_files ) ;
2016-07-21 00:16:12 -04:00
2016-10-05 04:59:51 -04:00
// now go through list of subfiles and request the hash to hashcache
2016-07-21 00:16:12 -04:00
2016-10-05 04:59:51 -04:00
for ( DirectoryStorage : : FileIterator dit ( mSharedDirectories , indx ) ; dit ; + + dit )
{
// ask about the hash. If not present, ask HashCache. If not present, or different, the callback will update it.
2016-07-21 00:16:12 -04:00
2016-10-05 04:59:51 -04:00
RsFileHash hash ;
2016-07-27 15:22:59 -04:00
2016-10-05 04:59:51 -04:00
if ( mHashCache - > requestHash ( cumulated_path + " / " + dit . name ( ) , dit . size ( ) , dit . modtime ( ) , hash , this , * dit ) & & dit . hash ( ) ! = hash )
mSharedDirectories - > updateHash ( * dit , hash ) ;
}
2016-07-21 00:16:12 -04:00
}
2016-10-05 04:59:51 -04:00
# ifdef DEBUG_LOCAL_DIR_UPDATER
else
std : : cerr < < " directory is unchanged. Keeping existing files and subdirs list. " < < std : : endl ;
# endif
2016-07-21 00:16:12 -04:00
// go through the list of sub-dirs and recursively update
2016-10-05 04:59:51 -04:00
for ( DirectoryStorage : : DirIterator stored_dir_it ( mSharedDirectories , indx ) ; stored_dir_it ; + + stored_dir_it )
2016-08-17 08:48:54 -04:00
{
2016-09-18 16:05:27 -04:00
# ifdef DEBUG_LOCAL_DIR_UPDATER
2016-08-17 08:48:54 -04:00
std : : cerr < < " recursing into " < < stored_dir_it . name ( ) < < std : : endl ;
2016-09-18 16:05:27 -04:00
# endif
2016-11-24 17:42:56 -05:00
recursUpdateSharedDir ( cumulated_path + " / " + stored_dir_it . name ( ) , * stored_dir_it , existing_directories ) ;
2016-08-17 08:48:54 -04:00
}
2016-07-20 16:11:26 -04:00
}
2016-07-21 00:16:12 -04:00
2016-09-14 14:41:22 -04:00
bool LocalDirectoryUpdater : : inDirectoryCheck ( ) const
{
return mHashCache - > isRunning ( ) ;
}
2016-09-27 03:50:59 -04:00
void LocalDirectoryUpdater : : hash_callback ( uint32_t client_param , const std : : string & /*name*/ , const RsFileHash & hash , uint64_t /*size*/ )
2016-07-27 15:22:59 -04:00
{
if ( ! mSharedDirectories - > updateHash ( DirectoryStorage : : EntryIndex ( client_param ) , hash ) )
std : : cerr < < " (EE) Cannot update file. Something's wrong. " < < std : : endl ;
2016-09-18 12:34:39 -04:00
mSharedDirectories - > notifyTSChanged ( ) ;
2016-07-27 15:22:59 -04:00
}
2016-08-22 01:49:45 -04:00
2016-09-18 12:34:39 -04:00
bool LocalDirectoryUpdater : : hash_confirm ( uint32_t client_param )
{
return mSharedDirectories - > getEntryType ( DirectoryStorage : : EntryIndex ( client_param ) ) = = DIR_TYPE_FILE ;
}
2016-08-22 01:49:45 -04:00
2016-09-18 12:34:39 -04:00
void LocalDirectoryUpdater : : setFileWatchPeriod ( int seconds )
{
mDelayBetweenDirectoryUpdates = seconds ;
}
uint32_t LocalDirectoryUpdater : : fileWatchPeriod ( ) const
{
return mDelayBetweenDirectoryUpdates ;
}
2016-08-22 01:49:45 -04:00
2016-11-24 17:42:56 -05:00
void LocalDirectoryUpdater : : setFollowSymLinks ( bool b )
{
2016-11-25 14:50:10 -05:00
if ( b ! = mFollowSymLinks )
2016-12-02 13:02:41 -05:00
mNeedsFullRecheck = true ;
2016-11-25 14:50:10 -05:00
2016-11-24 17:42:56 -05:00
mFollowSymLinks = b ;
2016-11-25 14:50:10 -05:00
forceUpdate ( ) ;
2016-11-24 17:42:56 -05:00
}
bool LocalDirectoryUpdater : : followSymLinks ( ) const
{
return mFollowSymLinks ;
}
2016-08-22 01:49:45 -04:00