This commit is contained in:
Shauren
2025-10-11 14:31:13 +02:00
parent 35c1d2e989
commit 8fcec26917
39 changed files with 625 additions and 752 deletions

View File

@@ -10,7 +10,7 @@ Boost Process (Proposed for boost, but its not an official part of it yet. Used
efsw (Entropia File System Watcher - crossplatform file system watcher)
https://github.com/SpartanJ/efsw
Version: 1.3.1+ 36c1c7004a34b6f40719f0830bcfb10325415451
Version: 1.5.0+ f94a6616aba85fc9375fdff7ee69609d223a0672
fmt (a small, safe and fast formatting library)
https://github.com/fmtlib/fmt

View File

@@ -22,14 +22,12 @@ if (BUILD_SHARED_LIBS)
src/efsw/FileWatcherImpl.hpp
src/efsw/Lock.hpp
src/efsw/Log.cpp
src/efsw/Mutex.cpp
src/efsw/Mutex.hpp
src/efsw/sophist.h
src/efsw/String.cpp
src/efsw/String.hpp
src/efsw/System.cpp
src/efsw/System.hpp
src/efsw/Thread.cpp
src/efsw/Thread.hpp
src/efsw/Utf.hpp
src/efsw/Watcher.cpp
@@ -43,22 +41,14 @@ if (BUILD_SHARED_LIBS)
list (APPEND EFSW_CPP_SOURCE
src/efsw/platform/win/FileSystemImpl.cpp
src/efsw/platform/win/FileSystemImpl.hpp
src/efsw/platform/win/MutexImpl.cpp
src/efsw/platform/win/MutexImpl.hpp
src/efsw/platform/win/SystemImpl.cpp
src/efsw/platform/win/SystemImpl.hpp
src/efsw/platform/win/ThreadImpl.cpp
src/efsw/platform/win/ThreadImpl.hpp)
src/efsw/platform/win/SystemImpl.hpp)
else ()
list (APPEND EFSW_CPP_SOURCE
src/efsw/platform/posix/FileSystemImpl.cpp
src/efsw/platform/posix/FileSystemImpl.hpp
src/efsw/platform/posix/MutexImpl.cpp
src/efsw/platform/posix/MutexImpl.hpp
src/efsw/platform/posix/SystemImpl.cpp
src/efsw/platform/posix/SystemImpl.hpp
src/efsw/platform/posix/ThreadImpl.cpp
src/efsw/platform/posix/ThreadImpl.hpp)
src/efsw/platform/posix/SystemImpl.hpp)
endif()
if (APPLE)

View File

@@ -1,7 +1,7 @@
/**
@author Sepul Sepehr Taghdisian
Copyright (c) 2013 Martin Lucas Golini
Copyright (c) 2024 Martín Lucas Golini
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -32,31 +32,31 @@
extern "C" {
#endif
#if defined(_WIN32)
#ifdef EFSW_DYNAMIC
// Windows platforms
#ifdef EFSW_EXPORTS
// From DLL side, we must export
#define EFSW_API __declspec(dllexport)
#else
// From client application side, we must import
#define EFSW_API __declspec(dllimport)
#endif
#else
// No specific directive needed for static build
#ifndef EFSW_API
#define EFSW_API
#endif
#endif
#if defined( _WIN32 )
#ifdef EFSW_DYNAMIC
// Windows platforms
#ifdef EFSW_EXPORTS
// From DLL side, we must export
#define EFSW_API __declspec( dllexport )
#else
#if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS )
#define EFSW_API __attribute__ ((visibility("default")))
#endif
// From client application side, we must import
#define EFSW_API __declspec( dllimport )
#endif
#else
// No specific directive needed for static build
#ifndef EFSW_API
#define EFSW_API
#endif
#endif
#else
#if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS )
#define EFSW_API __attribute__( ( visibility( "default" ) ) )
#endif
// Other platforms don't need to define anything
#ifndef EFSW_API
#define EFSW_API
#endif
// Other platforms don't need to define anything
#ifndef EFSW_API
#define EFSW_API
#endif
#endif
/// Type for a watch id
@@ -65,27 +65,24 @@ typedef long efsw_watchid;
/// Type for watcher
typedef void* efsw_watcher;
enum efsw_action
{
EFSW_ADD = 1, /// Sent when a file is created or renamed
EFSW_DELETE = 2, /// Sent when a file is deleted or renamed
EFSW_MODIFIED = 3, /// Sent when a file is modified
EFSW_MOVED = 4 /// Sent when a file is moved
enum efsw_action {
EFSW_ADD = 1, /// Sent when a file is created or renamed
EFSW_DELETE = 2, /// Sent when a file is deleted or renamed
EFSW_MODIFIED = 3, /// Sent when a file is modified
EFSW_MOVED = 4 /// Sent when a file is moved
};
enum efsw_error
{
EFSW_NOTFOUND = -1,
EFSW_REPEATED = -2,
EFSW_OUTOFSCOPE = -3,
EFSW_NOTREADABLE = -4,
EFSW_REMOTE = -5,
EFSW_WATCHER_FAILED = -6,
EFSW_UNSPECIFIED = -7
enum efsw_error {
EFSW_NOTFOUND = -1,
EFSW_REPEATED = -2,
EFSW_OUTOFSCOPE = -3,
EFSW_NOTREADABLE = -4,
EFSW_REMOTE = -5,
EFSW_WATCHER_FAILED = -6,
EFSW_UNSPECIFIED = -7
};
enum efsw_option
{
enum efsw_option {
/// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and
/// file system events may be dropped. For that, using a different (bigger) buffer size
/// can be defined here, but note that this does not work for network drives,
@@ -95,19 +92,37 @@ enum efsw_option
/// For Windows, per default all events are captured but we might only be interested
/// in a subset; the value of the option should be set to a bitwise or'ed set of
/// FILE_NOTIFY_CHANGE_* flags.
EFSW_OPT_WIN_NOTIFY_FILTER = 2
EFSW_OPT_WIN_NOTIFY_FILTER = 2,
/// For macOS (FSEvents backend), per default all modified event types are capture but we might
// only be interested in a subset; the value of the option should be set to a set of bitwise
// from:
// kFSEventStreamEventFlagItemFinderInfoMod
// kFSEventStreamEventFlagItemModified
// kFSEventStreamEventFlagItemInodeMetaMod
// Default configuration will set the 3 flags
EFSW_OPT_MAC_MODIFIED_FILTER = 3,
/// macOS sometimes informs incorrect or old file states that may confuse the consumer
/// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing
/// the number of events reported. This will have an small performance and memory impact as a
/// consequence.
EFSW_OPT_MAC_SANITIZE_EVENTS = 4,
/// Linux does not support natively recursive watchers. This means that when using recursive
/// watches efsw registers new watchers for each directory. If new file are created between
/// the time efsw takes to register the new directory those events might be missed. To avoid
/// missing new file notifications efsw will trigger synthetic new file events for existing
/// files in the new directroy watched. This might have the unintended consequence of sending
/// duplicated created events due to the system also emitting this event.
LINUX_PRODUCE_SYNTHETIC_EVENTS = 5,
};
/// Basic interface for listening for file events.
typedef void (*efsw_pfn_fileaction_callback) (
efsw_watcher watcher,
efsw_watchid watchid,
const char* dir,
const char* filename,
enum efsw_action action,
const char* old_filename,
void* param
);
typedef void ( *efsw_pfn_fileaction_callback )( efsw_watcher watcher, efsw_watchid watchid,
const char* dir, const char* filename,
enum efsw_action action, const char* old_filename,
void* param );
typedef void ( *efsw_pfn_handle_missed_fileactions )( efsw_watcher watcher, efsw_watchid watchid,
const char* dir );
typedef struct {
enum efsw_option option;
@@ -118,10 +133,10 @@ typedef struct {
* Creates a new file-watcher
* @param generic_mode Force the use of the Generic file watcher
*/
efsw_watcher EFSW_API efsw_create(int generic_mode);
efsw_watcher EFSW_API efsw_create( int generic_mode );
/// Release the file-watcher and unwatch any directories
void EFSW_API efsw_release(efsw_watcher watcher);
void EFSW_API efsw_release( efsw_watcher watcher );
/// Retrieve last error occured by file-watcher
EFSW_API const char* efsw_getlasterror();
@@ -131,47 +146,49 @@ EFSW_API void efsw_clearlasterror();
/// Add a directory watch
/// On error returns WatchID with Error type.
efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory,
efsw_pfn_fileaction_callback callback_fn, int recursive, void* param);
efsw_watchid EFSW_API efsw_addwatch( efsw_watcher watcher, const char* directory,
efsw_pfn_fileaction_callback callback_fn, int recursive,
void* param );
/// Add a directory watch, specifying options
/// @param options Pointer to an array of watcher options
/// @param nr_options Number of options referenced by \p options
efsw_watchid EFSW_API efsw_addwatch_withoptions(efsw_watcher watcher, const char* directory,
efsw_pfn_fileaction_callback callback_fn, int recursive, efsw_watcher_option *options,
int options_number, void* param);
efsw_watchid EFSW_API efsw_addwatch_withoptions(
efsw_watcher watcher, const char* directory, efsw_pfn_fileaction_callback callback_fn,
int recursive, efsw_watcher_option* options, int options_number, void* param,
efsw_pfn_handle_missed_fileactions callback_fn_missed_file_actions );
/// Remove a directory watch. This is a brute force search O(nlogn).
void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory);
void EFSW_API efsw_removewatch( efsw_watcher watcher, const char* directory );
/// Remove a directory watch. This is a map lookup O(logn).
void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid);
void EFSW_API efsw_removewatch_byid( efsw_watcher watcher, efsw_watchid watchid );
/// Starts watching ( in other thread )
void EFSW_API efsw_watch(efsw_watcher watcher);
void EFSW_API efsw_watch( efsw_watcher watcher );
/**
* Allow recursive watchers to follow symbolic links to other directories
* followSymlinks is disabled by default
*/
void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable);
void EFSW_API efsw_follow_symlinks( efsw_watcher watcher, int enable );
/** @return If can follow symbolic links to directorioes */
int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher);
int EFSW_API efsw_follow_symlinks_isenabled( efsw_watcher watcher );
/**
* When enable this it will allow symlinks to watch recursively out of the pointed directory.
* follorSymlinks must be enabled to this work.
* For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed,
* it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion.
* Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ).
* Buy enabling out of scope links, it will allow this behavior.
* For example, added symlink to /home/folder, and the symlink points to /, this by default is not
* allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid great
* levels of recursion. Enabling this could lead in infinite recursion, and crash the watcher ( it
* will try not to avoid this ). Buy enabling out of scope links, it will allow this behavior.
* allowOutOfScopeLinks are disabled by default.
*/
void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow);
void EFSW_API efsw_allow_outofscopelinks( efsw_watcher watcher, int allow );
/// @return Returns if out of scope links are allowed
int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher);
int EFSW_API efsw_outofscopelinks_isallowed( efsw_watcher watcher );
#ifdef __cplusplus
}

View File

@@ -1,7 +1,7 @@
/**
@author Martín Lucas Golini
Copyright (c) 2013 Martín Lucas Golini
Copyright (c) 2024 Martín Lucas Golini
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +28,6 @@
#ifndef ESFW_HPP
#define ESFW_HPP
#include <vector>
#include <string>
#include <vector>
@@ -135,7 +134,27 @@ enum Option {
/// For Windows, per default all events are captured but we might only be interested
/// in a subset; the value of the option should be set to a bitwise or'ed set of
/// FILE_NOTIFY_CHANGE_* flags.
WinNotifyFilter = 2
WinNotifyFilter = 2,
/// For macOS (FSEvents backend), per default all modified event types are capture but we might
/// only be interested in a subset; the value of the option should be set to a set of bitwise
/// from:
/// kFSEventStreamEventFlagItemFinderInfoMod
/// kFSEventStreamEventFlagItemModified
/// kFSEventStreamEventFlagItemInodeMetaMod
/// Default configuration will set the 3 flags
MacModifiedFilter = 3,
/// macOS sometimes informs incorrect or old file states that may confuse the consumer
/// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing
/// the number of events reported. This will have an small performance and memory impact as a
/// consequence.
MacSanitizeEvents = 4,
/// Linux does not support natively recursive watchers. This means that when using recursive
/// watches efsw registers new watchers for each directory. If new file are created between
/// the time efsw takes to register the new directory those events might be missed. To avoid
/// missing new file notifications efsw will trigger synthetic created file events for existing
/// files in the new directroy watched. This might have the unintended consequence of sending
/// duplicated created events due to the system also emitting this event.
LinuxProduceSyntheticEvents = 5,
};
}
typedef Options::Option Option;
@@ -168,8 +187,8 @@ class EFSW_API FileWatcher {
/// @param recursive Set this to true to include subdirectories
/// @param options Allows customization of a watcher
/// @return Returns the watch id for the directory or, on error, a WatchID with Error type.
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
const std::vector<WatcherOption> &options );
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
const std::vector<WatcherOption>& options );
/// Remove a directory watch. This is a brute force search O(nlogn).
void removeWatch( const std::string& directory );
@@ -226,13 +245,19 @@ class FileWatchListener {
virtual void handleFileAction( WatchID watchid, const std::string& dir,
const std::string& filename, Action action,
std::string oldFilename = "" ) = 0;
/// Handles that have missed file actions
/// @param watchid The watch id for the directory
/// @param dir The directory
virtual void handleMissedFileActions( WatchID /*watchid*/,
const std::string& /*dir*/ ) {}
};
/// Optional, typically platform specific parameter for customization of a watcher.
/// @class WatcherOption
class WatcherOption {
public:
WatcherOption(Option option, int value) : mOption(option), mValue(value) {};
WatcherOption( Option option, int value ) : mOption( option ), mValue( value ){};
Option mOption;
int mValue;
};

View File

@@ -49,8 +49,10 @@ void efPRINTC( unsigned int cond, const char* format, ... );
#define efDEBUGC( cond, format, args... ) \
{}
#else
#define efDEBUG
#define efDEBUGC
#define efDEBUG( ... ) \
{}
#define efDEBUGC( ... ) \
{}
#endif
#endif

View File

@@ -1,11 +1,19 @@
#include <cstring>
#include <efsw/FileSystem.hpp>
#include <efsw/platform/platformimpl.hpp>
#include <climits>
#if EFSW_OS == EFSW_OS_MACOSX
#include <CoreFoundation/CoreFoundation.h>
#endif
#if EFSW_OS == EFSW_OS_WIN
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
namespace efsw {
bool FileSystem::isDirectory( const std::string& path ) {
@@ -133,4 +141,21 @@ std::string FileSystem::getCurrentWorkingDirectory() {
return Platform::FileSystem::getCurrentWorkingDirectory();
}
std::string FileSystem::getRealPath( const std::string& path ) {
std::string realPath;
#if defined( EFSW_PLATFORM_POSIX )
char dir[PATH_MAX];
realpath( path.c_str(), &dir[0] );
realPath = std::string( dir );
#elif EFSW_OS == EFSW_OS_WIN
wchar_t dir[_MAX_PATH + 1];
GetFullPathNameW( String::fromUtf8( path ).toWideString().c_str(), _MAX_PATH, &dir[0],
nullptr );
realPath = String( dir ).toUtf8();
#else
#warning FileSystem::getRealPath() not implemented on this platform.
#endif
return realPath;
}
} // namespace efsw

View File

@@ -3,7 +3,6 @@
#include <efsw/FileInfo.hpp>
#include <efsw/base.hpp>
#include <map>
namespace efsw {
@@ -34,6 +33,9 @@ class FileSystem {
static bool changeWorkingDirectory( const std::string& path );
static std::string getCurrentWorkingDirectory();
static std::string getRealPath( const std::string& path );
};
} // namespace efsw

View File

@@ -10,10 +10,12 @@ class Watcher_CAPI : public efsw::FileWatchListener {
efsw_watcher mWatcher;
efsw_pfn_fileaction_callback mFn;
void* mParam;
efsw_pfn_handle_missed_fileactions mFnMissedFa;
public:
Watcher_CAPI( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) :
mWatcher( watcher ), mFn( fn ), mParam( param ) {}
Watcher_CAPI( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param,
efsw_pfn_handle_missed_fileactions fnfa ) :
mWatcher( watcher ), mFn( fn ), mParam( param ), mFnMissedFa( fnfa ) {}
void handleFileAction( efsw::WatchID watchid, const std::string& dir,
const std::string& filename, efsw::Action action,
@@ -21,6 +23,12 @@ class Watcher_CAPI : public efsw::FileWatchListener {
mFn( mWatcher, watchid, dir.c_str(), filename.c_str(), (enum efsw_action)action,
oldFilename.c_str(), mParam );
}
void handleMissedFileActions( efsw::WatchID watchid, const std::string& dir ) {
if ( mFnMissedFa ) {
mFnMissedFa( mWatcher, watchid, dir.c_str() );
}
}
};
/*************************************************************************************************
@@ -28,12 +36,12 @@ class Watcher_CAPI : public efsw::FileWatchListener {
*/
static std::vector<Watcher_CAPI*> g_callbacks;
Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn ) {
Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) {
for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end();
++i ) {
Watcher_CAPI* callback = *i;
if ( callback->mFn == fn && callback->mWatcher == watcher )
if ( callback->mFn == fn && callback->mWatcher == watcher && callback->mParam == param )
return *i;
}
@@ -77,25 +85,27 @@ EFSW_API void efsw_clearlasterror() {
efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory,
efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) {
return efsw_addwatch_withoptions( watcher, directory, callback_fn, recursive, 0, 0, param );
return efsw_addwatch_withoptions( watcher, directory, callback_fn, recursive, 0, 0, param,
nullptr );
}
efsw_watchid efsw_addwatch_withoptions(efsw_watcher watcher, const char* directory,
efsw_pfn_fileaction_callback callback_fn, int recursive,
efsw_watcher_option *options, int options_number,
void* param) {
Watcher_CAPI* callback = find_callback( watcher, callback_fn );
efsw_watchid
efsw_addwatch_withoptions( efsw_watcher watcher, const char* directory,
efsw_pfn_fileaction_callback callback_fn, int recursive,
efsw_watcher_option* options, int options_number, void* param,
efsw_pfn_handle_missed_fileactions callback_fn_missed_file_actions ) {
Watcher_CAPI* callback = find_callback( watcher, callback_fn, param );
if ( callback == NULL ) {
callback = new Watcher_CAPI( watcher, callback_fn, param );
callback = new Watcher_CAPI( watcher, callback_fn, param, callback_fn_missed_file_actions );
g_callbacks.push_back( callback );
}
std::vector<efsw::WatcherOption> watcher_options{};
for ( int i = 0; i < options_number; i++ ) {
efsw_watcher_option* option = &options[i];
watcher_options.emplace_back( efsw::WatcherOption{
static_cast<efsw::Option>(option->option), option->value } );
watcher_options.emplace_back(
efsw::WatcherOption{ static_cast<efsw::Option>( option->option ), option->value } );
}
return ( (efsw::FileWatcher*)watcher )

View File

@@ -41,7 +41,33 @@ bool FileWatcherFSEvents::isGranular() {
return getOSXReleaseNumber() >= 11;
}
void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef, void* userData,
static std::string convertCFStringToStdString( CFStringRef cfString ) {
// Try to get the C string pointer directly
const char* cStr = CFStringGetCStringPtr( cfString, kCFStringEncodingUTF8 );
if ( cStr ) {
// If the pointer is valid, directly return a std::string from it
return std::string( cStr );
} else {
// If not, manually convert it
CFIndex length = CFStringGetLength( cfString );
CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ) +
1; // +1 for null terminator
char* buffer = new char[maxSize];
if ( CFStringGetCString( cfString, buffer, maxSize, kCFStringEncodingUTF8 ) ) {
std::string result( buffer );
delete[] buffer;
return result;
} else {
delete[] buffer;
return "";
}
}
}
void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, void* userData,
size_t numEvents, void* eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[] ) {
@@ -51,8 +77,24 @@ void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef, void
events.reserve( numEvents );
for ( size_t i = 0; i < numEvents; i++ ) {
events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), (long)eventFlags[i],
(Uint64)eventIds[i] ) );
if ( isGranular() ) {
CFDictionaryRef pathInfoDict =
static_cast<CFDictionaryRef>( CFArrayGetValueAtIndex( (CFArrayRef)eventPaths, i ) );
CFStringRef path = static_cast<CFStringRef>(
CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedDataPathKey ) );
CFNumberRef cfInode = static_cast<CFNumberRef>(
CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedFileIDKey ) );
if ( cfInode ) {
unsigned long inode = 0;
CFNumberGetValue( cfInode, kCFNumberLongType, &inode );
events.push_back( FSEvent( convertCFStringToStdString( path ), (long)eventFlags[i],
(Uint64)eventIds[i], inode ) );
}
} else {
events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ),
(long)eventFlags[i], (Uint64)eventIds[i] ) );
}
}
watcher->handleActions( events );
@@ -84,8 +126,8 @@ FileWatcherFSEvents::~FileWatcherFSEvents() {
}
WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption> &options ) {
std::string dir( directory );
bool recursive, const std::vector<WatcherOption>& options ) {
std::string dir( FileSystem::getRealPath( directory ) );
FileInfo fi( dir );
@@ -125,6 +167,9 @@ WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchLi
pWatch->Directory = dir;
pWatch->Recursive = recursive;
pWatch->FWatcher = this;
pWatch->ModifiedFlags =
getOptionValue( options, Option::MacModifiedFilter, efswFSEventsModified );
pWatch->SanitizeEvents = getOptionValue( options, Option::MacSanitizeEvents, 0 ) != 0;
pWatch->init();
@@ -169,8 +214,8 @@ void FileWatcherFSEvents::removeWatch( WatchID watchid ) {
void FileWatcherFSEvents::watch() {}
void FileWatcherFSEvents::handleAction( Watcher* watch, const std::string& filename,
unsigned long action, std::string oldFilename ) {
void FileWatcherFSEvents::handleAction( Watcher* /*watch*/, const std::string& /*filename*/,
unsigned long /*action*/, std::string /*oldFilename*/ ) {
/// Not used
}

View File

@@ -16,27 +16,6 @@
namespace efsw {
/* OSX < 10.7 has no file events */
/* So i declare the events constants */
enum FSEventEvents {
efswFSEventStreamCreateFlagNoDefer = 0x00000002,
efswFSEventStreamCreateFlagFileEvents = 0x00000010,
efswFSEventStreamEventFlagItemCreated = 0x00000100,
efswFSEventStreamEventFlagItemRemoved = 0x00000200,
efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400,
efswFSEventStreamEventFlagItemRenamed = 0x00000800,
efswFSEventStreamEventFlagItemModified = 0x00001000,
efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000,
efswFSEventStreamEventFlagItemChangeOwner = 0x00004000,
efswFSEventStreamEventFlagItemXattrMod = 0x00008000,
efswFSEventStreamEventFlagItemIsFile = 0x00010000,
efswFSEventStreamEventFlagItemIsDir = 0x00020000,
efswFSEventStreamEventFlagItemIsSymlink = 0x00040000,
efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod |
efswFSEventStreamEventFlagItemModified |
efswFSEventStreamEventFlagItemInodeMetaMod
};
/// Implementation for Win32 based on ReadDirectoryChangesW.
/// @class FileWatcherFSEvents
class FileWatcherFSEvents : public FileWatcherImpl {

View File

@@ -101,7 +101,7 @@ void FileWatcherGeneric::removeWatch( WatchID watchid ) {
void FileWatcherGeneric::watch() {
if ( NULL == mThread ) {
mThread = new Thread( &FileWatcherGeneric::run, this );
mThread = new Thread([this]{run();});
mThread->launch();
}
}

View File

@@ -7,6 +7,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -69,15 +70,17 @@ FileWatcherInotify::~FileWatcherInotify() {
}
WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption>& ) {
bool recursive, const std::vector<WatcherOption>& options ) {
if ( !mInitOK )
return Errors::Log::createLastError( Errors::Unspecified, directory );
Lock initLock( mInitLock );
return addWatch( directory, watcher, recursive, NULL );
bool syntheticEvents = getOptionValue( options, Options::LinuxProduceSyntheticEvents, 0 ) != 0;
return addWatch( directory, watcher, recursive, syntheticEvents, NULL );
}
WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, WatcherInotify* parent ) {
bool recursive, bool syntheticEvents, WatcherInotify* parent,
bool fromInternalEvent ) {
std::string dir( directory );
FileSystem::dirAddSlashAtEnd( dir );
@@ -137,6 +140,7 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
pWatch->Directory = dir;
pWatch->Recursive = recursive;
pWatch->Parent = parent;
pWatch->syntheticEvents = syntheticEvents;
{
Lock lock( mWatchesLock );
@@ -151,6 +155,18 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
if ( pWatch->Recursive ) {
std::map<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory );
if ( fromInternalEvent && parent != NULL && syntheticEvents ) {
for ( const auto& file : files ) {
if ( file.second.isRegularFile() || file.second.isDirectory() ||
file.second.isLink() ) {
pWatch->Listener->handleFileAction(
pWatch->ID, pWatch->Directory,
FileSystem::fileNameFromPath( file.second.Filepath ), Actions::Add );
}
}
}
std::map<std::string, FileInfo>::iterator it = files.begin();
for ( ; it != files.end(); ++it ) {
@@ -160,7 +176,8 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
const FileInfo& cfi = it->second;
if ( cfi.isDirectory() && cfi.isReadable() ) {
addWatch( cfi.Filepath, watcher, recursive, pWatch );
addWatch( cfi.Filepath, watcher, recursive, syntheticEvents, pWatch,
fromInternalEvent );
}
}
}
@@ -244,7 +261,7 @@ void FileWatcherInotify::removeWatch( WatchID watchid ) {
void FileWatcherInotify::watch() {
if ( NULL == mThread ) {
mThread = new Thread( &FileWatcherInotify::run, this );
mThread = new Thread( [this] { run(); } );
mThread->launch();
}
}
@@ -267,10 +284,10 @@ Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) {
void FileWatcherInotify::run() {
char* buff = new char[BUFF_SIZE];
memset( buff, 0, BUFF_SIZE );
WatchMap::iterator wit;
WatcherInotify* curWatcher = NULL;
WatcherInotify* currentMoveFrom = NULL;
u_int32_t currentMoveCookie = -1;
uint32_t currentMoveCookie = -1;
bool lastWasMovedFrom = false;
std::string prevOldFileName;
@@ -294,16 +311,21 @@ void FileWatcherInotify::run() {
struct inotify_event* pevent = (struct inotify_event*)&buff[i];
{
curWatcher = NULL;
{
Lock lock( mWatchesLock );
wit = mWatches.find( pevent->wd );
auto wit = mWatches.find( pevent->wd );
if ( wit != mWatches.end() )
curWatcher = wit->second;
}
if ( wit != mWatches.end() ) {
handleAction( wit->second, (char*)pevent->name, pevent->mask );
if ( curWatcher ) {
handleAction( curWatcher, (char*)pevent->name, pevent->mask );
if ( ( pevent->mask & IN_MOVED_TO ) && wit->second == currentMoveFrom &&
if ( ( pevent->mask & IN_MOVED_TO ) && curWatcher == currentMoveFrom &&
pevent->cookie == currentMoveCookie ) {
/// make pair success
currentMoveFrom = NULL;
@@ -316,14 +338,30 @@ void FileWatcherInotify::run() {
std::make_pair( currentMoveFrom, prevOldFileName ) );
}
currentMoveFrom = wit->second;
currentMoveFrom = curWatcher;
currentMoveCookie = pevent->cookie;
} else {
/// Keep track of the IN_MOVED_FROM events to know
/// if the IN_MOVED_TO event is also fired
if ( currentMoveFrom ) {
mMovedOutsideWatches.push_back(
std::make_pair( currentMoveFrom, prevOldFileName ) );
if ( std::find_if( mMovedOutsideWatches.begin(),
mMovedOutsideWatches.end(),
[currentMoveFrom](
const std::pair<WatcherInotify*,
std::string>& moved ) {
return moved.first == currentMoveFrom;
} ) == mMovedOutsideWatches.end() ) {
mMovedOutsideWatches.push_back(
std::make_pair( currentMoveFrom, prevOldFileName ) );
} else {
efDEBUG( "Info: Tried to add watch to the moved outside "
"watches but it was already there, Watch ID: %d - "
"Address: %p - Path: \"%s\" - prevOldFileName: "
"\"%s\"\n",
pevent->wd, currentMoveFrom,
currentMoveFrom->Directory.c_str(),
prevOldFileName.c_str() );
}
}
currentMoveFrom = NULL;
@@ -343,8 +381,18 @@ void FileWatcherInotify::run() {
// Here means no event received
// If last event is IN_MOVED_FROM, we assume no IN_MOVED_TO
if ( currentMoveFrom ) {
mMovedOutsideWatches.push_back(
std::make_pair( currentMoveFrom, currentMoveFrom->OldFileName ) );
if ( std::find_if(
mMovedOutsideWatches.begin(), mMovedOutsideWatches.end(),
[currentMoveFrom]( const std::pair<WatcherInotify*, std::string>& moved ) {
return moved.first == currentMoveFrom;
} ) == mMovedOutsideWatches.end() ) {
mMovedOutsideWatches.push_back(
std::make_pair( currentMoveFrom, currentMoveFrom->OldFileName ) );
} else {
efDEBUG( "Warning: Tried to add watch to the moved outside "
"watches but it was already there, Watch Address: %p\n",
currentMoveFrom );
}
}
currentMoveFrom = NULL;
@@ -378,8 +426,8 @@ void FileWatcherInotify::run() {
continue;
}
Watcher* watch = ( *it ).first;
const std::string& oldFileName = ( *it ).second;
Watcher* watch = it->first;
const std::string& oldFileName = it->second;
/// Check if the file move was a folder already being watched
std::vector<Watcher*> eraseWatches;
@@ -387,8 +435,8 @@ void FileWatcherInotify::run() {
{
Lock lock( mWatchesLock );
for ( ; wit != mWatches.end(); ++wit ) {
Watcher* oldWatch = wit->second;
for ( auto wit : mWatches ) {
Watcher* oldWatch = wit.second;
if ( oldWatch != watch &&
-1 != String::strStartsWith( watch->Directory + oldFileName + "/",
@@ -448,8 +496,9 @@ void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath )
}
if ( !found ) {
addWatch( fpath, watch->Listener, watch->Recursive,
static_cast<WatcherInotify*>( watch ) );
WatcherInotify* iWatch = static_cast<WatcherInotify*>( watch );
addWatch( fpath, watch->Listener, watch->Recursive, iWatch->syntheticEvents,
static_cast<WatcherInotify*>( watch ), true );
}
}
}
@@ -464,7 +513,9 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena
std::string fpath( watch->Directory + filename );
if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) {
if ( IN_Q_OVERFLOW & action ) {
watch->Listener->handleMissedFileActions( watch->ID, watch->Directory );
} else if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) {
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename,
Actions::Modified );
} else if ( IN_MOVED_TO & action ) {

View File

@@ -65,7 +65,8 @@ class FileWatcherInotify : public FileWatcherImpl {
std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches;
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
WatcherInotify* parent = NULL );
bool syntheticEvents, WatcherInotify* parent = NULL,
bool fromInternalEvent = false );
bool pathInWatches( const std::string& path ) override;

View File

@@ -162,7 +162,7 @@ bool FileWatcherKqueue::isAddingWatcher() const {
void FileWatcherKqueue::watch() {
if ( NULL == mThread ) {
mThread = new Thread( &FileWatcherKqueue::run, this );
mThread = new Thread([this]{run();});
mThread->launch();
}
}

View File

@@ -26,7 +26,8 @@ FileWatcherWin32::~FileWatcherWin32() {
removeAllWatches();
CloseHandle( mIOCP );
if ( mIOCP )
CloseHandle( mIOCP );
}
WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher,
@@ -112,7 +113,7 @@ void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) {
void FileWatcherWin32::watch() {
if ( NULL == mThread ) {
mThread = new Thread( &FileWatcherWin32::run, this );
mThread = new Thread([this]{run();});
mThread->launch();
}
}
@@ -143,7 +144,8 @@ void FileWatcherWin32::run() {
break;
} else {
Lock lock( mWatchesLock );
WatchCallback( numOfBytes, ov );
if (mWatches.find( (WatcherStructWin32*)ov ) != mWatches.end())
WatchCallback( numOfBytes, ov );
}
}
} else {

View File

@@ -7,7 +7,7 @@
#include <efsw/WatcherWin32.hpp>
#include <map>
#include <set>
#include <unordered_set>
#include <vector>
namespace efsw {
@@ -17,7 +17,7 @@ namespace efsw {
class FileWatcherWin32 : public FileWatcherImpl {
public:
/// type for a map from WatchID to WatcherWin32 pointer
typedef std::set<WatcherStructWin32*> Watches;
typedef std::unordered_set<WatcherStructWin32*> Watches;
FileWatcherWin32( FileWatcher* parent );

View File

@@ -1,21 +1,11 @@
#ifndef EFSW_LOCK_HPP
#define EFSW_LOCK_HPP
#include <mutex>
#include <efsw/Mutex.hpp>
namespace efsw {
/** Simple mutex class */
class Lock {
public:
explicit Lock( Mutex& mutex ) : mMutex( mutex ) { mMutex.lock(); }
~Lock() { mMutex.unlock(); }
private:
Mutex& mMutex;
};
using Lock = std::unique_lock<Mutex>;
} // namespace efsw
#endif

View File

@@ -1,20 +0,0 @@
#include <efsw/Mutex.hpp>
#include <efsw/platform/platformimpl.hpp>
namespace efsw {
Mutex::Mutex() : mMutexImpl( new Platform::MutexImpl() ) {}
Mutex::~Mutex() {
efSAFE_DELETE( mMutexImpl );
}
void Mutex::lock() {
mMutexImpl->lock();
}
void Mutex::unlock() {
mMutexImpl->unlock();
}
} // namespace efsw

View File

@@ -1,31 +1,10 @@
#ifndef EFSW_MUTEX_HPP
#define EFSW_MUTEX_HPP
#include <efsw/base.hpp>
#include <mutex>
namespace efsw {
namespace Platform {
class MutexImpl;
}
/** Simple mutex class */
class Mutex {
public:
Mutex();
~Mutex();
/** Lock the mutex */
void lock();
/** Unlock the mutex */
void unlock();
private:
Platform::MutexImpl* mMutexImpl;
};
using Mutex = std::recursive_mutex;
} // namespace efsw
#endif

View File

@@ -11,7 +11,6 @@
#include <cstdlib>
#include <cstring>
#include <efsw/base.hpp>
#include <fstream>
#include <iostream>
#include <locale>
#include <sstream>
@@ -24,7 +23,7 @@ namespace efsw {
* **/
class String {
public:
typedef Uint32 StringBaseType;
typedef char32_t StringBaseType;
typedef std::basic_string<StringBaseType> StringType;
typedef StringType::iterator Iterator; //! Iterator type
typedef StringType::const_iterator ConstIterator; //! Constant iterator type

View File

@@ -1,41 +0,0 @@
#include <efsw/Thread.hpp>
#include <efsw/platform/platformimpl.hpp>
namespace efsw {
Thread::Thread() : mThreadImpl( NULL ), mEntryPoint( NULL ) {}
Thread::~Thread() {
wait();
efSAFE_DELETE( mEntryPoint );
}
void Thread::launch() {
wait();
mThreadImpl = new Platform::ThreadImpl( this );
}
void Thread::wait() {
if ( mThreadImpl ) {
mThreadImpl->wait();
efSAFE_DELETE( mThreadImpl );
}
}
void Thread::terminate() {
if ( mThreadImpl ) {
mThreadImpl->terminate();
efSAFE_DELETE( mThreadImpl );
}
}
void Thread::run() {
if ( mEntryPoint )
mEntryPoint->run();
}
} // namespace efsw

View File

@@ -2,99 +2,48 @@
#define EFSW_THREAD_HPP
#include <efsw/base.hpp>
#include <functional>
#include <memory>
#include <thread>
namespace efsw {
namespace Platform {
class ThreadImpl;
}
namespace Private {
struct ThreadFunc;
}
/** @brief Thread manager class */
class Thread {
public:
typedef void ( *FuncType )( void* );
template <typename F> Thread( F function );
Thread(std::function<void()> fun)
: mFun{std::move(fun)}
{
}
template <typename F, typename A> Thread( F function, A argument );
template <typename C> Thread( void ( C::*function )(), C* object );
virtual ~Thread();
~Thread()
{
wait();
}
/** Launch the thread */
virtual void launch();
void launch()
{
if (!mThread)
mThread.reset(new std::thread{std::move(mFun)});
}
/** Wait the thread until end */
void wait();
void wait()
{
if (mThread)
{
mThread->join();
mThread.reset();
}
}
private:
/** Terminate the thread */
void terminate();
protected:
Thread();
private:
friend class Platform::ThreadImpl;
/** The virtual function to run in the thread */
virtual void run();
Platform::ThreadImpl* mThreadImpl; ///< OS-specific implementation of the thread
Private::ThreadFunc* mEntryPoint; ///< Abstraction of the function to run
std::unique_ptr<std::thread> mThread;
std::function<void()> mFun;
};
//! NOTE: Taken from SFML2 threads
namespace Private {
// Base class for abstract thread functions
struct ThreadFunc {
virtual ~ThreadFunc() {}
virtual void run() = 0;
};
// Specialization using a functor (including free functions) with no argument
template <typename T> struct ThreadFunctor : ThreadFunc {
ThreadFunctor( T functor ) : m_functor( functor ) {}
virtual void run() { m_functor(); }
T m_functor;
};
// Specialization using a functor (including free functions) with one argument
template <typename F, typename A> struct ThreadFunctorWithArg : ThreadFunc {
ThreadFunctorWithArg( F function, A arg ) : m_function( function ), m_arg( arg ) {}
virtual void run() { m_function( m_arg ); }
F m_function;
A m_arg;
};
// Specialization using a member function
template <typename C> struct ThreadMemberFunc : ThreadFunc {
ThreadMemberFunc( void ( C::*function )(), C* object ) :
m_function( function ), m_object( object ) {}
virtual void run() { ( m_object->*m_function )(); }
void ( C::*m_function )();
C* m_object;
};
} // namespace Private
template <typename F>
Thread::Thread( F functor ) :
mThreadImpl( NULL ), mEntryPoint( new Private::ThreadFunctor<F>( functor ) ) {}
template <typename F, typename A>
Thread::Thread( F function, A argument ) :
mThreadImpl( NULL ),
mEntryPoint( new Private::ThreadFunctorWithArg<F efCOMMA A>( function, argument ) ) {}
template <typename C>
Thread::Thread( void ( C::*function )(), C* object ) :
mThreadImpl( NULL ), mEntryPoint( new Private::ThreadMemberFunc<C>( function, object ) ) {}
} // namespace efsw
#endif

View File

@@ -10,13 +10,6 @@ namespace efsw {
WatcherFSEvents::WatcherFSEvents() :
Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ) {}
WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener,
bool recursive, WatcherFSEvents* parent ) :
Watcher( id, directory, listener, recursive ),
FWatcher( NULL ),
FSStream( NULL ),
WatcherGen( NULL ) {}
WatcherFSEvents::~WatcherFSEvents() {
if ( NULL != FSStream ) {
FSEventStreamStop( FSStream );
@@ -35,7 +28,9 @@ void WatcherFSEvents::init() {
Uint32 streamFlags = kFSEventStreamCreateFlagNone;
if ( FileWatcherFSEvents::isGranular() ) {
streamFlags = efswFSEventStreamCreateFlagFileEvents | efswFSEventStreamCreateFlagNoDefer;
streamFlags = efswFSEventStreamCreateFlagFileEvents | efswFSEventStreamCreateFlagNoDefer |
efswFSEventStreamCreateFlagUseExtendedData |
efswFSEventStreamCreateFlagUseCFTypes;
} else {
WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive );
}
@@ -48,13 +43,13 @@ void WatcherFSEvents::init() {
ctx.release = NULL;
ctx.copyDescription = NULL;
dispatch_queue_t queue = dispatch_queue_create(NULL, NULL);
dispatch_queue_t queue = dispatch_queue_create( NULL, NULL );
FSStream =
FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx,
CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0., streamFlags );
FSEventStreamSetDispatchQueue(FSStream, queue);
FSEventStreamSetDispatchQueue( FSStream, queue );
FSEventStreamStart( FSStream );
@@ -66,27 +61,37 @@ void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir,
const std::string& filename, Action action,
std::string oldFilename ) {
Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ),
FileSystem::precomposeFileName( filename ), action, FileSystem::precomposeFileName( oldFilename ) );
FileSystem::precomposeFileName( filename ), action,
FileSystem::precomposeFileName( oldFilename ) );
}
void WatcherFSEvents::sendMissedFileActions( WatchID watchid,
const std::string& dir) {
Listener->handleMissedFileActions( watchid,
FileSystem::precomposeFileName( dir ) );
}
void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path,
std::string& dirPath, std::string& filePath ) {
if ( flags & efswFSEventStreamEventFlagItemCreated ) {
if ( FileInfo::exists( path ) ) {
sendFileAction( ID, dirPath, filePath, Actions::Add );
}
std::string& dirPath, std::string& filePath, Uint64 inode ) {
if ( ( flags & efswFSEventStreamEventFlagItemCreated ) && FileInfo::exists( path ) &&
( !SanitizeEvents || FilesAdded.find( inode ) != FilesAdded.end() ) ) {
sendFileAction( ID, dirPath, filePath, Actions::Add );
if ( SanitizeEvents )
FilesAdded.insert( inode );
}
if ( flags & efswFSEventsModified ) {
if ( flags & ModifiedFlags ) {
sendFileAction( ID, dirPath, filePath, Actions::Modified );
}
if ( flags & efswFSEventStreamEventFlagItemRemoved ) {
if ( ( flags & efswFSEventStreamEventFlagItemRemoved ) && !FileInfo::exists( path ) ) {
// Since i don't know the order, at least i try to keep the data consistent with the real
// state
if ( !FileInfo::exists( path ) ) {
sendFileAction( ID, dirPath, filePath, Actions::Delete );
}
sendFileAction( ID, dirPath, filePath, Actions::Delete );
if ( SanitizeEvents )
FilesAdded.erase( inode );
}
}
@@ -98,7 +103,16 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
if ( event.Flags &
( kFSEventStreamEventFlagUserDropped | kFSEventStreamEventFlagKernelDropped |
kFSEventStreamEventFlagEventIdsWrapped | kFSEventStreamEventFlagHistoryDone |
kFSEventStreamEventFlagMustScanSubDirs) ) {
efDEBUG( "Rescan/Drop event for watch: %s - flags: 0x%x\n", Directory.c_str(), event.Flags );
std::string dirPath = Directory;
FileSystem::dirRemoveSlashAtEnd( dirPath );
sendMissedFileActions(ID, dirPath );
continue;
}
if ( event.Flags &
( kFSEventStreamEventFlagEventIdsWrapped | kFSEventStreamEventFlagHistoryDone |
kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount |
kFSEventStreamEventFlagRootChanged ) ) {
continue;
@@ -128,19 +142,20 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
// been added modified and erased, but i can't know if first was erased and then added
// and modified, or added, then modified and then erased. I don't know what they were
// thinking by doing this...
efDEBUG( "Event in: %s - flags: %ld\n", event.Path.c_str(), event.Flags );
efDEBUG( "Event in: %s - flags: 0x%x\n", event.Path.c_str(), event.Flags );
if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) {
if ( ( i + 1 < esize ) &&
( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) &&
( events[i + 1].Id == event.Id + 1 ) ) {
( events[i + 1].inode == event.inode ) ) {
FSEvent& nEvent = events[i + 1];
std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) );
std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) );
if ( event.Path != nEvent.Path ) {
if ( dirPath == newDir ) {
if ( !FileInfo::exists( event.Path ) ) {
if ( !FileInfo::exists( event.Path ) ||
0 == strcasecmp( event.Path.c_str(), nEvent.Path.c_str() ) ) {
sendFileAction( ID, dirPath, newFilepath, Actions::Moved,
filePath );
} else {
@@ -151,12 +166,12 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
sendFileAction( ID, dirPath, filePath, Actions::Delete );
sendFileAction( ID, newDir, newFilepath, Actions::Add );
if ( nEvent.Flags & efswFSEventsModified ) {
if ( nEvent.Flags & ModifiedFlags ) {
sendFileAction( ID, newDir, newFilepath, Actions::Modified );
}
}
} else {
handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath );
handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath, event.inode );
}
if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated |
@@ -172,14 +187,14 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
} else if ( FileInfo::exists( event.Path ) ) {
sendFileAction( ID, dirPath, filePath, Actions::Add );
if ( event.Flags & efswFSEventsModified ) {
if ( event.Flags & ModifiedFlags ) {
sendFileAction( ID, dirPath, filePath, Actions::Modified );
}
} else {
sendFileAction( ID, dirPath, filePath, Actions::Delete );
}
} else {
handleAddModDel( event.Flags, event.Path, dirPath, filePath );
handleAddModDel( event.Flags, event.Path, dirPath, filePath, event.inode );
}
} else {
efDEBUG( "Directory: %s changed\n", event.Path.c_str() );
@@ -189,7 +204,7 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
}
void WatcherFSEvents::process() {
std::set<std::string>::iterator it = DirsChanged.begin();
std::unordered_set<std::string>::iterator it = DirsChanged.begin();
for ( ; it != DirsChanged.end(); it++ ) {
if ( !FileWatcherFSEvents::isGranular() ) {

View File

@@ -9,29 +9,51 @@
#include <CoreServices/CoreServices.h>
#include <efsw/FileInfo.hpp>
#include <efsw/WatcherGeneric.hpp>
#include <set>
#include <unordered_set>
#include <vector>
namespace efsw {
/* OSX < 10.7 has no file events */
/* So i declare the events constants */
enum FSEventEvents {
efswFSEventStreamCreateFlagUseCFTypes = 0x00000001,
efswFSEventStreamCreateFlagNoDefer = 0x00000002,
efswFSEventStreamCreateFlagFileEvents = 0x00000010,
efswFSEventStreamCreateFlagUseExtendedData = 0x00000040,
efswFSEventStreamEventFlagItemCreated = 0x00000100,
efswFSEventStreamEventFlagItemRemoved = 0x00000200,
efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400,
efswFSEventStreamEventFlagItemRenamed = 0x00000800,
efswFSEventStreamEventFlagItemModified = 0x00001000,
efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000,
efswFSEventStreamEventFlagItemChangeOwner = 0x00004000,
efswFSEventStreamEventFlagItemXattrMod = 0x00008000,
efswFSEventStreamEventFlagItemIsFile = 0x00010000,
efswFSEventStreamEventFlagItemIsDir = 0x00020000,
efswFSEventStreamEventFlagItemIsSymlink = 0x00040000,
efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod |
efswFSEventStreamEventFlagItemModified |
efswFSEventStreamEventFlagItemInodeMetaMod
};
class FileWatcherFSEvents;
class FSEvent {
public:
FSEvent( std::string path, long flags, Uint64 id ) : Path( path ), Flags( flags ), Id( id ) {}
FSEvent( std::string path, long flags, Uint64 id, Uint64 inode = 0 ) :
Path( path ), Flags( flags ), Id( id ), inode( inode ) {}
std::string Path;
long Flags;
Uint64 Id;
long Flags{ 0 };
Uint64 Id{ 0 };
Uint64 inode{ 0 };
};
class WatcherFSEvents : public Watcher {
public:
WatcherFSEvents();
WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, bool recursive,
WatcherFSEvents* parent = NULL );
~WatcherFSEvents();
void init();
@@ -42,17 +64,22 @@ class WatcherFSEvents : public Watcher {
Atomic<FileWatcherFSEvents*> FWatcher;
FSEventStreamRef FSStream;
Uint64 ModifiedFlags{ efswFSEventsModified };
bool SanitizeEvents{ false };
protected:
void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath,
std::string& filePath );
std::string& filePath, Uint64 inode );
WatcherGeneric* WatcherGen;
std::set<std::string> DirsChanged;
std::unordered_set<std::string> DirsChanged;
std::unordered_set<Uint64> FilesAdded;
void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename,
Action action, std::string oldFilename = "" );
void sendMissedFileActions( WatchID watchid, const std::string& dir);
};
} // namespace efsw

View File

@@ -16,6 +16,7 @@ class WatcherInotify : public Watcher {
WatchID InotifyID;
FileInfo DirInfo;
bool syntheticEvents{ false };
};
} // namespace efsw

View File

@@ -354,7 +354,8 @@ void WatcherKqueue::watch() {
bool needScan = false;
// Then we get the the events of the current folder
while ( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1,
while ( !mChangeList.empty() &&
( nev = kevent( mKqueue, mChangeList.data(), mChangeListCount + 1, &event, 1,
&mWatcher->mTimeOut ) ) != 0 ) {
// An error ocurred?
if ( nev == -1 ) {

View File

@@ -1,4 +1,5 @@
#include <efsw/Debug.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/String.hpp>
#include <efsw/WatcherWin32.hpp>
@@ -8,26 +9,52 @@
namespace efsw {
/// Unpacks events and passes them to a user defined callback.
void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) {
struct EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX {
DWORD NextEntryOffset;
DWORD Action;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastModificationTime;
LARGE_INTEGER LastChangeTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER AllocatedLength;
LARGE_INTEGER FileSize;
DWORD FileAttributes;
DWORD ReparsePointTag;
LARGE_INTEGER FileId;
LARGE_INTEGER ParentFileId;
DWORD FileNameLength;
WCHAR FileName[1];
};
if ( NULL == lpOverlapped ) {
return;
}
typedef EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX* EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX;
PFILE_NOTIFY_INFORMATION pNotify;
WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped;
WatcherWin32* pWatch = tWatch->Watch;
size_t offset = 0;
typedef BOOL( WINAPI* EFSW_LPREADDIRECTORYCHANGESEXW )( HANDLE hDirectory, LPVOID lpBuffer,
DWORD nBufferLength, BOOL bWatchSubtree,
DWORD dwNotifyFilter, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
DWORD ReadDirectoryNotifyInformationClass );
if ( dwNumberOfBytesTransfered == 0 ) {
if ( nullptr != pWatch && !pWatch->StopNow ) {
RefreshWatch( tWatch );
} else {
static EFSW_LPREADDIRECTORYCHANGESEXW pReadDirectoryChangesExW = NULL;
#define EFSW_ReadDirectoryNotifyExtendedInformation 2
static void initReadDirectoryChangesEx() {
static bool hasInit = false;
if ( !hasInit ) {
hasInit = true;
HMODULE hModule = GetModuleHandleW( L"Kernel32.dll" );
if ( !hModule )
return;
}
}
pReadDirectoryChangesExW =
(EFSW_LPREADDIRECTORYCHANGESEXW)GetProcAddress( hModule, "ReadDirectoryChangesExW" );
}
}
void WatchCallbackOld( WatcherWin32* pWatch ) {
PFILE_NOTIFY_INFORMATION pNotify;
size_t offset = 0;
do {
bool skip = false;
@@ -62,6 +89,96 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve
pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action );
}
} while ( pNotify->NextEntryOffset != 0 );
}
void WatchCallbackEx( WatcherWin32* pWatch ) {
EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX pNotify;
size_t offset = 0;
do {
bool skip = false;
pNotify = (EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX)&pWatch->Buffer[offset];
offset += pNotify->NextEntryOffset;
int count =
WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL );
if ( count == 0 )
continue;
std::string nfile( count, '\0' );
count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count,
NULL, NULL );
if ( FILE_ACTION_MODIFIED == pNotify->Action ) {
FileInfo fifile( std::string( pWatch->DirName ) + nfile );
if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime &&
pWatch->LastModifiedEvent.file.Size == fifile.Size &&
pWatch->LastModifiedEvent.fileName == nfile ) {
skip = true;
}
pWatch->LastModifiedEvent.fileName = nfile;
pWatch->LastModifiedEvent.file = fifile;
} else if ( FILE_ACTION_RENAMED_OLD_NAME == pNotify->Action ) {
pWatch->OldFiles.emplace_back( nfile, pNotify->FileId );
skip = true;
} else if ( FILE_ACTION_RENAMED_NEW_NAME == pNotify->Action ) {
std::string oldFile;
LARGE_INTEGER oldFileId{};
for ( auto it = pWatch->OldFiles.begin(); it != pWatch->OldFiles.end(); ++it ) {
if ( it->second.QuadPart == pNotify->FileId.QuadPart ) {
oldFile = it->first;
oldFileId = it->second;
it = pWatch->OldFiles.erase( it );
break;
}
}
if ( oldFile.empty() ) {
pWatch->Watch->handleAction( pWatch, nfile, FILE_ACTION_ADDED );
skip = true;
} else {
pWatch->Watch->handleAction( pWatch, oldFile, FILE_ACTION_RENAMED_OLD_NAME );
}
}
if ( !skip ) {
pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action );
}
} while ( pNotify->NextEntryOffset != 0 );
}
/// Unpacks events and passes them to a user defined callback.
void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) {
if ( NULL == lpOverlapped ) {
return;
}
WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped;
WatcherWin32* pWatch = tWatch->Watch;
if ( dwNumberOfBytesTransfered == 0 ) {
if ( nullptr != pWatch && !pWatch->StopNow ) {
/// Missed file actions due to buffer overflowed
std::string dir = pWatch->DirName;
FileSystem::dirRemoveSlashAtEnd( dir );
pWatch->Listener->handleMissedFileActions( pWatch->ID, dir );
RefreshWatch( tWatch );
} else {
return;
}
}
// Fork watch depending on the Windows API supported
if ( pWatch->Extended ) {
WatchCallbackEx( pWatch );
} else {
WatchCallbackOld( pWatch );
}
if ( !pWatch->StopNow ) {
RefreshWatch( tWatch );
@@ -69,17 +186,40 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve
}
/// Refreshes the directory monitoring.
bool RefreshWatch( WatcherStructWin32* pWatch ) {
bool bRet = ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(),
pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive,
pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, NULL ) != 0;
RefreshResult RefreshWatch( WatcherStructWin32* pWatch ) {
initReadDirectoryChangesEx();
bool bRet = false;
RefreshResult ret = RefreshResult::Failed;
pWatch->Watch->Extended = false;
if ( pReadDirectoryChangesExW ) {
bRet = pReadDirectoryChangesExW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(),
(DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive,
pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped,
NULL, EFSW_ReadDirectoryNotifyExtendedInformation ) != 0;
if ( bRet ) {
ret = RefreshResult::SucessEx;
pWatch->Watch->Extended = true;
}
}
if ( !bRet ) {
bRet = ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(),
(DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive,
pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped,
NULL ) != 0;
if ( bRet )
ret = RefreshResult::Success;
}
if ( !bRet ) {
std::string error = std::to_string( GetLastError() );
Errors::Log::createLastError( Errors::WatcherFailed, error );
}
return bRet;
return ret;
}
/// Stops monitoring a directory.
@@ -91,19 +231,17 @@ void DestroyWatch( WatcherStructWin32* pWatch ) {
CloseHandle( pWatch->Watch->DirHandle );
efSAFE_DELETE_ARRAY( pWatch->Watch->DirName );
efSAFE_DELETE( pWatch->Watch );
efSAFE_DELETE( pWatch );
}
}
/// Starts monitoring a directory.
WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive,
DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ) {
WatcherStructWin32* tWatch;
size_t ptrsize = sizeof( *tWatch );
tWatch = static_cast<WatcherStructWin32*>(
HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize ) );
WatcherStructWin32* tWatch = new WatcherStructWin32();
WatcherWin32* pWatch = new WatcherWin32(bufferSize);
tWatch->Watch = pWatch;
if (tWatch)
tWatch->Watch = pWatch;
pWatch->DirHandle = CreateFileW(
szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
@@ -114,14 +252,14 @@ WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive,
pWatch->NotifyFilter = notifyFilter;
pWatch->Recursive = recursive;
if ( RefreshWatch( tWatch ) ) {
if ( RefreshResult::Failed != RefreshWatch( tWatch ) ) {
return tWatch;
}
}
CloseHandle( pWatch->DirHandle );
efSAFE_DELETE( pWatch->Watch );
HeapFree( GetProcessHeap(), 0, tWatch );
efSAFE_DELETE( tWatch );
return NULL;
}

View File

@@ -22,6 +22,8 @@ namespace efsw {
class WatcherWin32;
enum RefreshResult { Failed, Success, SucessEx };
/// Internal watch data
struct WatcherStructWin32 {
OVERLAPPED Overlapped;
@@ -33,7 +35,7 @@ struct sLastModifiedEvent {
std::string fileName;
};
bool RefreshWatch( WatcherStructWin32* pWatch );
RefreshResult RefreshWatch( WatcherStructWin32* pWatch );
void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped );
@@ -51,6 +53,7 @@ class WatcherWin32 : public Watcher {
lParam( 0 ),
NotifyFilter( 0 ),
StopNow( false ),
Extended( false ),
Watch( NULL ),
DirName( NULL ) {
Buffer.resize(dwBufferSize);
@@ -62,9 +65,11 @@ class WatcherWin32 : public Watcher {
LPARAM lParam;
DWORD NotifyFilter;
bool StopNow;
bool Extended;
FileWatcherImpl* Watch;
char* DirName;
sLastModifiedEvent LastModifiedEvent;
std::vector<std::pair<std::string, LARGE_INTEGER>> OldFiles;
};
} // namespace efsw

View File

@@ -4,13 +4,9 @@
#include <efsw/base.hpp>
#if defined( EFSW_PLATFORM_POSIX )
#include <efsw/platform/posix/ThreadImpl.hpp>
#include <efsw/platform/posix/MutexImpl.hpp>
#include <efsw/platform/posix/SystemImpl.hpp>
#include <efsw/platform/posix/FileSystemImpl.hpp>
#elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#include <efsw/platform/win/ThreadImpl.hpp>
#include <efsw/platform/win/MutexImpl.hpp>
#include <efsw/platform/win/SystemImpl.hpp>
#include <efsw/platform/win/FileSystemImpl.hpp>
#else

View File

@@ -1,28 +0,0 @@
#include <efsw/platform/posix/MutexImpl.hpp>
#if defined( EFSW_PLATFORM_POSIX )
namespace efsw { namespace Platform {
MutexImpl::MutexImpl() {
pthread_mutexattr_t attributes;
pthread_mutexattr_init( &attributes );
pthread_mutexattr_settype( &attributes, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &mMutex, &attributes );
}
MutexImpl::~MutexImpl() {
pthread_mutex_destroy( &mMutex );
}
void MutexImpl::lock() {
pthread_mutex_lock( &mMutex );
}
void MutexImpl::unlock() {
pthread_mutex_unlock( &mMutex );
}
}} // namespace efsw::Platform
#endif

View File

@@ -1,30 +0,0 @@
#ifndef EFSW_MUTEXIMPLPOSIX_HPP
#define EFSW_MUTEXIMPLPOSIX_HPP
#include <efsw/base.hpp>
#if defined( EFSW_PLATFORM_POSIX )
#include <pthread.h>
namespace efsw { namespace Platform {
class MutexImpl {
public:
MutexImpl();
~MutexImpl();
void lock();
void unlock();
private:
pthread_mutex_t mMutex;
};
}} // namespace efsw::Platform
#endif
#endif

View File

@@ -1,62 +0,0 @@
#include <efsw/Thread.hpp>
#include <efsw/platform/posix/ThreadImpl.hpp>
#if defined( EFSW_PLATFORM_POSIX )
#include <cassert>
#include <efsw/Debug.hpp>
#include <iostream>
namespace efsw { namespace Platform {
ThreadImpl::ThreadImpl( efsw::Thread* owner ) : mIsActive( false ) {
mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0;
if ( !mIsActive ) {
efDEBUG( "Failed to create thread\n" );
}
}
ThreadImpl::~ThreadImpl() {
terminate();
}
void ThreadImpl::wait() {
// Wait for the thread to finish, no timeout
if ( mIsActive ) {
assert( pthread_equal( pthread_self(), mThread ) == 0 );
mIsActive = pthread_join( mThread, NULL ) != 0;
}
}
void ThreadImpl::terminate() {
if ( mIsActive ) {
#if !defined( __ANDROID__ ) && !defined( ANDROID )
pthread_cancel( mThread );
#else
pthread_kill( mThread, SIGUSR1 );
#endif
mIsActive = false;
}
}
void* ThreadImpl::entryPoint( void* userData ) {
// Tell the thread to handle cancel requests immediatly
#ifdef PTHREAD_CANCEL_ASYNCHRONOUS
pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
#endif
// The Thread instance is stored in the user data
Thread* owner = static_cast<Thread*>( userData );
// Forward to the owner
owner->run();
return NULL;
}
}} // namespace efsw::Platform
#endif

View File

@@ -1,39 +0,0 @@
#ifndef EFSW_THREADIMPLPOSIX_HPP
#define EFSW_THREADIMPLPOSIX_HPP
#include <efsw/base.hpp>
#if defined( EFSW_PLATFORM_POSIX )
#include <efsw/Atomic.hpp>
#include <pthread.h>
namespace efsw {
class Thread;
namespace Platform {
class ThreadImpl {
public:
explicit ThreadImpl( efsw::Thread* owner );
~ThreadImpl();
void wait();
void terminate();
protected:
static void* entryPoint( void* userData );
pthread_t mThread;
Atomic<bool> mIsActive;
};
} // namespace Platform
} // namespace efsw
#endif
#endif

View File

@@ -1,25 +0,0 @@
#include <efsw/platform/win/MutexImpl.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
namespace efsw { namespace Platform {
MutexImpl::MutexImpl() {
InitializeCriticalSection( &mMutex );
}
MutexImpl::~MutexImpl() {
DeleteCriticalSection( &mMutex );
}
void MutexImpl::lock() {
EnterCriticalSection( &mMutex );
}
void MutexImpl::unlock() {
LeaveCriticalSection( &mMutex );
}
}} // namespace efsw::Platform
#endif

View File

@@ -1,33 +0,0 @@
#ifndef EFSW_MUTEXIMPLWIN_HPP
#define EFSW_MUTEXIMPLWIN_HPP
#include <efsw/base.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
namespace efsw { namespace Platform {
class MutexImpl {
public:
MutexImpl();
~MutexImpl();
void lock();
void unlock();
private:
CRITICAL_SECTION mMutex;
};
}} // namespace efsw::Platform
#endif
#endif

View File

@@ -1,56 +0,0 @@
#include <assert.h>
#include <efsw/Thread.hpp>
#include <efsw/platform/win/ThreadImpl.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#include <efsw/Debug.hpp>
namespace efsw { namespace Platform {
ThreadImpl::ThreadImpl( efsw::Thread* owner ) {
mThread = reinterpret_cast<HANDLE>(
_beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) );
if ( !mThread ) {
efDEBUG( "Failed to create thread\n" );
}
}
ThreadImpl::~ThreadImpl() {
if ( mThread ) {
CloseHandle( mThread );
}
}
void ThreadImpl::wait() {
// Wait for the thread to finish, no timeout
if ( mThread ) {
assert( mThreadId != GetCurrentThreadId() ); // A thread cannot wait for itself!
WaitForSingleObject( mThread, INFINITE );
}
}
void ThreadImpl::terminate() {
if ( mThread ) {
TerminateThread( mThread, 0 );
}
}
unsigned int __stdcall ThreadImpl::entryPoint( void* userData ) {
// The Thread instance is stored in the user data
Thread* owner = static_cast<Thread*>( userData );
// Forward to the owner
owner->run();
// Optional, but it is cleaner
_endthreadex( 0 );
return 0;
}
}} // namespace efsw::Platform
#endif

View File

@@ -1,42 +0,0 @@
#ifndef EFSW_THREADIMPLWIN_HPP
#define EFSW_THREADIMPLWIN_HPP
#include <efsw/base.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <process.h>
#include <windows.h>
namespace efsw {
class Thread;
namespace Platform {
class ThreadImpl {
public:
explicit ThreadImpl( efsw::Thread* owner );
~ThreadImpl();
void wait();
void terminate();
protected:
static unsigned int __stdcall entryPoint( void* userData );
HANDLE mThread;
unsigned int mThreadId;
};
} // namespace Platform
} // namespace efsw
#endif
#endif

View File

@@ -8,9 +8,9 @@
#include <time.h>
#ifdef _WIN32
#include <Windows.h>
#include <Windows.h>
#else
#include <unistd.h>
#include <unistd.h>
#endif
const char PATH_SEPARATOR =
@@ -32,10 +32,10 @@ void sleepMsecs( int msecs ) {
Sleep( msecs );
#else
sleep( msecs );
#endif
#endif
}
const char * getActionName( enum efsw_action action ) {
const char* getActionName( enum efsw_action action ) {
switch ( action ) {
case EFSW_ADD:
return "Add";
@@ -50,16 +50,15 @@ const char * getActionName( enum efsw_action action ) {
}
}
void handleFileAction( efsw_watcher watcher, efsw_watchid watchid,
const char* dir, const char* filename,
enum efsw_action action, const char* oldFilename,
void* param ) {
void handleFileAction( efsw_watcher watcher, efsw_watchid watchid, const char* dir,
const char* filename, enum efsw_action action, const char* oldFilename,
void* param ) {
if ( strlen( oldFilename ) == 0 ) {
printf( "Watch ID %ld DIR (%s) FILE (%s) has event %s\n",
watchid, dir, filename, getActionName( action ));
printf( "Watch ID %ld DIR (%s) FILE (%s) has event %s\n", watchid, dir, filename,
getActionName( action ) );
} else {
printf( "Watch ID %ld DIR (%s) FILE (from file %s to %s) has event %s\n",
watchid, dir, oldFilename, filename, getActionName( action ));
printf( "Watch ID %ld DIR (%s) FILE (from file %s to %s) has event %s\n", watchid, dir,
oldFilename, filename, getActionName( action ) );
}
}
@@ -87,17 +86,17 @@ int main( int argc, char** argv ) {
signal( SIGINT, sigend );
signal( SIGTERM, sigend );
printf("Press ^C to exit demo\n");
printf( "Press ^C to exit demo\n" );
bool commonTest = true;
bool useGeneric = false;
char *path = 0;
char* path = 0;
if ( argc >= 2 ) {
path = argv[1];
struct stat s;
if( stat(path,&s) == 0 && (s.st_mode & S_IFDIR) == S_IFDIR ) {
if ( stat( path, &s ) == 0 && ( s.st_mode & S_IFDIR ) == S_IFDIR ) {
commonTest = false;
}
@@ -115,24 +114,25 @@ int main( int argc, char** argv ) {
if ( commonTest ) {
char cwd[256];
getcwd( cwd, sizeof(cwd) );
getcwd( cwd, sizeof( cwd ) );
printf( "CurPath: %s\n", cwd );
/// starts watching
efsw_watch( fileWatcher );
/// add a watch to the system
char path1[256];
sprintf(path1, "%s%ctest", cwd, PATH_SEPARATOR );
handleWatchID( efsw_addwatch_withoptions( fileWatcher, path1, handleFileAction, true, 0, 0, 0 ) );
char path1[512];
snprintf( path1, sizeof( path1 ), "%s%ctest", cwd, PATH_SEPARATOR );
handleWatchID( efsw_addwatch_withoptions( fileWatcher, path1, handleFileAction, true, 0, 0,
0, NULL ) );
/// adds another watch after started watching...
sleepMsecs( 100 );
char path2[256];
sprintf(path2, "%s%ctest2", cwd, PATH_SEPARATOR );
efsw_watchid watchID = handleWatchID(
efsw_addwatch_withoptions( fileWatcher, path2, handleFileAction, true, 0, 0, 0 ) );
char path2[512];
snprintf( path2, sizeof( path2 ), "%s%ctest2", cwd, PATH_SEPARATOR );
efsw_watchid watchID = handleWatchID( efsw_addwatch_withoptions(
fileWatcher, path2, handleFileAction, true, 0, 0, 0, NULL ) );
/// delete the watch
if ( watchID > 0 ) {
@@ -159,6 +159,6 @@ int main( int argc, char** argv ) {
}
efsw_release( fileWatcher );
return 0;
}

View File

@@ -99,7 +99,7 @@ int main( int argc, char** argv ) {
std::cout << "CurPath: " << CurPath.c_str() << std::endl;
/// starts watching
/// starts watching
fileWatcher.watch();
/// add a watch to the system