mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Dep/efsw: Update to SpartanJ/efsw@f94a6616ab
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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() ) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -16,6 +16,7 @@ class WatcherInotify : public Watcher {
|
||||
WatchID InotifyID;
|
||||
|
||||
FileInfo DirInfo;
|
||||
bool syntheticEvents{ false };
|
||||
};
|
||||
|
||||
} // namespace efsw
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user