This commit is contained in:
Shauren
2024-05-29 12:23:06 +02:00
parent 67cb736950
commit 937e618533
78 changed files with 4612 additions and 5233 deletions

View File

@@ -8,9 +8,9 @@ Boost Process (Proposed for boost, but its not an official part of it yet. Used
http://www.highscore.de/boost/process0.5/
Version: 0.5
efws (Entropia File System Watcher - crossplatform file system watcher)
https://bitbucket.org/SpartanJ/efsw
Version: 1.0.0 e6afbec564e249771046c714b0c7f2154e4c7fef
efsw (Entropia File System Watcher - crossplatform file system watcher)
https://github.com/SpartanJ/efsw
Version: 1.3.1+ 36c1c7004a34b6f40719f0830bcfb10325415451
fmt (a small, safe and fast formatting library)
https://github.com/fmtlib/fmt

View File

@@ -1,6 +0,0 @@
repo: 78c2ea8c48b213ee0078d6326a1dd719d0844764
node: e6afbec564e249771046c714b0c7f2154e4c7fef
branch: default
latesttag: 1.0.0
latesttagdistance: 12
changessincelatesttag: 12

View File

@@ -1,68 +1,109 @@
if (BUILD_SHARED_LIBS)
set(SRCS
set(EFSW_CPP_SOURCE
src/efsw/Atomic.hpp
src/efsw/base.hpp
src/efsw/Debug.cpp
src/efsw/Debug.hpp
src/efsw/DirectorySnapshot.cpp
src/efsw/DirectorySnapshot.hpp
src/efsw/DirectorySnapshotDiff.cpp
src/efsw/DirectorySnapshotDiff.hpp
src/efsw/DirWatcherGeneric.cpp
src/efsw/DirWatcherGeneric.hpp
src/efsw/FileInfo.cpp
src/efsw/FileInfo.hpp
src/efsw/FileSystem.cpp
src/efsw/FileSystem.hpp
src/efsw/FileWatcher.cpp
src/efsw/FileWatcherCWrapper.cpp
src/efsw/FileWatcherGeneric.cpp
src/efsw/FileWatcherGeneric.hpp
src/efsw/FileWatcherImpl.cpp
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
src/efsw/WatcherGeneric.cpp)
src/efsw/Watcher.hpp
src/efsw/WatcherGeneric.cpp
src/efsw/WatcherGeneric.hpp
src/efsw/platform/platformimpl.hpp
)
if (WIN32)
list (APPEND SRCS
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/ThreadImpl.cpp)
src/efsw/platform/win/SystemImpl.hpp
src/efsw/platform/win/ThreadImpl.cpp
src/efsw/platform/win/ThreadImpl.hpp)
else ()
list (APPEND SRCS
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/ThreadImpl.cpp)
src/efsw/platform/posix/SystemImpl.hpp
src/efsw/platform/posix/ThreadImpl.cpp
src/efsw/platform/posix/ThreadImpl.hpp)
endif()
if (APPLE)
list (APPEND SRCS
list (APPEND EFSW_CPP_SOURCE
src/efsw/FileWatcherFSEvents.cpp
src/efsw/FileWatcherFSEvents.hpp
src/efsw/FileWatcherKqueue.cpp
src/efsw/FileWatcherKqueue.hpp
src/efsw/WatcherFSEvents.cpp
src/efsw/WatcherKqueue.cpp)
exec_program(uname ARGS -v OUTPUT_VARIABLE OSX_VERSION)
string(REGEX MATCH "[0-9]+" OSX_VERSION ${OSX_VERSION})
if (NOT OSX_VERSION GREATER 9)
set(OPTIONAL_COMPILE_DEFINITIONS "-DEFSW_FSEVENTS_NOT_SUPPORTED")
endif()
src/efsw/WatcherFSEvents.hpp
src/efsw/WatcherKqueue.cpp
src/efsw/WatcherKqueue.hpp)
set(OPTIONAL_LINK_LIBRARIES "-framework CoreFoundation" "-framework CoreServices")
elseif (WIN32)
list (APPEND SRCS
list (APPEND EFSW_CPP_SOURCE
src/efsw/FileWatcherWin32.cpp
src/efsw/WatcherWin32.cpp)
src/efsw/FileWatcherWin32.hpp
src/efsw/WatcherWin32.cpp
src/efsw/WatcherWin32.hpp)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
list (APPEND SRCS
list (APPEND EFSW_CPP_SOURCE
src/efsw/FileWatcherInotify.cpp
src/efsw/WatcherInotify.cpp)
if (NOT EXISTS "/usr/include/sys/inotify.h" AND NOT EXISTS "/usr/local/include/sys/inotify.h")
src/efsw/FileWatcherInotify.hpp
src/efsw/WatcherInotify.cpp
src/efsw/WatcherInotify.hpp)
find_path(EFSW_INOTIFY_H
NAMES
sys/inotify.h
NO_CACHE
)
if (EFSW_INOTIFY_H STREQUAL "EFSW_INOTIFY_H-NOTFOUND")
list (APPEND EFSW_CPP_SOURCE
src/efsw/inotify-nosys.h
)
set(OPTIONAL_COMPILE_DEFINITIONS "-DEFSW_INOTIFY_NOSYS")
endif()
elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
list (APPEND SRCS
list (APPEND EFSW_CPP_SOURCE
src/efsw/FileWatcherKqueue.cpp
src/efsw/WatcherKqueue.cpp)
src/efsw/FileWatcherKqueue.hpp
src/efsw/WatcherKqueue.cpp
src/efsw/WatcherKqueue.hpp)
endif()
add_library(efsw STATIC ${SRCS})
add_library(efsw STATIC ${EFSW_CPP_SOURCE})
target_include_directories(efsw
PUBLIC

View File

@@ -1,4 +1,4 @@
Copyright (c) 2012 Martín Lucas Golini
Copyright (c) 2020 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
@@ -19,4 +19,4 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
http://code.google.com/p/simplefilewatcher/ also MIT licensed.
http://code.google.com/p/simplefilewatcher/ also MIT licensed.

View File

@@ -1,5 +1,8 @@
Entropia File System Watcher
Entropia File System Watcher ![efsw](https://web.ensoft.dev/efsw/efsw-logo.svg)
============================
[![build status](https://img.shields.io/github/actions/workflow/status/SpartanJ/efsw/main.yml?branch=master)](https://github.com/SpartanJ/efsw/actions?query=workflow%3Abuild)
**efsw** is a C++ cross-platform file system watcher and notifier.
**efsw** monitors the file system asynchronously for changes to files and directories by watching a list of specified paths, and raises events when a directory or file change.
@@ -19,8 +22,8 @@ Entropia File System Watcher
* OS-independent generic watcher
(polling the disk for directory snapshots and comparing them periodically)
If any of the backend fails to start by any reason, it will fallback to the OS-independent implementation.
This should never happen, except for the Kqueue implementation, see `Platform limitations and clarifications`.
If any of the backend fails to start for any reason, it will fallback to the OS-independent implementation.
This should never happen, except for the Kqueue implementation; see `Platform limitations and clarifications`.
**Code License**
--------------
@@ -31,39 +34,41 @@ This should never happen, except for the Kqueue implementation, see `Platform li
```c++
// Inherits from the abstract listener class, and implements the the file action handler
class UpdateListener : public efsw::FileWatchListener
{
public:
UpdateListener() {}
void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" )
{
switch( action )
{
case efsw::Actions::Add:
std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Added" << std::endl;
break;
case efsw::Actions::Delete:
std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Delete" << std::endl;
break;
case efsw::Actions::Modified:
std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Modified" << std::endl;
break;
case efsw::Actions::Moved:
std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Moved from (" << oldFilename << ")" << std::endl;
break;
default:
std::cout << "Should never happen!" << std::endl;
}
}
class UpdateListener : public efsw::FileWatchListener {
public:
void handleFileAction( efsw::WatchID watchid, const std::string& dir,
const std::string& filename, efsw::Action action,
std::string oldFilename ) override {
switch ( action ) {
case efsw::Actions::Add:
std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Added"
<< std::endl;
break;
case efsw::Actions::Delete:
std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Delete"
<< std::endl;
break;
case efsw::Actions::Modified:
std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Modified"
<< std::endl;
break;
case efsw::Actions::Moved:
std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Moved from ("
<< oldFilename << ")" << std::endl;
break;
default:
std::cout << "Should never happen!" << std::endl;
}
}
};
// Create the file system watcher instance
// efsw::FileWatcher allow a first boolean parameter that indicates if it should start with the generic file watcher instead of the platform specific backend
efsw::FileWatcher * fileWatcher = new efsw::FileWatcher();
// efsw::FileWatcher allow a first boolean parameter that indicates if it should start with the
// generic file watcher instead of the platform specific backend
efsw::FileWatcher* fileWatcher = new efsw::FileWatcher();
// Create the instance of your efsw::FileWatcherListener implementation
UpdateListener * listener = new UpdateListener();
UpdateListener* listener = new UpdateListener();
// Add a folder to watch, and get the efsw::WatchID
// It will watch the /tmp folder recursively ( the third parameter indicates that is recursive )
@@ -73,11 +78,16 @@ efsw::WatchID watchID = fileWatcher->addWatch( "/tmp", listener, true );
// Adds another directory to watch. This time as non-recursive.
efsw::WatchID watchID2 = fileWatcher->addWatch( "/usr", listener, false );
// For Windows, adds another watch, specifying to use a bigger buffer, to not miss events
// (do not use for network locations, see efsw.hpp for details).
efsw::WatchID watchID3 = fileWatcher->addWatch( "c:\\temp", listener, true, { (BufferSize, 128*1024) } );
// Start watching asynchronously the directories
fileWatcher->watch();
// Remove the second watcher added
// You can also call removeWatch by passing the watch path ( it must end with an slash or backslash in windows, since that's how internally it's saved )
// You can also call removeWatch by passing the watch path ( it must end with an slash or backslash
// in windows, since that's how internally it's saved )
fileWatcher->removeWatch( watchID2 );
```
@@ -87,21 +97,21 @@ None :)
**Compiling**
------------
To generate project files you will need to [download and install](http://industriousone.com/premake/download) [Premake](http://industriousone.com/what-premake)
To generate project files you will need to [download and install](https://premake.github.io/download) [Premake](https://premake.github.io/docs/What-Is-Premake)
Then you can generate the project for your platform just going to the project directory where the premake4.lua file is located and then execute:
Then you can generate the project for your platform by just going to the project directory where the premake4.lua file is located and executing:
`premake4 gmake` to generate project Makefiles, then `cd make/*YOURPLATFORM*/`, and finally `make` or `make config=release` ( it will generate the static lib, the shared lib and the test application ).
or
`premake4 vs2010` to generate Visual Studio 2010 project.
`premake5 gmake2` to generate project Makefiles, then `cd make/*YOURPLATFORM*/`, and finally `make` or `make config=release_x86_64` ( it will generate the static lib, the shared lib and the test application ).
or
`premake4 xcode4` to generate Xcode 4 project.
`premake5 vs2022` to generate Visual Studio 2022 project.
There is also a cmake file that i don't oficially support but it works just fine, provided by [Mohammed Nafees](https://bitbucket.org/binaryking).
or
`premake5 xcode4` to generate Xcode 4 project.
There is also a cmake file that I don't officially support but it works just fine, provided by [Mohammed Nafees](https://github.com/mnafees) and improved by [Eugene Shalygin](https://github.com/zeule).
**Platform limitations and clarifications**
-------------------------------------------
@@ -112,21 +122,21 @@ handleFileAction returns UTF-8 strings in all platforms.
Windows and FSEvents Mac OS X implementation can't follow symlinks ( it will ignore followSymlinks() and allowOutOfScopeLinks() ).
Kqueue implementation is limited by the maximun number of file descriptors allowed per process by the OS, in the case of reaching the file descriptors limit ( in BSD around 18000 and in OS X around 10240 ) it will fallback to the generic file watcher.
Kqueue implementation is limited by the maximum number of file descriptors allowed per process by the OS. In the case of reaching the file descriptors limit ( in BSD around 18000 and in OS X around 10240 ), it will fallback to the generic file watcher.
OS X will only use Kqueue if OS X version is below to 10.5, and this implementation needs to be compiled separately from the OS X >= 10.5 implementation. Since there's no way to compile FSEvents backend in OS X below 10.5.
OS X will use only Kqueue if the OS X version is below 10.5. This implementation needs to be compiled separately from the OS X >= 10.5 implementation, since there's no way to compile FSEvents backend in OS X below 10.5.
FSEvents for OS X Lion and beyond in some cases will generate more actions that in reality ocurred, since fine-grained implementation of FSEvents doesn't give the order of the actions retrieved, in some cases i need to guess/aproximate the order of them.
FSEvents for OS X Lion and beyond in some cases will generate more actions than in reality ocurred, since fine-grained implementation of FSEvents doesn't give the order of the actions retrieved. In some cases I need to guess/approximate the order of them.
Generic watcher relies on the inode information to detect file and directories renames/move. Since Windows has no concept of inodes as Unix platforms do, there is no current reliable way of determining file/directory movement on Windows without help from the Windows API ( this is replaced with Add/Delete events ).
Linux versions below 2.6.13 are not supported, since inotify wasn't implemented yet. I'm not interested in support older kernels, since i don't see the point. If someone needs this open an issue in the issue tracker and i may consider implenent a dnotify backend.
Linux versions below 2.6.13 are not supported, since inotify wasn't implemented yet. I'm not interested in supporting older kernels, since I don't see the point. If someone needs this, open an issue in the issue tracker and I may consider implementing a dnotify backend.
OS-independent watcher, Kqueue and FSEvents for OS X below 10.5 keep cache of the directories structures, to be able to detect changes in the directories. This means that there's a memory overhead for this backends.
OS-independent watcher, Kqueue and FSEvents for OS X below 10.5 keep cache of the directories structures, to be able to detect changes in the directories. This means that there's a memory overhead for these backends.
**Useful information**
--------------------
The project also comes with a C API wrapper, contributed by [Sepul Sepehr Taghdisian](https://bitbucket.org/sepul).
The project also comes with a C API wrapper, contributed by [Sepul Sepehr Taghdisian](https://github.com/septag).
There's a string manipulation class not exposed in the efsw header ( efsw::String ) that can be used to make string encoding conversion.

View File

@@ -80,7 +80,22 @@ enum efsw_error
EFSW_OUTOFSCOPE = -3,
EFSW_NOTREADABLE = -4,
EFSW_REMOTE = -5,
EFSW_UNSPECIFIED = -6
EFSW_WATCHER_FAILED = -6,
EFSW_UNSPECIFIED = -7
};
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,
/// because a buffer larger than 64K will fail the folder being watched, see
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx)
EFSW_OPT_WIN_BUFFER_SIZE = 1,
/// 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
};
/// Basic interface for listening for file events.
@@ -94,6 +109,11 @@ typedef void (*efsw_pfn_fileaction_callback) (
void* param
);
typedef struct {
enum efsw_option option;
int value;
} efsw_watcher_option;
/**
* Creates a new file-watcher
* @param generic_mode Force the use of the Generic file watcher
@@ -103,15 +123,24 @@ 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);
/// Retreive last error occured by file-watcher
/// Retrieve last error occured by file-watcher
EFSW_API const char* efsw_getlasterror();
/// Add a directory watch. Same as the other addWatch, but doesn't have recursive option.
/// For backwards compatibility.
/// Reset file-watcher last error
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);
/// 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);
/// Remove a directory watch. This is a brute force search O(nlogn).
void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory);

View File

@@ -28,34 +28,37 @@
#ifndef ESFW_HPP
#define ESFW_HPP
#include <vector>
#include <string>
#include <list>
#include <vector>
#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 )
#ifndef EFSW_API
#define EFSW_API __attribute__( ( visibility( "default" ) ) )
#endif
#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
namespace efsw {
@@ -66,128 +69,174 @@ typedef long WatchID;
// forward declarations
class FileWatcherImpl;
class FileWatchListener;
class WatcherOption;
/// Actions to listen for. Rename will send two events, one for
/// the deletion of the old file, and one for the creation of the
/// new file.
namespace Actions {
enum Action
{
/// Sent when a file is created or renamed
Add = 1,
/// Sent when a file is deleted or renamed
Delete = 2,
/// Sent when a file is modified
Modified = 3,
/// Sent when a file is moved
Moved = 4
};
enum Action {
/// Sent when a file is created or renamed
Add = 1,
/// Sent when a file is deleted or renamed
Delete = 2,
/// Sent when a file is modified
Modified = 3,
/// Sent when a file is moved
Moved = 4
};
}
typedef Actions::Action Action;
/// Errors log namespace
namespace Errors {
enum Error
{
FileNotFound = -1,
FileRepeated = -2,
FileOutOfScope = -3,
FileNotReadable = -4,
FileRemote = -5, /** Directory in remote file system ( create a generic FileWatcher instance to watch this directory ). */
Unspecified = -6
enum Error {
NoError = 0,
FileNotFound = -1,
FileRepeated = -2,
FileOutOfScope = -3,
FileNotReadable = -4,
/// Directory in remote file system
/// ( create a generic FileWatcher instance to watch this directory ).
FileRemote = -5,
/// File system watcher failed to watch for changes.
WatcherFailed = -6,
Unspecified = -7
};
class EFSW_API Log
{
public:
/// @return The last error logged
static std::string getLastErrorLog();
class EFSW_API Log {
public:
/// @return The last error logged
static std::string getLastErrorLog();
/// Creates an error of the type specified
static Error createLastError( Error err, std::string log );
/// @return The code of the last error logged
static Error getLastErrorCode();
/// Reset last error
static void clearLastError();
/// Creates an error of the type specified
static Error createLastError( Error err, std::string log );
};
}
} // namespace Errors
typedef Errors::Error Error;
/// Optional file watcher settings.
namespace Options {
enum 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,
/// because a buffer larger than 64K will fail the folder being watched, see
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx)
WinBufferSize = 1,
/// 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
};
}
typedef Options::Option Option;
/// Listens to files and directories and dispatches events
/// to notify the listener of files and directories changes.
/// @class FileWatcher
class EFSW_API FileWatcher
{
public:
/// Default constructor, will use the default platform file watcher
FileWatcher();
class EFSW_API FileWatcher {
public:
/// Default constructor, will use the default platform file watcher
FileWatcher();
/// Constructor that lets you force the use of the Generic File Watcher
explicit FileWatcher( bool useGenericFileWatcher );
/// Constructor that lets you force the use of the Generic File Watcher
explicit FileWatcher( bool useGenericFileWatcher );
virtual ~FileWatcher();
virtual ~FileWatcher();
/// Add a directory watch. Same as the other addWatch, but doesn't have recursive option.
/// For backwards compatibility.
/// On error returns WatchID with Error type.
WatchID addWatch(const std::string& directory, FileWatchListener* watcher);
/// Add a directory watch. Same as the other addWatch, but doesn't have recursive option.
/// For backwards compatibility.
/// On error returns WatchID with Error type.
WatchID addWatch( const std::string& directory, FileWatchListener* watcher );
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive );
/// Remove a directory watch. This is a brute force search O(nlogn).
void removeWatch(const std::string& directory);
/// Add a directory watch, allowing customization with options
/// @param directory The folder to be watched
/// @param watcher The listener to receive events
/// @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 );
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch(WatchID watchid);
/// Remove a directory watch. This is a brute force search O(nlogn).
void removeWatch( const std::string& directory );
/// Starts watching ( in other thread )
void watch();
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch( WatchID watchid );
/// @return Returns a list of the directories that are being watched
std::list<std::string> directories();
/// Starts watching ( in other thread )
void watch();
/** Allow recursive watchers to follow symbolic links to other directories
* followSymlinks is disabled by default
*/
void followSymlinks( bool follow );
/// @return Returns a list of the directories that are being watched
std::vector<std::string> directories();
/** @return If can follow symbolic links to directorioes */
const bool& followSymlinks() const;
/** Allow recursive watchers to follow symbolic links to other directories
* followSymlinks is disabled by default
*/
void followSymlinks( bool follow );
/** 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.
* allowOutOfScopeLinks are disabled by default.
*/
void allowOutOfScopeLinks( bool allow );
/** @return If can follow symbolic links to directorioes */
const bool& followSymlinks() const;
/// @return Returns if out of scope links are allowed
const bool& allowOutOfScopeLinks() const;
private:
/// The implementation
FileWatcherImpl * mImpl;
bool mFollowSymlinks;
bool mOutOfScopeLinks;
/** 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. allowOutOfScopeLinks are disabled by default.
*/
void allowOutOfScopeLinks( bool allow );
/// @return Returns if out of scope links are allowed
const bool& allowOutOfScopeLinks() const;
private:
/// The implementation
FileWatcherImpl* mImpl;
bool mFollowSymlinks;
bool mOutOfScopeLinks;
};
/// Basic interface for listening for file events.
/// @class FileWatchListener
class FileWatchListener
{
public:
/// Handles the action file action
/// @param watchid The watch id for the directory
/// @param dir The directory
/// @param filename The filename that was accessed (not full path)
/// @param action Action that was performed
/// @param oldFilename The name of the file or directory moved
virtual void handleFileAction(WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" ) = 0;
class FileWatchListener {
public:
virtual ~FileWatchListener() {}
/// Handles the action file action
/// @param watchid The watch id for the directory
/// @param dir The directory
/// @param filename The filename that was accessed (not full path)
/// @param action Action that was performed
/// @param oldFilename The name of the file or directory moved
virtual void handleFileAction( WatchID watchid, const std::string& dir,
const std::string& filename, Action action,
std::string oldFilename = "" ) = 0;
};
}
/// Optional, typically platform specific parameter for customization of a watcher.
/// @class WatcherOption
class WatcherOption {
public:
WatcherOption(Option option, int value) : mOption(option), mValue(value) {};
Option mOption;
int mValue;
};
} // namespace efsw
#endif

View File

@@ -0,0 +1,33 @@
#ifndef EFSW_ATOMIC_BOOL_HPP
#define EFSW_ATOMIC_BOOL_HPP
#include <efsw/base.hpp>
#include <atomic>
namespace efsw {
template <typename T> class Atomic {
public:
explicit Atomic( T set = false ) : set_( set ) {}
Atomic& operator=( T set ) {
set_.store( set, std::memory_order_release );
return *this;
}
explicit operator T() const {
return set_.load( std::memory_order_acquire );
}
T load() const {
return set_.load( std::memory_order_acquire );
}
private:
std::atomic<T> set_;
};
} // namespace efsw
#endif

View File

@@ -3,83 +3,79 @@
#ifdef EFSW_COMPILER_MSVC
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <crtdbg.h>
#include <windows.h>
#endif
#include <cassert>
#include <cstdio>
#include <cstdarg>
#include <cstdio>
namespace efsw {
#ifdef DEBUG
void efREPORT_ASSERT( const char * File, int Line, const char * Exp )
{
#ifdef EFSW_COMPILER_MSVC
_CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp);
void efREPORT_ASSERT( const char* File, int Line, const char* Exp ) {
#ifdef EFSW_COMPILER_MSVC
_CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp );
DebugBreak();
#else
std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl;
DebugBreak();
#else
std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl;
#if defined(EFSW_COMPILER_GCC) && defined(EFSW_32BIT) && !defined(EFSW_ARM)
asm("int3");
#else
assert( false );
#endif
#endif
#if defined( EFSW_COMPILER_GCC ) && defined( EFSW_32BIT ) && !defined( EFSW_ARM )
asm( "int3" );
#else
assert( false );
#endif
#endif
}
void efPRINT( const char * format, ... )
{
char buf[2048];
va_list args;
void efPRINT( const char* format, ... ) {
char buf[2048];
va_list args;
va_start( args, format );
#ifdef EFSW_COMPILER_MSVC
_vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0]), format, args );
#else
vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args );
#endif
#ifdef EFSW_COMPILER_MSVC
_vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0] ), format, args );
#else
vsnprintf( buf, sizeof( buf ) / sizeof( buf[0] ), format, args );
#endif
va_end( args );
#ifdef EFSW_COMPILER_MSVC
OutputDebugStringA( buf );
#else
std::cout << buf;
#endif
#ifdef EFSW_COMPILER_MSVC
OutputDebugStringA( buf );
#else
std::cout << buf;
#endif
}
void efPRINTC( unsigned int cond, const char * format, ...)
{
void efPRINTC( unsigned int cond, const char* format, ... ) {
if ( 0 == cond )
return;
char buf[2048];
va_list args;
char buf[2048];
va_list args;
va_start( args, format );
#ifdef EFSW_COMPILER_MSVC
_vsnprintf_s( buf, efARRAY_SIZE( buf ), efARRAY_SIZE( buf ), format, args );
#else
vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args );
#endif
#ifdef EFSW_COMPILER_MSVC
_vsnprintf_s( buf, efARRAY_SIZE( buf ), efARRAY_SIZE( buf ), format, args );
#else
vsnprintf( buf, sizeof( buf ) / sizeof( buf[0] ), format, args );
#endif
va_end( args );
#ifdef EFSW_COMPILER_MSVC
OutputDebugStringA( buf );
#else
std::cout << buf;
#endif
#ifdef EFSW_COMPILER_MSVC
OutputDebugStringA( buf );
#else
std::cout << buf;
#endif
}
#endif
}
} // namespace efsw

View File

@@ -7,13 +7,19 @@ namespace efsw {
#ifdef DEBUG
void efREPORT_ASSERT( const char * File, const int Line, const char * Exp );
void efREPORT_ASSERT( const char* File, const int Line, const char* Exp );
#define efASSERT( expr ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #expr ); }
#define efASSERTM( expr, msg ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #msg ); }
#define efASSERT( expr ) \
if ( !( expr ) ) { \
efREPORT_ASSERT( __FILE__, __LINE__, #expr ); \
}
#define efASSERTM( expr, msg ) \
if ( !( expr ) ) { \
efREPORT_ASSERT( __FILE__, __LINE__, #msg ); \
}
void efPRINT ( const char * format, ... );
void efPRINTC ( unsigned int cond, const char * format, ... );
void efPRINT( const char* format, ... );
void efPRINTC( unsigned int cond, const char* format, ... );
#else
@@ -21,30 +27,34 @@ void efPRINTC ( unsigned int cond, const char * format, ... );
#define efASSERTM( expr, msg )
#ifndef EFSW_COMPILER_MSVC
#define efPRINT( format, args... ) {}
#define efPRINTC( cond, format, args... ) {}
#define efPRINT( format, args... ) \
{}
#define efPRINTC( cond, format, args... ) \
{}
#else
#define efPRINT
#define efPRINTC
#define efPRINT
#define efPRINTC
#endif
#endif
#ifdef EFSW_VERBOSE
#define efDEBUG efPRINT
#define efDEBUGC efPRINTC
#define efDEBUG efPRINT
#define efDEBUGC efPRINTC
#else
#ifndef EFSW_COMPILER_MSVC
#define efDEBUG( format, args... ) {}
#define efDEBUGC( cond, format, args... ) {}
#else
#define efDEBUG
#define efDEBUGC
#endif
#ifndef EFSW_COMPILER_MSVC
#define efDEBUG( format, args... ) \
{}
#define efDEBUGC( cond, format, args... ) \
{}
#else
#define efDEBUG
#define efDEBUGC
#endif
#endif
}
} // namespace efsw
#endif

View File

@@ -1,67 +1,53 @@
#include <efsw/Debug.hpp>
#include <efsw/DirWatcherGeneric.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/Debug.hpp>
#include <efsw/String.hpp>
namespace efsw {
DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles ) :
Parent( parent ),
Watch( ws ),
Recursive( recursive ),
Deleted( false )
{
DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric* parent, WatcherGeneric* ws,
const std::string& directory, bool recursive,
bool reportNewFiles ) :
Parent( parent ), Watch( ws ), Recursive( recursive ), Deleted( false ) {
resetDirectory( directory );
if ( !reportNewFiles )
{
if ( !reportNewFiles ) {
DirSnap.scan();
}
else
{
} else {
DirectorySnapshotDiff Diff = DirSnap.scan();
if ( Diff.changed() )
{
if ( Diff.changed() ) {
FileInfoList::iterator it;
DiffIterator( FilesCreated )
{
DiffIterator( FilesCreated ) {
handleAction( ( *it ).Filepath, Actions::Add );
}
}
}
}
DirWatcherGeneric::~DirWatcherGeneric()
{
DirWatcherGeneric::~DirWatcherGeneric() {
/// If the directory was deleted mark the files as deleted
if ( Deleted )
{
if ( Deleted ) {
DirectorySnapshotDiff Diff = DirSnap.scan();
if ( !DirSnap.exists() )
{
if ( !DirSnap.exists() ) {
FileInfoList::iterator it;
DiffIterator( FilesDeleted )
{
handleAction( (*it).Filepath, Actions::Delete );
DiffIterator( FilesDeleted ) {
handleAction( ( *it ).Filepath, Actions::Delete );
}
DiffIterator( DirsDeleted )
{
handleAction( (*it).Filepath, Actions::Delete );
DiffIterator( DirsDeleted ) {
handleAction( ( *it ).Filepath, Actions::Delete );
}
}
}
DirWatchMap::iterator it = Directories.begin();
for ( ; it != Directories.end(); ++it )
{
if ( Deleted )
{
for ( ; it != Directories.end(); ++it ) {
if ( Deleted ) {
/// If the directory was deleted, mark the flag for file deletion
it->second->Deleted = true;
}
@@ -70,24 +56,22 @@ DirWatcherGeneric::~DirWatcherGeneric()
}
}
void DirWatcherGeneric::resetDirectory( std::string directory )
{
void DirWatcherGeneric::resetDirectory( std::string directory ) {
std::string dir( directory );
/// Is this a recursive watch?
if ( Watch->Directory != directory )
{
if ( !( directory.size() && ( directory.at(0) == FileSystem::getOSSlash() || directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) )
{
if ( Watch->Directory != directory ) {
if ( !( directory.size() &&
( directory.at( 0 ) == FileSystem::getOSSlash() ||
directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) ) {
/// Get the real directory
if ( NULL != Parent )
{
FileSystem::dirAddSlashAtEnd(directory);
if ( NULL != Parent ) {
std::string parentPath( Parent->DirSnap.DirectoryInfo.Filepath );
FileSystem::dirAddSlashAtEnd( parentPath );
FileSystem::dirAddSlashAtEnd( directory );
dir = Parent->DirSnap.DirectoryInfo.Filepath + directory;
}
else
{
dir = parentPath + directory;
} else {
efDEBUG( "resetDirectory(): Parent is NULL. Fatal error." );
}
}
@@ -96,161 +80,140 @@ void DirWatcherGeneric::resetDirectory( std::string directory )
DirSnap.setDirectoryInfo( dir );
}
void DirWatcherGeneric::handleAction( const std::string &filename, unsigned long action, std::string oldFilename)
{
Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath, FileSystem::fileNameFromPath( filename ), (Action)action, oldFilename );
void DirWatcherGeneric::handleAction( const std::string& filename, unsigned long action,
std::string oldFilename ) {
Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath,
FileSystem::fileNameFromPath( filename ), (Action)action,
oldFilename );
}
void DirWatcherGeneric::addChilds( bool reportNewFiles )
{
if ( Recursive )
{
void DirWatcherGeneric::addChilds( bool reportNewFiles ) {
if ( Recursive ) {
/// Create the subdirectories watchers
std::string dir;
for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ )
{
if ( it->second.isDirectory() && it->second.isReadable() && !FileSystem::isRemoteFS( it->second.Filepath ) )
{
for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ ) {
if ( it->second.isDirectory() && it->second.isReadable() &&
!FileSystem::isRemoteFS( it->second.Filepath ) ) {
/// Check if the directory is a symbolic link
std::string curPath;
std::string link( FileSystem::getLinkRealPath( it->second.Filepath, curPath ) );
dir = it->first;
if ( "" != link )
{
if ( "" != link ) {
/// Avoid adding symlinks directories if it's now enabled
if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() )
{
if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) {
continue;
}
/// If it's a symlink check if the realpath exists as a watcher, or
/// if the path is outside the current dir
if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) )
{
if ( Watch->WatcherImpl->pathInWatches( link ) ||
Watch->pathInWatches( link ) ||
!Watch->WatcherImpl->linkAllowed( curPath, link ) ) {
continue;
}
else
{
} else {
dir = link;
}
}
else
{
if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) )
{
} else {
if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) {
continue;
}
}
if ( reportNewFiles )
{
if ( reportNewFiles ) {
handleAction( dir, Actions::Add );
}
Directories[dir] = new DirWatcherGeneric( this, Watch, dir, Recursive, reportNewFiles );
Directories[dir] =
new DirWatcherGeneric( this, Watch, dir, Recursive, reportNewFiles );
Directories[dir]->addChilds( reportNewFiles );
Directories[dir]->addChilds( reportNewFiles );
}
}
}
}
void DirWatcherGeneric::watch( bool reportOwnChange )
{
void DirWatcherGeneric::watch( bool reportOwnChange ) {
DirectorySnapshotDiff Diff = DirSnap.scan();
if ( reportOwnChange && Diff.DirChanged && NULL != Parent )
{
Watch->Listener->handleFileAction( Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ), FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified );
if ( reportOwnChange && Diff.DirChanged && NULL != Parent ) {
Watch->Listener->handleFileAction(
Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ),
FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified );
}
if ( Diff.changed() )
{
if ( Diff.changed() ) {
FileInfoList::iterator it;
MovedList::iterator mit;
/// Files
DiffIterator( FilesCreated )
{
handleAction( (*it).Filepath, Actions::Add );
DiffIterator( FilesCreated ) {
handleAction( ( *it ).Filepath, Actions::Add );
}
DiffIterator( FilesModified )
{
handleAction( (*it).Filepath, Actions::Modified );
DiffIterator( FilesModified ) {
handleAction( ( *it ).Filepath, Actions::Modified );
}
DiffIterator( FilesDeleted )
{
handleAction( (*it).Filepath, Actions::Delete );
DiffIterator( FilesDeleted ) {
handleAction( ( *it ).Filepath, Actions::Delete );
}
DiffMovedIterator( FilesMoved )
{
handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
DiffMovedIterator( FilesMoved ) {
handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first );
}
/// Directories
DiffIterator( DirsCreated )
{
createDirectory( (*it).Filepath );
DiffIterator( DirsCreated ) {
createDirectory( ( *it ).Filepath );
}
DiffIterator( DirsModified )
{
handleAction( (*it).Filepath, Actions::Modified );
DiffIterator( DirsModified ) {
handleAction( ( *it ).Filepath, Actions::Modified );
}
DiffIterator( DirsDeleted )
{
handleAction( (*it).Filepath, Actions::Delete );
removeDirectory( (*it).Filepath );
DiffIterator( DirsDeleted ) {
handleAction( ( *it ).Filepath, Actions::Delete );
removeDirectory( ( *it ).Filepath );
}
DiffMovedIterator( DirsMoved )
{
handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
moveDirectory( (*mit).first, (*mit).second.Filepath );
DiffMovedIterator( DirsMoved ) {
handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first );
moveDirectory( ( *mit ).first, ( *mit ).second.Filepath );
}
}
/// Process the subdirectories looking for changes
for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); ++dit )
{
for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); ++dit ) {
/// Just watch
dit->second->watch();
}
}
void DirWatcherGeneric::watchDir( std::string &dir )
{
DirWatcherGeneric * watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks() ?
findDirWatcher( dir ) :
findDirWatcherFast( dir );
void DirWatcherGeneric::watchDir( std::string& dir ) {
DirWatcherGeneric* watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks()
? findDirWatcher( dir )
: findDirWatcherFast( dir );
if ( NULL != watcher )
{
if ( NULL != watcher ) {
watcher->watch( true );
}
}
DirWatcherGeneric * DirWatcherGeneric::findDirWatcherFast( std::string dir )
{
DirWatcherGeneric* DirWatcherGeneric::findDirWatcherFast( std::string dir ) {
// remove the common base ( dir should always start with the same base as the watcher )
efASSERT( !dir.empty() );
efASSERT( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() );
efASSERT( DirSnap.DirectoryInfo.Filepath == dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) );
efASSERT( DirSnap.DirectoryInfo.Filepath ==
dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) );
if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() )
{
if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ) {
dir = dir.substr( DirSnap.DirectoryInfo.Filepath.size() - 1 );
}
if ( dir.size() == 1 )
{
if ( dir.size() == 1 ) {
efASSERT( dir[0] == FileSystem::getOSSlash() );
return this;
}
@@ -258,22 +221,18 @@ DirWatcherGeneric * DirWatcherGeneric::findDirWatcherFast( std::string dir )
size_t level = 0;
std::vector<std::string> dirv = String::split( dir, FileSystem::getOSSlash(), false );
DirWatcherGeneric * watcher = this;
DirWatcherGeneric* watcher = this;
while ( level < dirv.size() )
{
while ( level < dirv.size() ) {
// search the dir level in the current watcher
DirWatchMap::iterator it = watcher->Directories.find( dirv[ level ] );
DirWatchMap::iterator it = watcher->Directories.find( dirv[level] );
// found? continue with the next level
if ( it != watcher->Directories.end() )
{
if ( it != watcher->Directories.end() ) {
watcher = it->second;
level++;
}
else
{
} else {
// couldn't found the folder level?
// directory not watched
return NULL;
@@ -283,22 +242,16 @@ DirWatcherGeneric * DirWatcherGeneric::findDirWatcherFast( std::string dir )
return watcher;
}
DirWatcherGeneric * DirWatcherGeneric::findDirWatcher( std::string dir )
{
if ( DirSnap.DirectoryInfo.Filepath == dir )
{
DirWatcherGeneric* DirWatcherGeneric::findDirWatcher( std::string dir ) {
if ( DirSnap.DirectoryInfo.Filepath == dir ) {
return this;
}
else
{
DirWatcherGeneric * watcher = NULL;
} else {
DirWatcherGeneric* watcher = NULL;
for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it )
{
for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it ) {
watcher = it->second->findDirWatcher( dir );
if ( NULL != watcher )
{
if ( NULL != watcher ) {
return watcher;
}
}
@@ -307,22 +260,22 @@ DirWatcherGeneric * DirWatcherGeneric::findDirWatcher( std::string dir )
return NULL;
}
DirWatcherGeneric * DirWatcherGeneric::createDirectory( std::string newdir )
{
DirWatcherGeneric* DirWatcherGeneric::createDirectory( std::string newdir ) {
FileSystem::dirRemoveSlashAtEnd( newdir );
newdir = FileSystem::fileNameFromPath( newdir );
DirWatcherGeneric * dw = NULL;
DirWatcherGeneric* dw = NULL;
/// Check if the directory is a symbolic link
std::string dir( DirSnap.DirectoryInfo.Filepath + newdir );
std::string parentPath( DirSnap.DirectoryInfo.Filepath );
FileSystem::dirAddSlashAtEnd( parentPath );
std::string dir( parentPath + newdir );
FileSystem::dirAddSlashAtEnd( dir );
FileInfo fi( dir );
if ( !fi.isDirectory() || !fi.isReadable() || FileSystem::isRemoteFS( dir ) )
{
if ( !fi.isDirectory() || !fi.isReadable() || FileSystem::isRemoteFS( dir ) ) {
return NULL;
}
@@ -330,57 +283,48 @@ DirWatcherGeneric * DirWatcherGeneric::createDirectory( std::string newdir )
std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
bool skip = false;
if ( "" != link )
{
if ( "" != link ) {
/// Avoid adding symlinks directories if it's now enabled
if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() )
{
if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) {
skip = true;
}
/// If it's a symlink check if the realpath exists as a watcher, or
/// if the path is outside the current dir
if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) )
{
if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) ||
!Watch->WatcherImpl->linkAllowed( curPath, link ) ) {
skip = true;
}
else
{
} else {
dir = link;
}
}
else
{
if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) )
{
} else {
if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) {
skip = true;
}
}
if ( !skip )
{
if ( !skip ) {
handleAction( newdir, Actions::Add );
/// Creates the new directory watcher of the subfolder and check for new files
dw = new DirWatcherGeneric( this, Watch, dir, Recursive );
dw->addChilds();
dw->watch();
/// Add it to the list of directories
Directories[ newdir ] = dw;
Directories[newdir] = dw;
}
return dw;
}
void DirWatcherGeneric::removeDirectory( std::string dir )
{
void DirWatcherGeneric::removeDirectory( std::string dir ) {
FileSystem::dirRemoveSlashAtEnd( dir );
dir = FileSystem::fileNameFromPath( dir );
DirWatcherGeneric * dw = NULL;
DirWatcherGeneric* dw = NULL;
DirWatchMap::iterator dit;
/// Folder deleted
@@ -388,8 +332,7 @@ void DirWatcherGeneric::removeDirectory( std::string dir )
/// Search the folder, it should exists
dit = Directories.find( dir );
if ( dit != Directories.end() )
{
if ( dit != Directories.end() ) {
dw = dit->second;
/// Flag it as deleted so it fire the event for every file inside deleted
@@ -403,49 +346,43 @@ void DirWatcherGeneric::removeDirectory( std::string dir )
}
}
void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir )
{
void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir ) {
FileSystem::dirRemoveSlashAtEnd( oldDir );
oldDir = FileSystem::fileNameFromPath( oldDir );
FileSystem::dirRemoveSlashAtEnd( newDir );
newDir = FileSystem::fileNameFromPath( newDir );
DirWatcherGeneric * dw = NULL;
DirWatcherGeneric* dw = NULL;
DirWatchMap::iterator dit;
/// Directory existed?
dit = Directories.find( oldDir );
if ( dit != Directories.end() )
{
if ( dit != Directories.end() ) {
dw = dit->second;
/// Remove the directory from the map
Directories.erase( dit->first );
Directories[ newDir ] = dw;
Directories[newDir] = dw;
dw->resetDirectory( newDir );
}
}
bool DirWatcherGeneric::pathInWatches( std::string path )
{
if ( DirSnap.DirectoryInfo.Filepath == path )
{
bool DirWatcherGeneric::pathInWatches( std::string path ) {
if ( DirSnap.DirectoryInfo.Filepath == path ) {
return true;
}
for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it )
{
if ( it->second->pathInWatches( path ) )
{
return true;
}
for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it ) {
if ( it->second->pathInWatches( path ) ) {
return true;
}
}
return false;
}
}
} // namespace efsw

View File

@@ -1,55 +1,57 @@
#ifndef EFSW_DIRWATCHERGENERIC_HPP
#define EFSW_DIRWATCHERGENERIC_HPP
#include <efsw/WatcherGeneric.hpp>
#include <efsw/FileInfo.hpp>
#include <efsw/DirectorySnapshot.hpp>
#include <efsw/FileInfo.hpp>
#include <efsw/WatcherGeneric.hpp>
#include <map>
namespace efsw {
class DirWatcherGeneric
{
public:
typedef std::map<std::string, DirWatcherGeneric*> DirWatchMap;
class DirWatcherGeneric {
public:
typedef std::map<std::string, DirWatcherGeneric*> DirWatchMap;
DirWatcherGeneric * Parent;
WatcherGeneric * Watch;
DirectorySnapshot DirSnap;
DirWatchMap Directories;
bool Recursive;
DirWatcherGeneric* Parent;
WatcherGeneric* Watch;
DirectorySnapshot DirSnap;
DirWatchMap Directories;
bool Recursive;
DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles = false );
DirWatcherGeneric( DirWatcherGeneric* parent, WatcherGeneric* ws, const std::string& directory,
bool recursive, bool reportNewFiles = false );
~DirWatcherGeneric();
~DirWatcherGeneric();
void watch( bool reportOwnChange = false );
void watch( bool reportOwnChange = false );
void watchDir( std::string& dir );
void watchDir( std::string& dir );
static bool isDir( const std::string& directory );
static bool isDir( const std::string& directory );
bool pathInWatches( std::string path );
bool pathInWatches( std::string path );
void addChilds( bool reportNewFiles = true );
void addChilds( bool reportNewFiles = true );
DirWatcherGeneric * findDirWatcher( std::string dir );
DirWatcherGeneric* findDirWatcher( std::string dir );
DirWatcherGeneric * findDirWatcherFast( std::string dir );
protected:
bool Deleted;
DirWatcherGeneric* findDirWatcherFast( std::string dir );
DirWatcherGeneric * createDirectory( std::string newdir );
protected:
bool Deleted;
void removeDirectory( std::string dir );
DirWatcherGeneric* createDirectory( std::string newdir );
void moveDirectory( std::string oldDir, std::string newDir );
void removeDirectory( std::string dir );
void resetDirectory( std::string directory );
void moveDirectory( std::string oldDir, std::string newDir );
void handleAction( const std::string& filename, unsigned long action, std::string oldFilename = "");
void resetDirectory( std::string directory );
void handleAction( const std::string& filename, unsigned long action,
std::string oldFilename = "" );
};
}
} // namespace efsw
#endif

View File

@@ -3,44 +3,32 @@
namespace efsw {
DirectorySnapshot::DirectorySnapshot()
{
}
DirectorySnapshot::DirectorySnapshot() {}
DirectorySnapshot::DirectorySnapshot( std::string directory )
{
DirectorySnapshot::DirectorySnapshot( std::string directory ) {
init( directory );
}
DirectorySnapshot::~DirectorySnapshot()
{
}
DirectorySnapshot::~DirectorySnapshot() {}
void DirectorySnapshot::init( std::string directory )
{
void DirectorySnapshot::init( std::string directory ) {
setDirectoryInfo( directory );
initFiles();
}
bool DirectorySnapshot::exists()
{
bool DirectorySnapshot::exists() {
return DirectoryInfo.exists();
}
void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff )
{
void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff ) {
FileInfo fi;
for ( FileInfoMap::iterator it = Files.begin(); it != Files.end(); it++ )
{
for ( FileInfoMap::iterator it = Files.begin(); it != Files.end(); it++ ) {
fi = it->second;
if ( fi.isDirectory() )
{
if ( fi.isDirectory() ) {
Diff.DirsDeleted.push_back( fi );
}
else
{
} else {
Diff.FilesDeleted.push_back( fi );
}
}
@@ -48,51 +36,44 @@ void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff )
Files.clear();
}
void DirectorySnapshot::setDirectoryInfo( std::string directory )
{
void DirectorySnapshot::setDirectoryInfo( std::string directory ) {
DirectoryInfo = FileInfo( directory );
}
void DirectorySnapshot::initFiles()
{
void DirectorySnapshot::initFiles() {
Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath );
FileInfoMap::iterator it = Files.begin();
std::list<std::string> eraseFiles;
std::vector<std::string> eraseFiles;
/// Remove all non regular files and non directories
for ( ; it != Files.end(); it++ )
{
if ( !it->second.isRegularFile() && !it->second.isDirectory() )
{
for ( ; it != Files.end(); it++ ) {
if ( !it->second.isRegularFile() && !it->second.isDirectory() ) {
eraseFiles.push_back( it->first );
}
}
for ( std::list<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); eit++ )
{
for ( std::vector<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end();
eit++ ) {
Files.erase( *eit );
}
}
DirectorySnapshotDiff DirectorySnapshot::scan()
{
DirectorySnapshotDiff Diff;
DirectorySnapshotDiff DirectorySnapshot::scan() {
DirectorySnapshotDiff Diff;
Diff.clear();
FileInfo curFI( DirectoryInfo.Filepath );
Diff.DirChanged = DirectoryInfo != curFI;
Diff.DirChanged = DirectoryInfo != curFI;
if ( Diff.DirChanged )
{
if ( Diff.DirChanged ) {
DirectoryInfo = curFI;
}
/// If the directory was erased, create the events for files and directories deletion
if ( !curFI.exists() )
{
if ( !curFI.exists() ) {
deleteAll( Diff );
return Diff;
@@ -100,8 +81,7 @@ DirectorySnapshotDiff DirectorySnapshot::scan()
FileInfoMap files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath );
if ( files.empty() && Files.empty() )
{
if ( files.empty() && Files.empty() ) {
return Diff;
}
@@ -110,52 +90,43 @@ DirectorySnapshotDiff DirectorySnapshot::scan()
FileInfoMap::iterator it;
FileInfoMap::iterator fiIt;
if ( Diff.DirChanged )
{
if ( Diff.DirChanged ) {
FilesCpy = Files;
}
for ( it = files.begin(); it != files.end(); it++ )
{
fi = it->second;
for ( it = files.begin(); it != files.end(); it++ ) {
fi = it->second;
/// File existed before?
fiIt = Files.find( it->first );
if ( fiIt != Files.end() )
{
if ( fiIt != Files.end() ) {
/// Erase from the file list copy
FilesCpy.erase( it->first );
/// File changed?
if ( (*fiIt).second != fi )
{
if ( ( *fiIt ).second != fi ) {
/// Update the new file info
Files[ it->first ] = fi;
Files[it->first] = fi;
/// handle modified event
if ( fi.isDirectory() )
{
if ( fi.isDirectory() ) {
Diff.DirsModified.push_back( fi );
}
else
{
} else {
Diff.FilesModified.push_back( fi );
}
}
}
/// Only add regular files or directories
else if ( fi.isRegularFile() || fi.isDirectory() )
{
else if ( fi.isRegularFile() || fi.isDirectory() ) {
/// New file found
Files[ it->first ] = fi;
Files[it->first] = fi;
FileInfoMap::iterator fit;
std::string oldFile = "";
/// Check if the same inode already existed
if ( ( fit = nodeInFiles( fi ) ) != Files.end() )
{
if ( ( fit = nodeInFiles( fi ) ) != Files.end() ) {
oldFile = fit->first;
/// Avoid firing a Delete event
@@ -164,45 +135,32 @@ DirectorySnapshotDiff DirectorySnapshot::scan()
/// Delete the old file name
Files.erase( fit->first );
if ( fi.isDirectory() )
{
if ( fi.isDirectory() ) {
Diff.DirsMoved.push_back( std::make_pair( oldFile, fi ) );
}
else
{
} else {
Diff.FilesMoved.push_back( std::make_pair( oldFile, fi ) );
}
}
else
{
if ( fi.isDirectory() )
{
} else {
if ( fi.isDirectory() ) {
Diff.DirsCreated.push_back( fi );
}
else
{
} else {
Diff.FilesCreated.push_back( fi );
}
}
}
}
if ( !Diff.DirChanged )
{
if ( !Diff.DirChanged ) {
return Diff;
}
/// The files or directories that remains were deleted
for ( it = FilesCpy.begin(); it != FilesCpy.end(); it++ )
{
for ( it = FilesCpy.begin(); it != FilesCpy.end(); it++ ) {
fi = it->second;
if ( fi.isDirectory() )
{
if ( fi.isDirectory() ) {
Diff.DirsDeleted.push_back( fi );
}
else
{
} else {
Diff.FilesDeleted.push_back( fi );
}
@@ -213,16 +171,12 @@ DirectorySnapshotDiff DirectorySnapshot::scan()
return Diff;
}
FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi )
{
FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi ) {
FileInfoMap::iterator it;
if ( FileInfo::inodeSupported() )
{
for ( it = Files.begin(); it != Files.end(); it++ )
{
if ( it->second.sameInode( fi ) && it->second.Filepath != fi.Filepath )
{
if ( FileInfo::inodeSupported() ) {
for ( it = Files.begin(); it != Files.end(); it++ ) {
if ( it->second.sameInode( fi ) && it->second.Filepath != fi.Filepath ) {
return it;
}
}
@@ -231,33 +185,28 @@ FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi )
return Files.end();
}
void DirectorySnapshot::addFile( std::string path )
{
void DirectorySnapshot::addFile( std::string path ) {
std::string name( FileSystem::fileNameFromPath( path ) );
Files[ name ] = FileInfo( path );
Files[name] = FileInfo( path );
}
void DirectorySnapshot::removeFile( std::string path )
{
void DirectorySnapshot::removeFile( std::string path ) {
std::string name( FileSystem::fileNameFromPath( path ) );
FileInfoMap::iterator it = Files.find( name );
if ( Files.end() != it )
{
if ( Files.end() != it ) {
Files.erase( it );
}
}
void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath )
{
void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath ) {
removeFile( oldPath );
addFile( newPath );
}
void DirectorySnapshot::updateFile(std::string path)
{
void DirectorySnapshot::updateFile( std::string path ) {
addFile( path );
}
}
} // namespace efsw

View File

@@ -5,42 +5,41 @@
namespace efsw {
class DirectorySnapshot
{
public:
FileInfo DirectoryInfo;
FileInfoMap Files;
class DirectorySnapshot {
public:
FileInfo DirectoryInfo;
FileInfoMap Files;
void setDirectoryInfo( std::string directory );
void setDirectoryInfo( std::string directory );
DirectorySnapshot();
DirectorySnapshot();
DirectorySnapshot( std::string directory );
DirectorySnapshot( std::string directory );
~DirectorySnapshot();
~DirectorySnapshot();
void init( std::string directory );
void init( std::string directory );
bool exists();
bool exists();
DirectorySnapshotDiff scan();
DirectorySnapshotDiff scan();
FileInfoMap::iterator nodeInFiles( FileInfo& fi );
FileInfoMap::iterator nodeInFiles( FileInfo& fi );
void addFile( std::string path );
void addFile( std::string path );
void removeFile( std::string path );
void removeFile( std::string path );
void moveFile( std::string oldPath, std::string newPath );
void moveFile( std::string oldPath, std::string newPath );
void updateFile( std::string path );
protected:
void initFiles();
void updateFile( std::string path );
void deleteAll( DirectorySnapshotDiff &Diff );
protected:
void initFiles();
void deleteAll( DirectorySnapshotDiff& Diff );
};
}
} // namespace efsw
#endif

View File

@@ -2,8 +2,7 @@
namespace efsw {
void DirectorySnapshotDiff::clear()
{
void DirectorySnapshotDiff::clear() {
FilesCreated.clear();
FilesModified.clear();
FilesMoved.clear();
@@ -14,16 +13,10 @@ void DirectorySnapshotDiff::clear()
DirsDeleted.clear();
}
bool DirectorySnapshotDiff::changed()
{
return !FilesCreated.empty() ||
!FilesModified.empty() ||
!FilesMoved.empty() ||
!FilesDeleted.empty() ||
!DirsCreated.empty() ||
!DirsModified.empty() ||
!DirsMoved.empty() ||
!DirsDeleted.empty();
bool DirectorySnapshotDiff::changed() {
return !FilesCreated.empty() || !FilesModified.empty() || !FilesMoved.empty() ||
!FilesDeleted.empty() || !DirsCreated.empty() || !DirsModified.empty() ||
!DirsMoved.empty() || !DirsDeleted.empty();
}
}
} // namespace efsw

View File

@@ -5,31 +5,31 @@
namespace efsw {
class DirectorySnapshotDiff
{
public:
FileInfoList FilesDeleted;
FileInfoList FilesCreated;
FileInfoList FilesModified;
MovedList FilesMoved;
FileInfoList DirsDeleted;
FileInfoList DirsCreated;
FileInfoList DirsModified;
MovedList DirsMoved;
bool DirChanged;
class DirectorySnapshotDiff {
public:
FileInfoList FilesDeleted;
FileInfoList FilesCreated;
FileInfoList FilesModified;
MovedList FilesMoved;
FileInfoList DirsDeleted;
FileInfoList DirsCreated;
FileInfoList DirsModified;
MovedList DirsMoved;
bool DirChanged;
void clear();
void clear();
bool changed();
bool changed();
};
#define DiffIterator( FileInfoListName ) it = Diff.FileInfoListName.begin(); \
for ( ; it != Diff.FileInfoListName.end(); it++ )
#define DiffIterator( FileInfoListName ) \
it = Diff.FileInfoListName.begin(); \
for ( ; it != Diff.FileInfoListName.end(); it++ )
#define DiffMovedIterator( MovedListName ) mit = Diff.MovedListName.begin(); \
for ( ; mit != Diff.MovedListName.end(); mit++ )
#define DiffMovedIterator( MovedListName ) \
mit = Diff.MovedListName.begin(); \
for ( ; mit != Diff.MovedListName.end(); mit++ )
}
} // namespace efsw
#endif

View File

@@ -16,208 +16,175 @@
#include <stdlib.h>
#ifdef EFSW_COMPILER_MSVC
#ifndef S_ISDIR
#define S_ISDIR(f) ((f)&_S_IFDIR)
#endif
#ifndef S_ISDIR
#define S_ISDIR( f ) ( (f)&_S_IFDIR )
#endif
#ifndef S_ISREG
#define S_ISREG(f) ((f)&_S_IFREG)
#endif
#ifndef S_ISREG
#define S_ISREG( f ) ( (f)&_S_IFREG )
#endif
#ifndef S_ISRDBL
#define S_ISRDBL(f) ((f)&_S_IREAD)
#endif
#ifndef S_ISRDBL
#define S_ISRDBL( f ) ( (f)&_S_IREAD )
#endif
#else
#include <unistd.h>
#include <unistd.h>
#ifndef S_ISRDBL
#define S_ISRDBL(f) ((f)&S_IRUSR)
#endif
#ifndef S_ISRDBL
#define S_ISRDBL( f ) ( (f)&S_IRUSR )
#endif
#endif
namespace efsw {
bool FileInfo::exists( const std::string& filePath )
{
bool FileInfo::exists( const std::string& filePath ) {
FileInfo fi( filePath );
return fi.exists();
}
bool FileInfo::isLink( const std::string& filePath )
{
bool FileInfo::isLink( const std::string& filePath ) {
FileInfo fi( filePath, true );
return fi.isLink();
}
bool FileInfo::inodeSupported()
{
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
bool FileInfo::inodeSupported() {
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
return true;
#else
#else
return false;
#endif
#endif
}
FileInfo::FileInfo() :
ModificationTime(0),
OwnerId(0),
GroupId(0),
Permissions(0),
Inode(0)
{}
ModificationTime( 0 ), OwnerId( 0 ), GroupId( 0 ), Permissions( 0 ), Inode( 0 ) {}
FileInfo::FileInfo( const std::string& filepath ) :
Filepath( filepath ),
ModificationTime(0),
OwnerId(0),
GroupId(0),
Permissions(0),
Inode(0)
{
ModificationTime( 0 ),
OwnerId( 0 ),
GroupId( 0 ),
Permissions( 0 ),
Inode( 0 ) {
getInfo();
}
FileInfo::FileInfo( const std::string& filepath, bool linkInfo ) :
Filepath( filepath ),
ModificationTime(0),
OwnerId(0),
GroupId(0),
Permissions(0),
Inode(0)
{
if ( linkInfo )
{
ModificationTime( 0 ),
OwnerId( 0 ),
GroupId( 0 ),
Permissions( 0 ),
Inode( 0 ) {
if ( linkInfo ) {
getRealInfo();
}
else
{
} else {
getInfo();
}
}
void FileInfo::getInfo()
{
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
if ( Filepath.size() == 3 && Filepath[1] == ':' && Filepath[2] == FileSystem::getOSSlash() )
{
void FileInfo::getInfo() {
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
if ( Filepath.size() == 3 && Filepath[1] == ':' && Filepath[2] == FileSystem::getOSSlash() ) {
Filepath += FileSystem::getOSSlash();
}
#endif
#endif
/// Why i'm doing this? stat in mingw32 doesn't work for directories if the dir path ends with a path slash
/// Why i'm doing this? stat in mingw32 doesn't work for directories if the dir path ends with a
/// path slash
bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
if ( slashAtEnd )
{
if ( slashAtEnd ) {
FileSystem::dirRemoveSlashAtEnd( Filepath );
}
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
struct stat st;
int res = stat( Filepath.c_str(), &st );
#else
#else
struct _stat st;
int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
#endif
#endif
if ( 0 == res )
{
ModificationTime = st.st_mtime;
Size = st.st_size;
OwnerId = st.st_uid;
GroupId = st.st_gid;
Permissions = st.st_mode;
Inode = st.st_ino;
if ( 0 == res ) {
ModificationTime = st.st_mtime;
Size = st.st_size;
OwnerId = st.st_uid;
GroupId = st.st_gid;
Permissions = st.st_mode;
Inode = st.st_ino;
}
if ( slashAtEnd )
{
if ( slashAtEnd ) {
FileSystem::dirAddSlashAtEnd( Filepath );
}
}
void FileInfo::getRealInfo()
{
void FileInfo::getRealInfo() {
bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
if ( slashAtEnd )
{
if ( slashAtEnd ) {
FileSystem::dirRemoveSlashAtEnd( Filepath );
}
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
struct stat st;
int res = lstat( Filepath.c_str(), &st );
#else
#else
struct _stat st;
int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
#endif
#endif
if ( 0 == res )
{
ModificationTime = st.st_mtime;
Size = st.st_size;
OwnerId = st.st_uid;
GroupId = st.st_gid;
Permissions = st.st_mode;
Inode = st.st_ino;
if ( 0 == res ) {
ModificationTime = st.st_mtime;
Size = st.st_size;
OwnerId = st.st_uid;
GroupId = st.st_gid;
Permissions = st.st_mode;
Inode = st.st_ino;
}
if ( slashAtEnd )
{
if ( slashAtEnd ) {
FileSystem::dirAddSlashAtEnd( Filepath );
}
}
bool FileInfo::operator==( const FileInfo& Other ) const
{
return ( ModificationTime == Other.ModificationTime &&
Size == Other.Size &&
OwnerId == Other.OwnerId &&
GroupId == Other.GroupId &&
Permissions == Other.Permissions &&
Inode == Other.Inode
);
bool FileInfo::operator==( const FileInfo& Other ) const {
return ( ModificationTime == Other.ModificationTime && Size == Other.Size &&
OwnerId == Other.OwnerId && GroupId == Other.GroupId &&
Permissions == Other.Permissions && Inode == Other.Inode );
}
bool FileInfo::isDirectory() const
{
return 0 != S_ISDIR(Permissions);
bool FileInfo::isDirectory() const {
return 0 != S_ISDIR( Permissions );
}
bool FileInfo::isRegularFile() const
{
return 0 != S_ISREG(Permissions);
bool FileInfo::isRegularFile() const {
return 0 != S_ISREG( Permissions );
}
bool FileInfo::isReadable() const
{
bool FileInfo::isReadable() const {
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
static bool isRoot = getuid() == 0;
return isRoot || 0 != S_ISRDBL(Permissions);
return isRoot || 0 != S_ISRDBL( Permissions );
#else
return 0 != S_ISRDBL(Permissions);
return 0 != S_ISRDBL( Permissions );
#endif
}
bool FileInfo::isLink() const
{
bool FileInfo::isLink() const {
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
return S_ISLNK(Permissions);
return S_ISLNK( Permissions );
#else
return false;
#endif
}
std::string FileInfo::linksTo()
{
std::string FileInfo::linksTo() {
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
if ( isLink() )
{
char * ch = realpath( Filepath.c_str(), NULL);
if ( isLink() ) {
char* ch = realpath( Filepath.c_str(), NULL );
if ( NULL != ch )
{
if ( NULL != ch ) {
std::string tstr( ch );
free( ch );
@@ -226,16 +193,14 @@ std::string FileInfo::linksTo()
}
}
#endif
return std::string("");
return std::string( "" );
}
bool FileInfo::exists()
{
bool FileInfo::exists() {
bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
if ( slashAtEnd )
{
FileSystem::dirRemoveSlashAtEnd(Filepath);
if ( slashAtEnd ) {
FileSystem::dirRemoveSlashAtEnd( Filepath );
}
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
@@ -246,34 +211,30 @@ bool FileInfo::exists()
int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
#endif
if (slashAtEnd)
{
FileSystem::dirAddSlashAtEnd(Filepath);
if ( slashAtEnd ) {
FileSystem::dirAddSlashAtEnd( Filepath );
}
return 0 == res;
}
FileInfo& FileInfo::operator=( const FileInfo& Other )
{
this->Filepath = Other.Filepath;
this->Size = Other.Size;
this->ModificationTime = Other.ModificationTime;
this->GroupId = Other.GroupId;
this->OwnerId = Other.OwnerId;
this->Permissions = Other.Permissions;
this->Inode = Other.Inode;
FileInfo& FileInfo::operator=( const FileInfo& Other ) {
this->Filepath = Other.Filepath;
this->Size = Other.Size;
this->ModificationTime = Other.ModificationTime;
this->GroupId = Other.GroupId;
this->OwnerId = Other.OwnerId;
this->Permissions = Other.Permissions;
this->Inode = Other.Inode;
return *this;
}
bool FileInfo::sameInode( const FileInfo& Other ) const
{
bool FileInfo::sameInode( const FileInfo& Other ) const {
return inodeSupported() && Inode == Other.Inode;
}
bool FileInfo::operator!=( const FileInfo& Other ) const
{
return !(*this == Other);
bool FileInfo::operator!=( const FileInfo& Other ) const {
return !( *this == Other );
}
}
} // namespace efsw

View File

@@ -2,65 +2,63 @@
#define EFSW_FILEINFO_HPP
#include <efsw/base.hpp>
#include <string>
#include <vector>
#include <map>
#include <list>
#include <string>
namespace efsw {
class FileInfo
{
public:
static bool exists( const std::string& filePath );
class FileInfo {
public:
static bool exists( const std::string& filePath );
static bool isLink( const std::string& filePath );
static bool isLink( const std::string& filePath );
static bool inodeSupported();
static bool inodeSupported();
FileInfo();
FileInfo();
FileInfo( const std::string& filepath );
FileInfo( const std::string& filepath );
FileInfo( const std::string& filepath, bool linkInfo );
FileInfo( const std::string& filepath, bool linkInfo );
bool operator==( const FileInfo& Other ) const;
bool operator==( const FileInfo& Other ) const;
bool operator!=( const FileInfo& Other ) const;
bool operator!=( const FileInfo& Other ) const;
FileInfo& operator=( const FileInfo& Other );
FileInfo& operator=( const FileInfo& Other );
bool isDirectory() const;
bool isDirectory() const;
bool isRegularFile() const;
bool isRegularFile() const;
bool isReadable() const;
bool isReadable() const;
bool sameInode( const FileInfo& Other ) const;
bool sameInode( const FileInfo& Other ) const;
bool isLink() const;
bool isLink() const;
std::string linksTo();
std::string linksTo();
bool exists();
bool exists();
void getInfo();
void getInfo();
void getRealInfo();
void getRealInfo();
std::string Filepath;
Uint64 ModificationTime;
Uint64 Size;
Uint32 OwnerId;
Uint32 GroupId;
Uint32 Permissions;
Uint64 Inode;
std::string Filepath;
Uint64 ModificationTime;
Uint64 Size;
Uint32 OwnerId;
Uint32 GroupId;
Uint32 Permissions;
Uint64 Inode;
};
typedef std::map<std::string, FileInfo> FileInfoMap;
typedef std::list<FileInfo> FileInfoList;
typedef std::list< std::pair< std::string, FileInfo> > MovedList;
typedef std::map<std::string, FileInfo> FileInfoMap;
typedef std::vector<FileInfo> FileInfoList;
typedef std::vector<std::pair<std::string, FileInfo>> MovedList;
}
} // namespace efsw
#endif

View File

@@ -1,3 +1,4 @@
#include <cstring>
#include <efsw/FileSystem.hpp>
#include <efsw/platform/platformimpl.hpp>
@@ -7,8 +8,7 @@
namespace efsw {
bool FileSystem::isDirectory( const std::string& path )
{
bool FileSystem::isDirectory( const std::string& path ) {
return Platform::FileSystem::isDirectory( path );
}
@@ -18,68 +18,56 @@ FileInfoMap FileSystem::filesInfoFromPath( std::string path ) {
return Platform::FileSystem::filesInfoFromPath( path );
}
char FileSystem::getOSSlash()
{
char FileSystem::getOSSlash() {
return Platform::FileSystem::getOSSlash();
}
bool FileSystem::slashAtEnd( std::string &dir )
{
return ( dir.size() && dir[ dir.size() - 1 ] == getOSSlash() );
bool FileSystem::slashAtEnd( std::string& dir ) {
return ( dir.size() && dir[dir.size() - 1] == getOSSlash() );
}
void FileSystem::dirAddSlashAtEnd( std::string& dir )
{
if ( dir.size() > 1 && dir[ dir.size() - 1 ] != getOSSlash() )
{
void FileSystem::dirAddSlashAtEnd( std::string& dir ) {
if ( dir.size() >= 1 && dir[dir.size() - 1] != getOSSlash() ) {
dir.push_back( getOSSlash() );
}
}
void FileSystem::dirRemoveSlashAtEnd( std::string& dir )
{
if ( dir.size() > 1 && dir[ dir.size() - 1 ] == getOSSlash() )
{
void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) {
if ( dir.size() >= 1 && dir[dir.size() - 1] == getOSSlash() ) {
dir.erase( dir.size() - 1 );
}
}
std::string FileSystem::fileNameFromPath( std::string filepath )
{
std::string FileSystem::fileNameFromPath( std::string filepath ) {
dirRemoveSlashAtEnd( filepath );
size_t pos = filepath.find_last_of( getOSSlash() );
if ( pos != std::string::npos )
{
if ( pos != std::string::npos ) {
return filepath.substr( pos + 1 );
}
return filepath;
}
std::string FileSystem::pathRemoveFileName( std::string filepath )
{
std::string FileSystem::pathRemoveFileName( std::string filepath ) {
dirRemoveSlashAtEnd( filepath );
size_t pos = filepath.find_last_of( getOSSlash() );
if ( pos != std::string::npos )
{
if ( pos != std::string::npos ) {
return filepath.substr( 0, pos + 1 );
}
return filepath;
}
std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath )
{
std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath ) {
FileSystem::dirRemoveSlashAtEnd( dir );
FileInfo fi( dir, true );
/// Check with lstat and see if it's a link
if ( fi.isLink() )
{
if ( fi.isLink() ) {
/// get the real path of the link
std::string link( fi.linksTo() );
@@ -96,39 +84,53 @@ std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath )
return "";
}
std::string FileSystem::precomposeFileName( const std::string& name )
{
std::string FileSystem::precomposeFileName( const std::string& name ) {
#if EFSW_OS == EFSW_OS_MACOSX
CFStringRef cfStringRef = CFStringCreateWithCString(kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8);
CFMutableStringRef cfMutable = CFStringCreateMutableCopy(NULL, 0, cfStringRef);
CFStringRef cfStringRef =
CFStringCreateWithCString( kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8 );
CFMutableStringRef cfMutable = CFStringCreateMutableCopy( NULL, 0, cfStringRef );
CFStringNormalize(cfMutable,kCFStringNormalizationFormC);
CFStringNormalize( cfMutable, kCFStringNormalizationFormC );
char c_str[255 + 1];
CFStringGetCString(cfMutable, c_str, sizeof(c_str)-1, kCFStringEncodingUTF8);
const char* c_str = CFStringGetCStringPtr( cfMutable, kCFStringEncodingUTF8 );
if ( c_str != NULL ) {
std::string result( c_str );
CFRelease( cfStringRef );
CFRelease( cfMutable );
return result;
}
CFIndex length = CFStringGetLength( cfMutable );
CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 );
if ( maxSize == kCFNotFound ) {
CFRelease( cfStringRef );
CFRelease( cfMutable );
return std::string();
}
CFRelease(cfStringRef);
CFRelease(cfMutable);
return std::string(c_str);
std::string result( maxSize + 1, '\0' );
if ( CFStringGetCString( cfMutable, &result[0], result.size(), kCFStringEncodingUTF8 ) ) {
result.resize( std::strlen( result.c_str() ) );
CFRelease( cfStringRef );
CFRelease( cfMutable );
} else {
result.clear();
}
return result;
#else
return name;
#endif
}
bool FileSystem::isRemoteFS( const std::string& directory )
{
bool FileSystem::isRemoteFS( const std::string& directory ) {
return Platform::FileSystem::isRemoteFS( directory );
}
bool FileSystem::changeWorkingDirectory( const std::string& directory )
{
bool FileSystem::changeWorkingDirectory( const std::string& directory ) {
return Platform::FileSystem::changeWorkingDirectory( directory );
}
std::string FileSystem::getCurrentWorkingDirectory()
{
std::string FileSystem::getCurrentWorkingDirectory() {
return Platform::FileSystem::getCurrentWorkingDirectory();
}
}
} // namespace efsw

View File

@@ -1,44 +1,41 @@
#ifndef EFSW_FILESYSTEM_HPP
#define EFSW_FILESYSTEM_HPP
#include <efsw/base.hpp>
#include <efsw/FileInfo.hpp>
#include <efsw/base.hpp>
#include <map>
namespace efsw {
class FileSystem
{
public:
static bool isDirectory( const std::string& path );
class FileSystem {
public:
static bool isDirectory( const std::string& path );
static FileInfoMap filesInfoFromPath( std::string path );
static FileInfoMap filesInfoFromPath( std::string path );
static char getOSSlash();
static char getOSSlash();
static bool slashAtEnd( std::string& dir );
static bool slashAtEnd( std::string& dir );
static void dirAddSlashAtEnd( std::string& dir );
static void dirAddSlashAtEnd( std::string& dir );
static void dirRemoveSlashAtEnd( std::string& dir );
static void dirRemoveSlashAtEnd( std::string& dir );
static std::string fileNameFromPath( std::string filepath );
static std::string fileNameFromPath( std::string filepath );
static std::string pathRemoveFileName( std::string filepath );
static std::string pathRemoveFileName( std::string filepath );
static void realPath( std::string curdir, std::string& path );
static std::string getLinkRealPath( std::string dir, std::string& curPath );
static std::string getLinkRealPath( std::string dir, std::string& curPath );
static std::string precomposeFileName( const std::string& name );
static std::string precomposeFileName(const std::string& name);
static bool isRemoteFS( const std::string& directory );
static bool isRemoteFS( const std::string& directory );
static bool changeWorkingDirectory( const std::string& path );
static bool changeWorkingDirectory( const std::string & path );
static std::string getCurrentWorkingDirectory();
static std::string getCurrentWorkingDirectory();
};
}
} // namespace efsw
#endif

View File

@@ -1,43 +1,39 @@
#include <efsw/efsw.hpp>
#include <efsw/FileWatcherImpl.hpp>
#include <efsw/FileWatcherGeneric.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/FileWatcherGeneric.hpp>
#include <efsw/FileWatcherImpl.hpp>
#include <efsw/efsw.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
# include <efsw/FileWatcherWin32.hpp>
# define FILEWATCHER_IMPL FileWatcherWin32
# define BACKEND_NAME "Win32"
#include <efsw/FileWatcherWin32.hpp>
#define FILEWATCHER_IMPL FileWatcherWin32
#define BACKEND_NAME "Win32"
#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
# include <efsw/FileWatcherInotify.hpp>
# define FILEWATCHER_IMPL FileWatcherInotify
# define BACKEND_NAME "Inotify"
#include <efsw/FileWatcherInotify.hpp>
#define FILEWATCHER_IMPL FileWatcherInotify
#define BACKEND_NAME "Inotify"
#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE
# include <efsw/FileWatcherKqueue.hpp>
# define FILEWATCHER_IMPL FileWatcherKqueue
# define BACKEND_NAME "Kqueue"
#include <efsw/FileWatcherKqueue.hpp>
#define FILEWATCHER_IMPL FileWatcherKqueue
#define BACKEND_NAME "Kqueue"
#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
# include <efsw/FileWatcherFSEvents.hpp>
# define FILEWATCHER_IMPL FileWatcherFSEvents
# define BACKEND_NAME "FSEvents"
#include <efsw/FileWatcherFSEvents.hpp>
#define FILEWATCHER_IMPL FileWatcherFSEvents
#define BACKEND_NAME "FSEvents"
#else
# define FILEWATCHER_IMPL FileWatcherGeneric
# define BACKEND_NAME "Generic"
#define FILEWATCHER_IMPL FileWatcherGeneric
#define BACKEND_NAME "Generic"
#endif
#include <efsw/Debug.hpp>
namespace efsw {
FileWatcher::FileWatcher() :
mFollowSymlinks(false),
mOutOfScopeLinks(false)
{
FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) {
efDEBUG( "Using backend: %s\n", BACKEND_NAME );
mImpl = new FILEWATCHER_IMPL( this );
if ( !mImpl->initOK() )
{
if ( !mImpl->initOK() ) {
efSAFE_DELETE( mImpl );
efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );
@@ -47,23 +43,17 @@ FileWatcher::FileWatcher() :
}
FileWatcher::FileWatcher( bool useGenericFileWatcher ) :
mFollowSymlinks(false),
mOutOfScopeLinks(false)
{
if ( useGenericFileWatcher )
{
mFollowSymlinks( false ), mOutOfScopeLinks( false ) {
if ( useGenericFileWatcher ) {
efDEBUG( "Using backend: Generic\n" );
mImpl = new FileWatcherGeneric( this );
}
else
{
} else {
efDEBUG( "Using backend: %s\n", BACKEND_NAME );
mImpl = new FILEWATCHER_IMPL( this );
if ( !mImpl->initOK() )
{
if ( !mImpl->initOK() ) {
efSAFE_DELETE( mImpl );
efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );
@@ -73,73 +63,58 @@ FileWatcher::FileWatcher( bool useGenericFileWatcher ) :
}
}
FileWatcher::~FileWatcher()
{
FileWatcher::~FileWatcher() {
efSAFE_DELETE( mImpl );
}
WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher)
{
if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) )
{
return mImpl->addWatch(directory, watcher, false);
}
else
{
WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) {
return addWatch( directory, watcher, false, {} );
}
WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive ) {
return addWatch( directory, watcher, recursive, {} );
}
WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption>& options ) {
if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) {
return mImpl->addWatch( directory, watcher, recursive, options );
} else {
return Errors::Log::createLastError( Errors::FileRemote, directory );
}
}
WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
{
if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) )
{
return mImpl->addWatch(directory, watcher, recursive);
}
else
{
return Errors::Log::createLastError( Errors::FileRemote, directory );
}
void FileWatcher::removeWatch( const std::string& directory ) {
mImpl->removeWatch( directory );
}
void FileWatcher::removeWatch(const std::string& directory)
{
mImpl->removeWatch(directory);
void FileWatcher::removeWatch( WatchID watchid ) {
mImpl->removeWatch( watchid );
}
void FileWatcher::removeWatch(WatchID watchid)
{
mImpl->removeWatch(watchid);
}
void FileWatcher::watch()
{
void FileWatcher::watch() {
mImpl->watch();
}
std::list<std::string> FileWatcher::directories()
{
std::vector<std::string> FileWatcher::directories() {
return mImpl->directories();
}
void FileWatcher::followSymlinks( bool follow )
{
void FileWatcher::followSymlinks( bool follow ) {
mFollowSymlinks = follow;
}
const bool& FileWatcher::followSymlinks() const
{
const bool& FileWatcher::followSymlinks() const {
return mFollowSymlinks;
}
void FileWatcher::allowOutOfScopeLinks( bool allow )
{
void FileWatcher::allowOutOfScopeLinks( bool allow ) {
mOutOfScopeLinks = allow;
}
const bool& FileWatcher::allowOutOfScopeLinks() const
{
const bool& FileWatcher::allowOutOfScopeLinks() const {
return mOutOfScopeLinks;
}
}
} // namespace efsw

View File

@@ -2,27 +2,24 @@
#include <efsw/efsw.hpp>
#include <vector>
#define TOBOOL(i) ((i) == 0 ? false : true)
#define TOBOOL( i ) ( ( i ) == 0 ? false : true )
/*************************************************************************************************/
class Watcher_CAPI : public efsw::FileWatchListener
{
public:
class Watcher_CAPI : public efsw::FileWatchListener {
public:
efsw_watcher mWatcher;
efsw_pfn_fileaction_callback mFn;
void* mParam;
public:
Watcher_CAPI(efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param) :
mWatcher( watcher ),
mFn( fn ),
mParam( param )
{}
void handleFileAction(efsw::WatchID watchid, const std::string& dir, const std::string& filename,
efsw::Action action, std::string oldFilename = "")
{
mFn(mWatcher, watchid, dir.c_str(), filename.c_str(), (enum efsw_action)action,
oldFilename.c_str(), mParam );
public:
Watcher_CAPI( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) :
mWatcher( watcher ), mFn( fn ), mParam( param ) {}
void handleFileAction( efsw::WatchID watchid, const std::string& dir,
const std::string& filename, efsw::Action action,
std::string oldFilename = "" ) {
mFn( mWatcher, watchid, dir.c_str(), filename.c_str(), (enum efsw_action)action,
oldFilename.c_str(), mParam );
}
};
@@ -31,28 +28,26 @@ public:
*/
static std::vector<Watcher_CAPI*> g_callbacks;
Watcher_CAPI* find_callback(efsw_watcher watcher, efsw_pfn_fileaction_callback fn)
{
for (std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); ++i )
{
Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn ) {
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 )
return *i;
}
return NULL;
}
Watcher_CAPI* remove_callback(efsw_watcher watcher)
{
Watcher_CAPI* remove_callback( efsw_watcher watcher ) {
std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin();
while (i != g_callbacks.end()) {
while ( i != g_callbacks.end() ) {
Watcher_CAPI* callback = *i;
if (callback->mWatcher == watcher)
i = g_callbacks.erase(i);
if ( callback->mWatcher == watcher )
i = g_callbacks.erase( i );
else
++i;
}
@@ -60,72 +55,77 @@ Watcher_CAPI* remove_callback(efsw_watcher watcher)
return NULL;
}
/*************************************************************************************************/
efsw_watcher efsw_create(int generic_mode)
{
return (efsw_watcher)new efsw::FileWatcher(TOBOOL(generic_mode));
efsw_watcher efsw_create( int generic_mode ) {
return ( efsw_watcher ) new efsw::FileWatcher( TOBOOL( generic_mode ) );
}
void efsw_release(efsw_watcher watcher)
{
remove_callback(watcher);
void efsw_release( efsw_watcher watcher ) {
remove_callback( watcher );
delete (efsw::FileWatcher*)watcher;
}
const char* efsw_getlasterror()
{
const char* efsw_getlasterror() {
static std::string log_str;
log_str = efsw::Errors::Log::getLastErrorLog();
return log_str.c_str();
}
efsw_watchid efsw_addwatch(efsw_watcher watcher, const char* directory,
efsw_pfn_fileaction_callback callback_fn, int recursive, void * param)
{
Watcher_CAPI* callback = find_callback(watcher, callback_fn);
EFSW_API void efsw_clearlasterror() {
efsw::Errors::Log::clearLastError();
}
if (callback == NULL) {
callback = new Watcher_CAPI(watcher, callback_fn, param);
g_callbacks.push_back(callback);
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 );
}
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 );
if ( callback == NULL ) {
callback = new Watcher_CAPI( watcher, callback_fn, param );
g_callbacks.push_back( callback );
}
return ((efsw::FileWatcher*)watcher)->addWatch(std::string(directory), callback,
TOBOOL(recursive));
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 } );
}
return ( (efsw::FileWatcher*)watcher )
->addWatch( std::string( directory ), callback, TOBOOL( recursive ), watcher_options );
}
void efsw_removewatch(efsw_watcher watcher, const char* directory)
{
((efsw::FileWatcher*)watcher)->removeWatch(std::string(directory));
void efsw_removewatch( efsw_watcher watcher, const char* directory ) {
( (efsw::FileWatcher*)watcher )->removeWatch( std::string( directory ) );
}
void efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid)
{
((efsw::FileWatcher*)watcher)->removeWatch(watchid);
void efsw_removewatch_byid( efsw_watcher watcher, efsw_watchid watchid ) {
( (efsw::FileWatcher*)watcher )->removeWatch( watchid );
}
void efsw_watch(efsw_watcher watcher)
{
((efsw::FileWatcher*)watcher)->watch();
void efsw_watch( efsw_watcher watcher ) {
( (efsw::FileWatcher*)watcher )->watch();
}
void efsw_follow_symlinks(efsw_watcher watcher, int enable)
{
((efsw::FileWatcher*)watcher)->followSymlinks(TOBOOL(enable));
void efsw_follow_symlinks( efsw_watcher watcher, int enable ) {
( (efsw::FileWatcher*)watcher )->followSymlinks( TOBOOL( enable ) );
}
int efsw_follow_symlinks_isenabled(efsw_watcher watcher)
{
return (int)((efsw::FileWatcher*)watcher)->followSymlinks();
int efsw_follow_symlinks_isenabled( efsw_watcher watcher ) {
return (int)( (efsw::FileWatcher*)watcher )->followSymlinks();
}
void efsw_allow_outofscopelinks(efsw_watcher watcher, int allow)
{
((efsw::FileWatcher*)watcher)->allowOutOfScopeLinks(TOBOOL(allow));
void efsw_allow_outofscopelinks( efsw_watcher watcher, int allow ) {
( (efsw::FileWatcher*)watcher )->allowOutOfScopeLinks( TOBOOL( allow ) );
}
int efsw_outofscopelinks_isallowed(efsw_watcher watcher)
{
return (int)((efsw::FileWatcher*)watcher)->allowOutOfScopeLinks();
int efsw_outofscopelinks_isallowed( efsw_watcher watcher ) {
return (int)( (efsw::FileWatcher*)watcher )->allowOutOfScopeLinks();
}

View File

@@ -1,67 +1,58 @@
#include <efsw/FileWatcherFSEvents.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/System.hpp>
#include <efsw/Debug.hpp>
#include <efsw/String.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/FileWatcherFSEvents.hpp>
#include <efsw/Lock.hpp>
#include <efsw/String.hpp>
#include <efsw/System.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
#include <sys/utsname.h>
namespace efsw
{
namespace efsw {
int getOSXReleaseNumber()
{
int getOSXReleaseNumber() {
static int osxR = -1;
if ( -1 == osxR )
{
if ( -1 == osxR ) {
struct utsname os;
if ( -1 != uname( &os ) ) {
std::string release( os.release );
size_t pos = release.find_first_of( '.' );
if ( pos != std::string::npos )
{
if ( pos != std::string::npos ) {
release = release.substr( 0, pos );
}
int rel = 0;
if ( String::fromString<int>( rel, release ) )
{
if ( String::fromString<int>( rel, release ) ) {
osxR = rel;
}
}
}
return osxR;
}
bool FileWatcherFSEvents::isGranular()
{
bool FileWatcherFSEvents::isGranular() {
return getOSXReleaseNumber() >= 11;
}
void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef,
void *userData,
size_t numEvents,
void *eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[] )
{
WatcherFSEvents * watcher = static_cast<WatcherFSEvents*>( userData );
void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef, void* userData,
size_t numEvents, void* eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[] ) {
WatcherFSEvents* watcher = static_cast<WatcherFSEvents*>( userData );
std::vector<FSEvent> events;
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] ) );
for ( size_t i = 0; i < numEvents; i++ ) {
events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), (long)eventFlags[i],
(Uint64)eventIds[i] ) );
}
watcher->handleActions( events );
@@ -71,60 +62,42 @@ void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef,
efDEBUG( "\n" );
}
FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher * parent ) :
FileWatcherImpl( parent ),
mRunLoopRef( NULL ),
mLastWatchID(0),
mThread( NULL )
{
FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) :
FileWatcherImpl( parent ), mLastWatchID( 0 ) {
mInitOK = true;
watch();
}
FileWatcherFSEvents::~FileWatcherFSEvents()
{
FileWatcherFSEvents::~FileWatcherFSEvents() {
mInitOK = false;
efSAFE_DELETE( mThread );
mWatchCond.notify_all();
WatchMap::iterator iter = mWatches.begin();
for( ; iter != mWatches.end(); ++iter )
{
WatcherFSEvents * watch = iter->second;
for ( ; iter != mWatches.end(); ++iter ) {
WatcherFSEvents* watch = iter->second;
efSAFE_DELETE( watch );
}
mWatches.clear();
}
WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive )
{
/// Wait to the RunLoopRef to be ready
while ( NULL == mRunLoopRef )
{
System::sleep( 1 );
}
WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption> &options ) {
std::string dir( directory );
FileInfo fi( dir );
if ( !fi.isDirectory() )
{
if ( !fi.isDirectory() ) {
return Errors::Log::createLastError( Errors::FileNotFound, dir );
}
else if ( !fi.isReadable() )
{
} else if ( !fi.isReadable() ) {
return Errors::Log::createLastError( Errors::FileNotReadable, dir );
}
FileSystem::dirAddSlashAtEnd( dir );
if ( pathInWatches( dir ) )
{
if ( pathInWatches( dir ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, directory );
}
@@ -132,67 +105,60 @@ WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchLi
std::string curPath;
std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
if ( "" != link )
{
if ( "" != link ) {
/// If it's a symlink check if the realpath exists as a watcher, or
/// if the path is outside the current dir
if ( pathInWatches( link ) )
{
if ( pathInWatches( link ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, directory );
}
else if ( !linkAllowed( curPath, link ) )
{
} else if ( !linkAllowed( curPath, link ) ) {
return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
}
else
{
} else {
dir = link;
}
}
mLastWatchID++;
WatcherFSEvents * pWatch = new WatcherFSEvents();
pWatch->Listener = watcher;
pWatch->ID = mLastWatchID;
pWatch->Directory = dir;
pWatch->Recursive = recursive;
pWatch->FWatcher = this;
WatcherFSEvents* pWatch = new WatcherFSEvents();
pWatch->Listener = watcher;
pWatch->ID = mLastWatchID;
pWatch->Directory = dir;
pWatch->Recursive = recursive;
pWatch->FWatcher = this;
pWatch->init();
Lock lock( mWatchesLock );
mWatches.insert(std::make_pair(mLastWatchID, pWatch));
{
Lock lock( mWatchesLock );
mWatches.insert( std::make_pair( mLastWatchID, pWatch ) );
}
mWatchCond.notify_all();
return pWatch->ID;
}
void FileWatcherFSEvents::removeWatch(const std::string& directory)
{
void FileWatcherFSEvents::removeWatch( const std::string& directory ) {
Lock lock( mWatchesLock );
WatchMap::iterator iter = mWatches.begin();
for(; iter != mWatches.end(); ++iter)
{
if( directory == iter->second->Directory )
{
for ( ; iter != mWatches.end(); ++iter ) {
if ( directory == iter->second->Directory ) {
removeWatch( iter->second->ID );
return;
}
}
}
void FileWatcherFSEvents::removeWatch(WatchID watchid)
{
void FileWatcherFSEvents::removeWatch( WatchID watchid ) {
Lock lock( mWatchesLock );
WatchMap::iterator iter = mWatches.find( watchid );
if( iter == mWatches.end() )
if ( iter == mWatches.end() )
return;
WatcherFSEvents * watch = iter->second;
WatcherFSEvents* watch = iter->second;
mWatches.erase( iter );
@@ -201,63 +167,30 @@ void FileWatcherFSEvents::removeWatch(WatchID watchid)
efSAFE_DELETE( watch );
}
void FileWatcherFSEvents::watch()
{
if ( NULL == mThread )
{
mThread = new Thread( &FileWatcherFSEvents::run, this );
mThread->launch();
}
}
void FileWatcherFSEvents::watch() {}
void FileWatcherFSEvents::run()
{
mRunLoopRef = CFRunLoopGetCurrent();
while ( mInitOK )
{
if ( !mNeedInit.empty() )
{
for ( std::list<WatcherFSEvents*>::iterator it = mNeedInit.begin(); it != mNeedInit.end(); ++it )
{
(*it)->initAsync();
}
mNeedInit.clear();
}
CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut );
}
CFRunLoopStop( mRunLoopRef );
mRunLoopRef = NULL;
}
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
}
std::list<std::string> FileWatcherFSEvents::directories()
{
std::list<std::string> dirs;
std::vector<std::string> FileWatcherFSEvents::directories() {
std::vector<std::string> dirs;
Lock lock( mWatchesLock );
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
dirs.reserve( mWatches.size() );
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
dirs.push_back( std::string( it->second->Directory ) );
}
return dirs;
}
bool FileWatcherFSEvents::pathInWatches( const std::string& path )
{
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
if ( it->second->Directory == path )
{
bool FileWatcherFSEvents::pathInWatches( const std::string& path ) {
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
if ( it->second->Directory == path ) {
return true;
}
}
@@ -265,6 +198,6 @@ bool FileWatcherFSEvents::pathInWatches( const std::string& path )
return false;
}
}
} // namespace efsw
#endif

View File

@@ -7,98 +7,94 @@
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <dispatch/dispatch.h>
#include <efsw/WatcherFSEvents.hpp>
#include <map>
#include <list>
#include <vector>
#include <condition_variable>
#include <mutex>
namespace efsw
{
namespace efsw {
/* OSX < 10.7 has no file events */
/* So i declare the events constants */
enum FSEventEvents
{
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
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
{
class FileWatcherFSEvents : public FileWatcherImpl {
friend class WatcherFSEvents;
public:
/// @return If FSEvents supports file-level notifications ( true if OS X >= 10.7 )
static bool isGranular();
/// type for a map from WatchID to WatcherWin32 pointer
typedef std::map<WatchID, WatcherFSEvents*> WatchMap;
FileWatcherFSEvents( FileWatcher * parent );
public:
/// @return If FSEvents supports file-level notifications ( true if OS X >= 10.7 )
static bool isGranular();
virtual ~FileWatcherFSEvents();
/// type for a map from WatchID to WatcherWin32 pointer
typedef std::map<WatchID, WatcherFSEvents*> WatchMap;
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
FileWatcherFSEvents( FileWatcher* parent );
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch(const std::string& directory);
virtual ~FileWatcherFSEvents();
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch(WatchID watchid);
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
const std::vector<WatcherOption> &options ) override;
/// Updates the watcher. Must be called often.
void watch();
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch( const std::string& directory ) override;
/// Handles the action
void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch( WatchID watchid ) override;
/// @return Returns a list of the directories that are being watched
std::list<std::string> directories();
protected:
static void FSEventCallback( ConstFSEventStreamRef streamRef,
void *userData,
size_t numEvents,
void *eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[]
);
CFRunLoopRef mRunLoopRef;
/// Vector of WatcherWin32 pointers
WatchMap mWatches;
/// The last watchid
WatchID mLastWatchID;
/// Updates the watcher. Must be called often.
void watch() override;
Thread * mThread;
/// Handles the action
void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
std::string oldFilename = "" ) override;
Mutex mWatchesLock;
/// @return Returns a list of the directories that are being watched
std::vector<std::string> directories() override;
bool pathInWatches( const std::string& path );
protected:
static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents,
void* eventPaths, const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[] );
/// Vector of WatcherWin32 pointers
WatchMap mWatches;
/// The last watchid
WatchID mLastWatchID;
Mutex mWatchesLock;
bool pathInWatches( const std::string& path ) override;
std::mutex mWatchesMutex;
std::condition_variable mWatchCond;
std::list<WatcherFSEvents*> mNeedInit;
private:
void run();
};
}
} // namespace efsw
#endif

View File

@@ -1,22 +1,17 @@
#include <efsw/FileWatcherGeneric.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/System.hpp>
#include <efsw/FileWatcherGeneric.hpp>
#include <efsw/Lock.hpp>
#include <efsw/System.hpp>
namespace efsw
{
namespace efsw {
FileWatcherGeneric::FileWatcherGeneric( FileWatcher * parent ) :
FileWatcherImpl( parent ),
mThread( NULL ),
mLastWatchID( 0 )
{
FileWatcherGeneric::FileWatcherGeneric( FileWatcher* parent ) :
FileWatcherImpl( parent ), mThread( NULL ), mLastWatchID( 0 ) {
mInitOK = true;
mIsGeneric = true;
}
FileWatcherGeneric::~FileWatcherGeneric()
{
FileWatcherGeneric::~FileWatcherGeneric() {
mInitOK = false;
efSAFE_DELETE( mThread );
@@ -24,161 +19,135 @@ FileWatcherGeneric::~FileWatcherGeneric()
/// Delete the watches
WatchList::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); ++it )
{
efSAFE_DELETE( (*it) );
for ( ; it != mWatches.end(); ++it ) {
efSAFE_DELETE( ( *it ) );
}
}
WatchID FileWatcherGeneric::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
{
WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption>& options ) {
std::string dir( directory );
FileSystem::dirAddSlashAtEnd( dir );
FileInfo fi( dir );
if ( !fi.isDirectory() )
{
if ( !fi.isDirectory() ) {
return Errors::Log::createLastError( Errors::FileNotFound, dir );
}
else if ( !fi.isReadable() )
{
} else if ( !fi.isReadable() ) {
return Errors::Log::createLastError( Errors::FileNotReadable, dir );
}
else if ( pathInWatches( dir ) )
{
} else if ( pathInWatches( dir ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, dir );
}
std::string curPath;
std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
if ( "" != link )
{
if ( pathInWatches( link ) )
{
if ( "" != link ) {
if ( pathInWatches( link ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, dir );
}
else if ( !linkAllowed( curPath, link ) )
{
} else if ( !linkAllowed( curPath, link ) ) {
return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
}
else
{
} else {
dir = link;
}
}
mLastWatchID++;
WatcherGeneric * pWatch = new WatcherGeneric( mLastWatchID, dir, watcher, this, recursive );
WatcherGeneric* pWatch = new WatcherGeneric( mLastWatchID, dir, watcher, this, recursive );
Lock lock( mWatchesLock );
mWatches.push_back(pWatch);
mWatches.push_back( pWatch );
return pWatch->ID;
}
void FileWatcherGeneric::removeWatch( const std::string& directory )
{
void FileWatcherGeneric::removeWatch( const std::string& directory ) {
WatchList::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); ++it )
{
if ( (*it)->Directory == directory )
{
WatcherGeneric * watch = (*it);
for ( ; it != mWatches.end(); ++it ) {
if ( ( *it )->Directory == directory ) {
WatcherGeneric* watch = ( *it );
Lock lock( mWatchesLock );
mWatches.erase( it );
efSAFE_DELETE( watch ) ;
efSAFE_DELETE( watch );
return;
}
}
}
void FileWatcherGeneric::removeWatch(WatchID watchid)
{
void FileWatcherGeneric::removeWatch( WatchID watchid ) {
WatchList::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); ++it )
{
if ( (*it)->ID == watchid )
{
WatcherGeneric * watch = (*it);
for ( ; it != mWatches.end(); ++it ) {
if ( ( *it )->ID == watchid ) {
WatcherGeneric* watch = ( *it );
Lock lock( mWatchesLock );
mWatches.erase( it );
efSAFE_DELETE( watch ) ;
efSAFE_DELETE( watch );
return;
}
}
}
void FileWatcherGeneric::watch()
{
if ( NULL == mThread )
{
void FileWatcherGeneric::watch() {
if ( NULL == mThread ) {
mThread = new Thread( &FileWatcherGeneric::run, this );
mThread->launch();
}
}
void FileWatcherGeneric::run()
{
do
{
void FileWatcherGeneric::run() {
do {
{
Lock lock( mWatchesLock);
Lock lock( mWatchesLock );
WatchList::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); ++it )
{
for ( ; it != mWatches.end(); ++it ) {
( *it )->watch();
}
}
if ( mInitOK ) System::sleep( 1000 );
if ( mInitOK )
System::sleep( 1000 );
} while ( mInitOK );
}
void FileWatcherGeneric::handleAction(Watcher *, const std::string&, unsigned long, std::string)
{
void FileWatcherGeneric::handleAction( Watcher*, const std::string&, unsigned long, std::string ) {
/// Not used
}
std::list<std::string> FileWatcherGeneric::directories()
{
std::list<std::string> dirs;
std::vector<std::string> FileWatcherGeneric::directories() {
std::vector<std::string> dirs;
Lock lock( mWatchesLock );
dirs.reserve( mWatches.size() );
WatchList::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); ++it )
{
dirs.push_back( (*it)->Directory );
for ( ; it != mWatches.end(); ++it ) {
dirs.push_back( ( *it )->Directory );
}
return dirs;
}
bool FileWatcherGeneric::pathInWatches( const std::string& path )
{
bool FileWatcherGeneric::pathInWatches( const std::string& path ) {
WatchList::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); ++it )
{
if ( (*it)->Directory == path || (*it)->pathInWatches( path ) )
{
for ( ; it != mWatches.end(); ++it ) {
if ( ( *it )->Directory == path || ( *it )->pathInWatches( path ) ) {
return true;
}
}
@@ -186,4 +155,4 @@ bool FileWatcherGeneric::pathInWatches( const std::string& path )
return false;
}
}
} // namespace efsw

View File

@@ -1,59 +1,61 @@
#ifndef EFSW_FILEWATCHERGENERIC_HPP
#define EFSW_FILEWATCHERGENERIC_HPP
#include <efsw/DirWatcherGeneric.hpp>
#include <efsw/FileWatcherImpl.hpp>
#include <efsw/WatcherGeneric.hpp>
#include <efsw/DirWatcherGeneric.hpp>
#include <list>
#include <vector>
namespace efsw
{
namespace efsw {
/// Implementation for Generic File Watcher.
/// @class FileWatcherGeneric
class FileWatcherGeneric : public FileWatcherImpl
{
public:
typedef std::list<WatcherGeneric*> WatchList;
class FileWatcherGeneric : public FileWatcherImpl {
public:
typedef std::vector<WatcherGeneric*> WatchList;
FileWatcherGeneric( FileWatcher * parent );
FileWatcherGeneric( FileWatcher* parent );
virtual ~FileWatcherGeneric();
virtual ~FileWatcherGeneric();
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
const std::vector<WatcherOption> &options ) override;
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch(const std::string& directory);
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch( const std::string& directory ) override;
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch(WatchID watchid);
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch( WatchID watchid ) override;
/// Updates the watcher. Must be called often.
void watch();
/// Updates the watcher. Must be called often.
void watch() override;
/// Handles the action
void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
/// Handles the action
void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
std::string oldFilename = "" ) override;
/// @return Returns a list of the directories that are being watched
std::list<std::string> directories();
protected:
Thread * mThread;
/// @return Returns a list of the directories that are being watched
std::vector<std::string> directories() override;
/// The last watchid
WatchID mLastWatchID;
protected:
Thread* mThread;
/// Map of WatchID to WatchStruct pointers
WatchList mWatches;
/// The last watchid
WatchID mLastWatchID;
Mutex mWatchesLock;
/// Map of WatchID to WatchStruct pointers
WatchList mWatches;
bool pathInWatches( const std::string& path );
private:
void run();
Mutex mWatchesLock;
bool pathInWatches( const std::string& path ) override;
private:
void run();
};
}
} // namespace efsw
#endif

View File

@@ -4,26 +4,31 @@
namespace efsw {
FileWatcherImpl::FileWatcherImpl( FileWatcher * parent ) :
mFileWatcher( parent ),
mInitOK( false ),
mIsGeneric( false )
{
FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) :
mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) {
System::maxFD();
}
FileWatcherImpl::~FileWatcherImpl()
{
FileWatcherImpl::~FileWatcherImpl() {}
bool FileWatcherImpl::initOK() {
return static_cast<bool>( mInitOK );
}
bool FileWatcherImpl::initOK()
{
return mInitOK;
bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) {
return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) ||
-1 != String::strStartsWith( curPath, link );
}
bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link )
{
return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || -1 != String::strStartsWith( curPath, link );
int FileWatcherImpl::getOptionValue( const std::vector<WatcherOption>& options, Option option,
int defaultValue ) {
for ( size_t i = 0; i < options.size(); i++ ) {
if ( options[i].mOption == option ) {
return options[i].mValue;
}
}
return defaultValue;
}
}
} // namespace efsw

View File

@@ -1,54 +1,64 @@
#ifndef EFSW_FILEWATCHERIMPL_HPP
#define EFSW_FILEWATCHERIMPL_HPP
#include <efsw/Atomic.hpp>
#include <efsw/Mutex.hpp>
#include <efsw/Thread.hpp>
#include <efsw/Watcher.hpp>
#include <efsw/base.hpp>
#include <efsw/efsw.hpp>
#include <efsw/Watcher.hpp>
#include <efsw/Thread.hpp>
#include <efsw/Mutex.hpp>
namespace efsw {
class FileWatcherImpl
{
public:
FileWatcherImpl( FileWatcher * parent );
class FileWatcherImpl {
public:
FileWatcherImpl( FileWatcher* parent );
virtual ~FileWatcherImpl();
virtual ~FileWatcherImpl();
/// Add a directory watch
/// On error returns WatchID with Error type.
virtual WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) = 0;
/// Add a directory watch
/// On error returns WatchID with Error type.
virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption>& options = {} ) = 0;
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
virtual void removeWatch(const std::string& directory) = 0;
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
virtual void removeWatch( const std::string& directory ) = 0;
/// Remove a directory watch. This is a map lookup O(logn).
virtual void removeWatch(WatchID watchid) = 0;
/// Remove a directory watch. This is a map lookup O(logn).
virtual void removeWatch( WatchID watchid ) = 0;
/// Updates the watcher. Must be called often.
virtual void watch() = 0;
/// Updates the watcher. Must be called often.
virtual void watch() = 0;
/// Handles the action
virtual void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "") = 0;
/// Handles the action
virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
std::string oldFilename = "" ) = 0;
/// @return Returns a list of the directories that are being watched
virtual std::list<std::string> directories() = 0;
/// @return Returns a list of the directories that are being watched
virtual std::vector<std::string> directories() = 0;
/// @return true if the backend init successfully
virtual bool initOK();
/// @return true if the backend init successfully
virtual bool initOK();
/// @return If the link is allowed according to the current path and the state of out scope links
virtual bool linkAllowed( const std::string& curPath, const std::string& link );
/// @return If the link is allowed according to the current path and the state of out scope
/// links
virtual bool linkAllowed( const std::string& curPath, const std::string& link );
/// Search if a directory already exists in the watches
virtual bool pathInWatches( const std::string& path ) = 0;
/// Search if a directory already exists in the watches
virtual bool pathInWatches( const std::string& path ) = 0;
FileWatcher * mFileWatcher;
bool mInitOK;
bool mIsGeneric;
protected:
friend class FileWatcher;
friend class DirWatcherGeneric;
FileWatcher* mFileWatcher;
Atomic<bool> mInitOK;
bool mIsGeneric;
int getOptionValue( const std::vector<WatcherOption>& options, Option option,
int defaultValue );
};
}
} // namespace efsw
#endif

View File

@@ -1,13 +1,14 @@
#include <algorithm>
#include <efsw/FileWatcherInotify.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef EFSW_INOTIFY_NOSYS
#include <efsw/inotify-nosys.h>
@@ -15,84 +16,81 @@
#include <sys/inotify.h>
#endif
#include <efsw/FileSystem.hpp>
#include <efsw/System.hpp>
#include <efsw/Debug.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/Lock.hpp>
#include <efsw/String.hpp>
#include <efsw/System.hpp>
#define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024)
#define BUFF_SIZE ( ( sizeof( struct inotify_event ) + FILENAME_MAX ) * 1024 )
namespace efsw
{
namespace efsw {
FileWatcherInotify::FileWatcherInotify( FileWatcher * parent ) :
FileWatcherImpl( parent ),
mFD(-1),
mThread(NULL)
{
FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) :
FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ), mIsTakingAction( false ) {
mFD = inotify_init();
if (mFD < 0)
{
efDEBUG( "Error: %s\n", strerror(errno) );
}
else
{
if ( mFD < 0 ) {
efDEBUG( "Error: %s\n", strerror( errno ) );
} else {
mInitOK = true;
}
}
FileWatcherInotify::~FileWatcherInotify()
{
FileWatcherInotify::~FileWatcherInotify() {
mInitOK = false;
// There is deadlock when release FileWatcherInotify instance since its handAction
// function is still running and hangs in requiring lock without init lock captured.
while ( mIsTakingAction ) {
// It'd use condition-wait instead of sleep. Actually efsw has no such
// implementation so we just skip and sleep while for that to avoid deadlock.
usleep( 1000 );
};
Lock initLock( mInitLock );
efSAFE_DELETE( mThread );
Lock l( mWatchesLock );
Lock l2( mRealWatchesLock );
WatchMap::iterator iter = mWatches.begin();
WatchMap::iterator end = mWatches.end();
for(; iter != end; ++iter)
{
for ( ; iter != end; ++iter ) {
efSAFE_DELETE( iter->second );
}
mWatches.clear();
if ( mFD != -1 )
{
close(mFD);
if ( mFD != -1 ) {
close( mFD );
mFD = -1;
}
}
WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive )
{
WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption>& ) {
if ( !mInitOK )
return Errors::Log::createLastError( Errors::Unspecified, directory );
Lock initLock( mInitLock );
return addWatch( directory, watcher, recursive, NULL );
}
WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent )
{
WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, WatcherInotify* parent ) {
std::string dir( directory );
FileSystem::dirAddSlashAtEnd( dir );
FileInfo fi( dir );
if ( !fi.isDirectory() )
{
if ( !fi.isDirectory() ) {
return Errors::Log::createLastError( Errors::FileNotFound, dir );
}
else if ( !fi.isReadable() )
{
} else if ( !fi.isReadable() ) {
return Errors::Log::createLastError( Errors::FileNotReadable, dir );
}
else if ( pathInWatches( dir ) )
{
} else if ( pathInWatches( dir ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, directory );
}
else if ( NULL != parent && FileSystem::isRemoteFS( dir ) )
{
} else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) {
return Errors::Log::createLastError( Errors::FileRemote, dir );
}
@@ -100,74 +98,68 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
std::string curPath;
std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
if ( "" != link )
{
if ( "" != link ) {
/// Avoid adding symlinks directories if it's now enabled
if ( NULL != parent && !mFileWatcher->followSymlinks() )
{
if ( NULL != parent && !mFileWatcher->followSymlinks() ) {
return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
}
/// If it's a symlink check if the realpath exists as a watcher, or
/// if the path is outside the current dir
if ( pathInWatches( link ) )
{
if ( pathInWatches( link ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, directory );
}
else if ( !linkAllowed( curPath, link ) )
{
} else if ( !linkAllowed( curPath, link ) ) {
return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
}
else
{
} else {
dir = link;
}
}
int wd = inotify_add_watch (mFD, dir.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE | IN_MODIFY);
int wd = inotify_add_watch( mFD, dir.c_str(),
IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM |
IN_DELETE | IN_MODIFY );
if ( wd < 0 )
{
if( errno == ENOENT )
{
if ( wd < 0 ) {
if ( errno == ENOENT ) {
return Errors::Log::createLastError( Errors::FileNotFound, dir );
}
else
{
return Errors::Log::createLastError( Errors::Unspecified, std::string(strerror(errno)) );
} else {
return Errors::Log::createLastError( Errors::Unspecified,
std::string( strerror( errno ) ) );
}
}
efDEBUG( "Added watch %s with id: %d\n", dir.c_str(), wd );
WatcherInotify * pWatch = new WatcherInotify();
pWatch->Listener = watcher;
pWatch->ID = wd;
pWatch->Directory = dir;
pWatch->Recursive = recursive;
pWatch->Parent = parent;
WatcherInotify* pWatch = new WatcherInotify();
pWatch->Listener = watcher;
pWatch->ID = parent ? parent->ID : wd;
pWatch->InotifyID = wd;
pWatch->Directory = dir;
pWatch->Recursive = recursive;
pWatch->Parent = parent;
{
Lock lock( mWatchesLock );
mWatches.insert(std::make_pair(wd, pWatch));
mWatches.insert( std::make_pair( wd, pWatch ) );
mWatchesRef[pWatch->Directory] = wd;
}
if ( NULL == pWatch->Parent )
{
mRealWatches[ pWatch->ID ] = pWatch;
if ( NULL == pWatch->Parent ) {
Lock l( mRealWatchesLock );
mRealWatches[pWatch->InotifyID] = pWatch;
}
if ( pWatch->Recursive )
{
if ( pWatch->Recursive ) {
std::map<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory );
std::map<std::string, FileInfo>::iterator it = files.begin();
for ( ; it != files.end(); ++it )
{
for ( ; it != files.end(); ++it ) {
if ( !mInitOK )
break;
const FileInfo& cfi = it->second;
if ( cfi.isDirectory() && cfi.isReadable() )
{
if ( cfi.isDirectory() && cfi.isReadable() ) {
addWatch( cfi.Filepath, watcher, recursive, pWatch );
}
}
@@ -176,401 +168,395 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
return wd;
}
void FileWatcherInotify::removeWatchLocked(WatchID watchid)
{
void FileWatcherInotify::removeWatchLocked( WatchID watchid ) {
WatchMap::iterator iter = mWatches.find( watchid );
if ( iter == mWatches.end() )
return;
WatcherInotify * watch = iter->second;
WatcherInotify* watch = iter->second;
if ( watch->Recursive )
{
WatchMap::iterator it = mWatches.begin();
std::list<WatchID> eraseWatches;
for(; it != mWatches.end(); ++it)
{
if ( it->second != watch &&
it->second->inParentTree( watch )
)
{
eraseWatches.push_back( it->second->ID );
}
for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator itm =
mMovedOutsideWatches.begin();
mMovedOutsideWatches.end() != itm; ++itm ) {
if ( itm->first == watch ) {
mMovedOutsideWatches.erase( itm );
break;
}
}
for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); ++eit )
{
if ( watch->Recursive && NULL == watch->Parent ) {
WatchMap::iterator it = mWatches.begin();
std::vector<WatchID> eraseWatches;
for ( ; it != mWatches.end(); ++it )
if ( it->second != watch && it->second->inParentTree( watch ) )
eraseWatches.push_back( it->second->InotifyID );
for ( std::vector<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end();
++eit ) {
removeWatch( *eit );
}
}
mWatchesRef.erase( watch->Directory );
mWatches.erase( iter );
if ( NULL == watch->Parent )
{
WatchMap::iterator eraseit = mRealWatches.find( watch->ID );
if ( NULL == watch->Parent ) {
WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID );
if ( eraseit != mRealWatches.end() )
{
if ( eraseit != mRealWatches.end() ) {
mRealWatches.erase( eraseit );
}
}
int err = inotify_rm_watch(mFD, watchid);
int err = inotify_rm_watch( mFD, watchid );
if ( err < 0 )
{
efDEBUG( "Error removing watch %d: %s\n", watchid, strerror(errno) );
}
else
{
if ( err < 0 ) {
efDEBUG( "Error removing watch %d: %s\n", watchid, strerror( errno ) );
} else {
efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watchid );
}
efSAFE_DELETE( watch );
}
void FileWatcherInotify::removeWatch(const std::string& directory)
{
void FileWatcherInotify::removeWatch( const std::string& directory ) {
if ( !mInitOK )
return;
Lock initLock( mInitLock );
Lock lock( mWatchesLock );
Lock l( mRealWatchesLock );
WatchMap::iterator iter = mWatches.begin();
std::unordered_map<std::string, WatchID>::iterator ref = mWatchesRef.find( directory );
if ( ref == mWatchesRef.end() )
return;
for(; iter != mWatches.end(); ++iter)
{
if( directory == iter->second->Directory )
{
WatcherInotify * watch = iter->second;
if ( watch->Recursive )
{
WatchMap::iterator it = mWatches.begin();
std::list<WatchID> eraseWatches;
for(; it != mWatches.end(); ++it)
{
if ( it->second->inParentTree( watch ) )
{
eraseWatches.push_back( it->second->ID );
}
}
for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); ++eit )
{
removeWatchLocked( *eit );
}
}
mWatches.erase( iter );
if ( NULL == watch->Parent )
{
WatchMap::iterator eraseit = mRealWatches.find( watch->ID );
if ( eraseit != mRealWatches.end() )
{
mRealWatches.erase( eraseit );
}
}
int err = inotify_rm_watch(mFD, watch->ID);
if ( err < 0 )
{
efDEBUG( "Error removing watch %d: %s\n", watch->ID, strerror(errno) );
}
else
{
efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watch->ID );
}
efSAFE_DELETE( watch );
break;
}
}
removeWatchLocked( ref->second );
}
void FileWatcherInotify::removeWatch( WatchID watchid )
{
Lock lock( mWatchesLock );
WatchMap::iterator iter = mWatches.find( watchid );
if( iter == mWatches.end() )
{
void FileWatcherInotify::removeWatch( WatchID watchid ) {
if ( !mInitOK )
return;
}
Lock initLock( mInitLock );
Lock lock( mWatchesLock );
removeWatchLocked( watchid );
}
void FileWatcherInotify::watch()
{
if ( NULL == mThread )
{
void FileWatcherInotify::watch() {
if ( NULL == mThread ) {
mThread = new Thread( &FileWatcherInotify::run, this );
mThread->launch();
}
}
Watcher * FileWatcherInotify::watcherContainsDirectory( std::string dir )
{
Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) {
FileSystem::dirRemoveSlashAtEnd( dir );
std::string watcherPath = FileSystem::pathRemoveFileName( dir );
FileSystem::dirAddSlashAtEnd( watcherPath );
Lock lock( mWatchesLock );
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
Watcher * watcher = it->second;
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
Watcher* watcher = it->second;
if ( watcher->Directory == watcherPath )
{
return watcher;
}
}
return NULL;
}
void FileWatcherInotify::run()
{
static char buff[BUFF_SIZE] = {0};
void FileWatcherInotify::run() {
char* buff = new char[BUFF_SIZE];
memset( buff, 0, BUFF_SIZE );
WatchMap::iterator wit;
std::list<WatcherInotify*> movedOutsideWatches;
do
{
WatcherInotify* currentMoveFrom = NULL;
u_int32_t currentMoveCookie = -1;
bool lastWasMovedFrom = false;
std::string prevOldFileName;
do {
fd_set rfds;
FD_ZERO (&rfds);
FD_SET (mFD, &rfds);
FD_ZERO( &rfds );
FD_SET( mFD, &rfds );
timeval timeout;
timeout.tv_sec=0;
timeout.tv_usec=100000;
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
if( select (FD_SETSIZE, &rfds, NULL, NULL, &timeout) > 0 )
{
if ( select( FD_SETSIZE, &rfds, NULL, NULL, &timeout ) > 0 ) {
ssize_t len;
len = read (mFD, buff, BUFF_SIZE);
len = read( mFD, buff, BUFF_SIZE );
if (len != -1)
{
if ( len != -1 ) {
ssize_t i = 0;
while (i < len)
{
struct inotify_event *pevent = (struct inotify_event *)&buff[i];
while ( i < len ) {
struct inotify_event* pevent = (struct inotify_event*)&buff[i];
{
Lock lock( mWatchesLock );
wit = mWatches.find( pevent->wd );
if ( wit != mWatches.end() )
{
handleAction(wit->second, pevent->name, pevent->mask);
Lock lock( mWatchesLock );
/// Keep track of the IN_MOVED_FROM events to know if the IN_MOVED_TO event is also fired
if ( !wit->second->OldFileName.empty() )
{
movedOutsideWatches.push_back( wit->second );
}
wit = mWatches.find( pevent->wd );
}
}
i += sizeof(struct inotify_event) + pevent->len;
}
if ( wit != mWatches.end() ) {
handleAction( wit->second, (char*)pevent->name, pevent->mask );
if ( !movedOutsideWatches.empty() )
{
/// In case that the IN_MOVED_TO is never fired means that the file was moved to other folder
for ( std::list<WatcherInotify*>::iterator it = movedOutsideWatches.begin(); it != movedOutsideWatches.end(); ++it )
{
Watcher * watch = (*it);
if ( !watch->OldFileName.empty() )
{
/// Check if the file move was a folder already being watched
std::list<Watcher*> eraseWatches;
for(; wit != mWatches.end(); ++wit)
{
Watcher * oldWatch = wit->second;
if ( oldWatch != watch &&
-1 != String::strStartsWith( watch->Directory + watch->OldFileName + "/", oldWatch->Directory ) )
{
eraseWatches.push_back( oldWatch );
}
}
/// Remove invalid watches
eraseWatches.sort();
for ( std::list<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); eit != eraseWatches.rend(); ++eit )
{
Watcher * rmWatch = *eit;
/// Create Delete event for removed watches that have been moved too
if ( Watcher * cntWatch = watcherContainsDirectory( rmWatch->Directory ) )
{
handleAction( cntWatch, FileSystem::fileNameFromPath( rmWatch->Directory ), IN_DELETE );
if ( ( pevent->mask & IN_MOVED_TO ) && wit->second == currentMoveFrom &&
pevent->cookie == currentMoveCookie ) {
/// make pair success
currentMoveFrom = NULL;
currentMoveCookie = -1;
} else if ( pevent->mask & IN_MOVED_FROM ) {
// Previous event was moved from and current event is moved from
// Treat it as a DELETE or moved ouside watches
if ( lastWasMovedFrom && currentMoveFrom ) {
mMovedOutsideWatches.push_back(
std::make_pair( currentMoveFrom, prevOldFileName ) );
}
removeWatch( rmWatch->ID );
}
currentMoveFrom = wit->second;
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 ) );
}
/// Remove the OldFileName
watch->OldFileName = "";
currentMoveFrom = NULL;
currentMoveCookie = -1;
}
}
lastWasMovedFrom = ( pevent->mask & IN_MOVED_FROM ) != 0;
if ( pevent->mask & IN_MOVED_FROM )
prevOldFileName = std::string( (char*)pevent->name );
}
movedOutsideWatches.clear();
i += sizeof( struct inotify_event ) + pevent->len;
}
}
} else {
// 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 ) );
}
currentMoveFrom = NULL;
currentMoveCookie = -1;
}
} while( mInitOK );
if ( !mMovedOutsideWatches.empty() ) {
// We need to make a copy since the element mMovedOutsideWatches could be modified
// during the iteration.
std::vector<std::pair<WatcherInotify*, std::string>> movedOutsideWatches(
mMovedOutsideWatches );
/// In case that the IN_MOVED_TO is never fired means that the file was moved to other
/// folder
for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator it =
movedOutsideWatches.begin();
it != movedOutsideWatches.end(); ++it ) {
// Skip if the watch has already being removed
if ( mMovedOutsideWatches.size() != movedOutsideWatches.size() ) {
bool found = false;
for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator itm =
mMovedOutsideWatches.begin();
mMovedOutsideWatches.end() != itm; ++itm ) {
if ( itm->first == it->first ) {
found = true;
break;
}
}
if ( !found )
continue;
}
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;
{
Lock lock( mWatchesLock );
for ( ; wit != mWatches.end(); ++wit ) {
Watcher* oldWatch = wit->second;
if ( oldWatch != watch &&
-1 != String::strStartsWith( watch->Directory + oldFileName + "/",
oldWatch->Directory ) ) {
eraseWatches.push_back( oldWatch );
}
}
}
/// Remove invalid watches
std::stable_sort( eraseWatches.begin(), eraseWatches.end(),
[]( const Watcher* left, const Watcher* right ) {
return left->Directory < right->Directory;
} );
if ( eraseWatches.empty() ) {
handleAction( watch, oldFileName, IN_DELETE );
} else {
for ( std::vector<Watcher*>::reverse_iterator eit = eraseWatches.rbegin();
eit != eraseWatches.rend(); ++eit ) {
Watcher* rmWatch = *eit;
/// Create Delete event for removed watches that have been moved too
if ( Watcher* cntWatch = watcherContainsDirectory( rmWatch->Directory ) ) {
handleAction( cntWatch,
FileSystem::fileNameFromPath( rmWatch->Directory ),
IN_DELETE );
}
}
}
}
mMovedOutsideWatches.clear();
}
} while ( mInitOK );
delete[] buff;
}
void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath )
{
void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) {
FileSystem::dirAddSlashAtEnd( fpath );
/// If the watcher is recursive, checks if the new file is a folder, and creates a watcher
if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
{
if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) {
bool found = false;
/// First check if exists
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
if ( it->second->Directory == fpath )
{
found = true;
break;
Lock lock( mWatchesLock );
/// First check if exists
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
if ( it->second->Directory == fpath ) {
found = true;
break;
}
}
}
if ( !found )
{
addWatch( fpath, watch->Listener, watch->Recursive, static_cast<WatcherInotify*>( watch ) );
if ( !found ) {
addWatch( fpath, watch->Listener, watch->Recursive,
static_cast<WatcherInotify*>( watch ) );
}
}
}
void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, unsigned long action, std::string )
{
if ( !watch || !watch->Listener )
{
void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename,
unsigned long action, std::string ) {
if ( !watch || !watch->Listener || !mInitOK ) {
return;
}
mIsTakingAction = true;
Lock initLock( mInitLock );
std::string fpath( watch->Directory + filename );
if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) )
{
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified );
}
else if( IN_MOVED_TO & action )
{
/// If OldFileName doesn't exist means that the file has been moved from other folder, so we just send the Add event
if ( watch->OldFileName.empty() )
{
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add );
if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) {
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename,
Actions::Modified );
} else if ( IN_MOVED_TO & action ) {
/// If OldFileName doesn't exist means that the file has been moved from other folder, so we
/// just send the Add event
if ( watch->OldFileName.empty() ) {
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename,
Actions::Add );
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified );
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename,
Actions::Modified );
checkForNewWatcher( watch, fpath );
}
else
{
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Moved, watch->OldFileName );
} else {
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename,
Actions::Moved, watch->OldFileName );
}
if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
{
if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) {
/// Update the new directory path
std::string opath( watch->Directory + watch->OldFileName );
FileSystem::dirAddSlashAtEnd( opath );
FileSystem::dirAddSlashAtEnd( fpath );
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
if ( it->second->Directory == opath && it->second->DirInfo.Inode == FileInfo( opath ).Inode )
{
it->second->Directory = fpath;
it->second->DirInfo = FileInfo( fpath );
Lock lock( mWatchesLock );
break;
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
if ( it->second->Directory == opath ) {
it->second->Directory = fpath;
it->second->DirInfo = FileInfo( fpath );
} else if ( -1 != String::strStartsWith( opath, it->second->Directory ) ) {
it->second->Directory = fpath + it->second->Directory.substr( opath.size() );
it->second->DirInfo.Filepath = it->second->Directory;
}
}
}
watch->OldFileName = "";
}
else if( IN_CREATE & action )
{
} else if ( IN_CREATE & action ) {
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add );
checkForNewWatcher( watch, fpath );
}
else if ( IN_MOVED_FROM & action )
{
} else if ( IN_MOVED_FROM & action ) {
watch->OldFileName = filename;
}
else if( IN_DELETE & action )
{
} else if ( IN_DELETE & action ) {
watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete );
FileSystem::dirAddSlashAtEnd( fpath );
/// If the file erased is a directory and recursive is enabled, removes the directory erased
if ( watch->Recursive )
{
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
if ( it->second->Directory == fpath )
{
removeWatch( it->second->ID );
if ( watch->Recursive ) {
Lock l( mWatchesLock );
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
if ( it->second->Directory == fpath ) {
removeWatchLocked( it->second->InotifyID );
break;
}
}
}
}
mIsTakingAction = false;
}
std::list<std::string> FileWatcherInotify::directories()
{
std::list<std::string> dirs;
std::vector<std::string> FileWatcherInotify::directories() {
std::vector<std::string> dirs;
Lock lock( mWatchesLock );
Lock l( mRealWatchesLock );
dirs.reserve( mRealWatches.size() );
WatchMap::iterator it = mRealWatches.begin();
for ( ; it != mRealWatches.end(); ++it )
{
dirs.push_back( it->second->Directory );
}
return dirs;
}
bool FileWatcherInotify::pathInWatches( const std::string& path )
{
bool FileWatcherInotify::pathInWatches( const std::string& path ) {
Lock l( mRealWatchesLock );
/// Search in the real watches, since it must allow adding a watch already watched as a subdir
WatchMap::iterator it = mRealWatches.begin();
for ( ; it != mRealWatches.end(); ++it )
{
if ( it->second->Directory == path )
{
return true;
}
}
return false;
}
}
} // namespace efsw
#endif

View File

@@ -7,68 +7,79 @@
#include <efsw/WatcherInotify.hpp>
#include <map>
#include <unordered_map>
#include <vector>
namespace efsw
{
namespace efsw {
/// Implementation for Linux based on inotify.
/// @class FileWatcherInotify
class FileWatcherInotify : public FileWatcherImpl
{
public:
/// type for a map from WatchID to WatchStruct pointer
typedef std::map<WatchID, WatcherInotify*> WatchMap;
class FileWatcherInotify : public FileWatcherImpl {
public:
/// type for a map from WatchID to WatchStruct pointer
typedef std::map<WatchID, WatcherInotify*> WatchMap;
FileWatcherInotify( FileWatcher * parent );
FileWatcherInotify( FileWatcher* parent );
virtual ~FileWatcherInotify();
virtual ~FileWatcherInotify();
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
const std::vector<WatcherOption>& options ) override;
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch(const std::string& directory);
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch( const std::string& directory ) override;
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch(WatchID watchid);
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch( WatchID watchid ) override;
/// Updates the watcher. Must be called often.
void watch();
/// Updates the watcher. Must be called often.
void watch() override;
/// Handles the action
void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
/// Handles the action
void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
std::string oldFilename = "" ) override;
/// @return Returns a list of the directories that are being watched
std::list<std::string> directories();
protected:
/// Map of WatchID to WatchStruct pointers
WatchMap mWatches;
/// @return Returns a list of the directories that are being watched
std::vector<std::string> directories() override;
/// User added watches
WatchMap mRealWatches;
protected:
/// Map of WatchID to WatchStruct pointers
WatchMap mWatches;
/// inotify file descriptor
int mFD;
/// User added watches
WatchMap mRealWatches;
Thread * mThread;
std::unordered_map<std::string, WatchID> mWatchesRef;
Mutex mWatchesLock;
/// inotify file descriptor
int mFD;
WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent = NULL );
Thread* mThread;
bool pathInWatches( const std::string& path );
private:
void run();
Mutex mWatchesLock;
Mutex mRealWatchesLock;
Mutex mInitLock;
bool mIsTakingAction;
std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches;
void removeWatchLocked(WatchID watchid);
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
WatcherInotify* parent = NULL );
void checkForNewWatcher( Watcher* watch, std::string fpath );
bool pathInWatches( const std::string& path ) override;
Watcher * watcherContainsDirectory( std::string dir );
private:
void run();
void removeWatchLocked( WatchID watchid );
void checkForNewWatcher( Watcher* watch, std::string fpath );
Watcher* watcherContainsDirectory( std::string dir );
};
}
} // namespace efsw
#endif

View File

@@ -2,42 +2,38 @@
#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <efsw/Debug.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/Lock.hpp>
#include <efsw/System.hpp>
#include <efsw/WatcherGeneric.hpp>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <efsw/FileSystem.hpp>
#include <efsw/System.hpp>
#include <efsw/Debug.hpp>
#include <efsw/WatcherGeneric.hpp>
#include <efsw/Lock.hpp>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
namespace efsw
{
namespace efsw {
FileWatcherKqueue::FileWatcherKqueue( FileWatcher * parent ) :
FileWatcherKqueue::FileWatcherKqueue( FileWatcher* parent ) :
FileWatcherImpl( parent ),
mLastWatchID(0),
mLastWatchID( 0 ),
mThread( NULL ),
mFileDescriptorCount( 1 ),
mAddingWatcher( false )
{
mTimeOut.tv_sec = 0;
mTimeOut.tv_nsec = 0;
mInitOK = true;
mAddingWatcher( false ) {
mTimeOut.tv_sec = 0;
mTimeOut.tv_nsec = 0;
mInitOK = true;
}
FileWatcherKqueue::~FileWatcherKqueue()
{
FileWatcherKqueue::~FileWatcherKqueue() {
WatchMap::iterator iter = mWatches.begin();
for(; iter != mWatches.end(); ++iter)
{
for ( ; iter != mWatches.end(); ++iter ) {
efSAFE_DELETE( iter->second );
}
@@ -48,8 +44,8 @@ FileWatcherKqueue::~FileWatcherKqueue()
efSAFE_DELETE( mThread );
}
WatchID FileWatcherKqueue::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
{
WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption>& options ) {
static bool s_ug = false;
std::string dir( directory );
@@ -58,55 +54,43 @@ WatchID FileWatcherKqueue::addWatch(const std::string& directory, FileWatchListe
FileInfo fi( dir );
if ( !fi.isDirectory() )
{
if ( !fi.isDirectory() ) {
return Errors::Log::createLastError( Errors::FileNotFound, dir );
}
else if ( !fi.isReadable() )
{
} else if ( !fi.isReadable() ) {
return Errors::Log::createLastError( Errors::FileNotReadable, dir );
}
else if ( pathInWatches( dir ) )
{
} else if ( pathInWatches( dir ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, directory );
}
std::string curPath;
std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
if ( "" != link )
{
if ( pathInWatches( link ) )
{
if ( "" != link ) {
if ( pathInWatches( link ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, directory );
}
else if ( !linkAllowed( curPath, link ) )
{
} else if ( !linkAllowed( curPath, link ) ) {
return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
}
else
{
} else {
dir = link;
}
}
/// Check first if are enough file descriptors available to create another kqueue watcher, otherwise it creates a generic watcher
if ( availablesFD() )
{
/// Check first if are enough file descriptors available to create another kqueue watcher,
/// otherwise it creates a generic watcher
if ( availablesFD() ) {
mAddingWatcher = true;
WatcherKqueue * watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this );
WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this );
{
Lock lock( mWatchesLock );
mWatches.insert(std::make_pair(mLastWatchID, watch));
mWatches.insert( std::make_pair( mLastWatchID, watch ) );
}
watch->addAll();
// if failed to open the directory... erase the watcher
if ( !watch->initOK() )
{
if ( !watch->initOK() ) {
int le = watch->lastErrno();
mWatches.erase( watch->ID );
@@ -116,129 +100,111 @@ WatchID FileWatcherKqueue::addWatch(const std::string& directory, FileWatchListe
mLastWatchID--;
// Probably the folder has too many files, create a generic watcher
if ( EACCES != le )
{
WatcherGeneric * genericWatch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive );
if ( EACCES != le ) {
WatcherGeneric* genericWatch =
new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive );
Lock lock( mWatchesLock );
mWatches.insert(std::make_pair(mLastWatchID, genericWatch));
}
else
{
mWatches.insert( std::make_pair( mLastWatchID, genericWatch ) );
} else {
return Errors::Log::createLastError( Errors::Unspecified, link );
}
}
mAddingWatcher = false;
}
else
{
if ( !s_ug )
{
efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", mFileDescriptorCount );
} else {
if ( !s_ug ) {
efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n",
mFileDescriptorCount );
s_ug = true;
}
WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive );
WatcherGeneric* watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive );
Lock lock( mWatchesLock );
mWatches.insert(std::make_pair(mLastWatchID, watch));
mWatches.insert( std::make_pair( mLastWatchID, watch ) );
}
return mLastWatchID;
}
void FileWatcherKqueue::removeWatch(const std::string& directory)
{
void FileWatcherKqueue::removeWatch( const std::string& directory ) {
Lock lock( mWatchesLock );
WatchMap::iterator iter = mWatches.begin();
for(; iter != mWatches.end(); ++iter)
{
if(directory == iter->second->Directory)
{
removeWatch(iter->first);
for ( ; iter != mWatches.end(); ++iter ) {
if ( directory == iter->second->Directory ) {
removeWatch( iter->first );
return;
}
}
}
void FileWatcherKqueue::removeWatch(WatchID watchid)
{
void FileWatcherKqueue::removeWatch( WatchID watchid ) {
Lock lock( mWatchesLock );
WatchMap::iterator iter = mWatches.find(watchid);
WatchMap::iterator iter = mWatches.find( watchid );
if(iter == mWatches.end())
if ( iter == mWatches.end() )
return;
Watcher* watch = iter->second;
mWatches.erase(iter);
mWatches.erase( iter );
efSAFE_DELETE( watch );
}
bool FileWatcherKqueue::isAddingWatcher() const
{
bool FileWatcherKqueue::isAddingWatcher() const {
return mAddingWatcher;
}
void FileWatcherKqueue::watch()
{
if ( NULL == mThread )
{
void FileWatcherKqueue::watch() {
if ( NULL == mThread ) {
mThread = new Thread( &FileWatcherKqueue::run, this );
mThread->launch();
}
}
void FileWatcherKqueue::run()
{
do
{
void FileWatcherKqueue::run() {
do {
{
Lock lock( mWatchesLock );
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
it->second->watch();
}
}
System::sleep( 500 );
} while( mInitOK );
} while ( mInitOK );
}
void FileWatcherKqueue::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
{
}
void FileWatcherKqueue::handleAction( Watcher* watch, const std::string& filename,
unsigned long action, std::string oldFilename ) {}
std::list<std::string> FileWatcherKqueue::directories()
{
std::list<std::string> dirs;
std::vector<std::string> FileWatcherKqueue::directories() {
std::vector<std::string> dirs;
Lock lock( mWatchesLock );
dirs.reserve( mWatches.size() );
WatchMap::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); ++it )
{
for ( ; it != mWatches.end(); ++it ) {
dirs.push_back( it->second->Directory );
}
return dirs;
}
bool FileWatcherKqueue::pathInWatches( const std::string& path )
{
bool FileWatcherKqueue::pathInWatches( const std::string& path ) {
WatchMap::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); ++it )
{
if ( it->second->Directory == path )
{
for ( ; it != mWatches.end(); ++it ) {
if ( it->second->Directory == path ) {
return true;
}
}
@@ -246,21 +212,18 @@ bool FileWatcherKqueue::pathInWatches( const std::string& path )
return false;
}
void FileWatcherKqueue::addFD()
{
void FileWatcherKqueue::addFD() {
mFileDescriptorCount++;
}
void FileWatcherKqueue::removeFD()
{
void FileWatcherKqueue::removeFD() {
mFileDescriptorCount--;
}
bool FileWatcherKqueue::availablesFD()
{
bool FileWatcherKqueue::availablesFD() {
return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500;
}
}
} // namespace efsw
#endif

View File

@@ -7,71 +7,74 @@
#include <efsw/WatcherKqueue.hpp>
namespace efsw
{
namespace efsw {
/// Implementation for OSX based on kqueue.
/// @class FileWatcherKqueue
class FileWatcherKqueue : public FileWatcherImpl
{
class FileWatcherKqueue : public FileWatcherImpl {
friend class WatcherKqueue;
public:
FileWatcherKqueue( FileWatcher * parent );
virtual ~FileWatcherKqueue();
public:
FileWatcherKqueue( FileWatcher* parent );
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
virtual ~FileWatcherKqueue();
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch(const std::string& directory);
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
const std::vector<WatcherOption> &options ) override;
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch(WatchID watchid);
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch( const std::string& directory ) override;
/// Updates the watcher. Must be called often.
void watch();
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch( WatchID watchid ) override;
/// Handles the action
void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
/// Updates the watcher. Must be called often.
void watch() override;
/// @return Returns a list of the directories that are being watched
std::list<std::string> directories();
protected:
/// Map of WatchID to WatchStruct pointers
WatchMap mWatches;
/// Handles the action
void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
std::string oldFilename = "" ) override;
/// time out data
struct timespec mTimeOut;
/// @return Returns a list of the directories that are being watched
std::vector<std::string> directories() override;
/// WatchID allocator
int mLastWatchID;
protected:
/// Map of WatchID to WatchStruct pointers
WatchMap mWatches;
Thread * mThread;
/// time out data
struct timespec mTimeOut;
Mutex mWatchesLock;
/// WatchID allocator
int mLastWatchID;
std::list<WatchID> mRemoveList;
Thread* mThread;
long mFileDescriptorCount;
Mutex mWatchesLock;
bool mAddingWatcher;
std::vector<WatchID> mRemoveList;
bool isAddingWatcher() const;
long mFileDescriptorCount;
bool pathInWatches( const std::string& path );
bool mAddingWatcher;
void addFD();
bool isAddingWatcher() const;
void removeFD();
bool pathInWatches( const std::string& path ) override;
bool availablesFD();
private:
void run();
void addFD();
void removeFD();
bool availablesFD();
private:
void run();
};
}
} // namespace efsw
#endif

View File

@@ -1,41 +1,43 @@
#include <efsw/FileWatcherWin32.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/System.hpp>
#include <efsw/String.hpp>
#include <efsw/FileWatcherWin32.hpp>
#include <efsw/Lock.hpp>
#include <efsw/String.hpp>
#include <efsw/System.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
namespace efsw
{
namespace efsw {
FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) :
FileWatcherImpl( parent ),
mLastWatchID(0),
mThread( NULL )
{
mInitOK = true;
FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) :
FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) {
mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 );
if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE )
mInitOK = true;
}
FileWatcherWin32::~FileWatcherWin32()
{
FileWatcherWin32::~FileWatcherWin32() {
mInitOK = false;
if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) {
PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL );
}
efSAFE_DELETE( mThread );
removeAllWatches();
CloseHandle( mIOCP );
}
WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
{
WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, const std::vector<WatcherOption> &options ) {
std::string dir( directory );
FileInfo fi( dir );
if ( !fi.isDirectory() )
{
if ( !fi.isDirectory() ) {
return Errors::Log::createLastError( Errors::FileNotFound, dir );
}
else if ( !fi.isReadable() )
{
} else if ( !fi.isReadable() ) {
return Errors::Log::createLastError( Errors::FileNotReadable, dir );
}
@@ -43,22 +45,22 @@ WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListen
Lock lock( mWatchesLock );
if ( pathInWatches( dir ) )
{
if ( pathInWatches( dir ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, dir );
}
WatchID watchid = ++mLastWatchID;
WatcherStructWin32 * watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), recursive, FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_SIZE
);
DWORD bufferSize = static_cast<DWORD>( getOptionValue(options, Option::WinBufferSize, 63 * 1024) );
DWORD notifyFilter = static_cast<DWORD>( getOptionValue(options, Option::WinNotifyFilter,
FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_SIZE) );
if( NULL == watch )
{
WatcherStructWin32* watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(),
recursive, bufferSize, notifyFilter, mIOCP );
if ( NULL == watch ) {
return Errors::Log::createLastError( Errors::FileNotFound, dir );
}
@@ -66,241 +68,191 @@ WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListen
watch->Watch->ID = watchid;
watch->Watch->Watch = this;
watch->Watch->Listener = watcher;
watch->Watch->DirName = new char[dir.length()+1];
strcpy(watch->Watch->DirName, dir.c_str());
watch->Watch->DirName = new char[dir.length() + 1];
strcpy( watch->Watch->DirName, dir.c_str() );
mWatchesNew.insert( watch );
mWatches.insert( watch );
return watchid;
}
void FileWatcherWin32::removeWatch(const std::string& directory)
{
void FileWatcherWin32::removeWatch( const std::string& directory ) {
Lock lock( mWatchesLock );
Watches::iterator iter = mWatches.begin();
for(; iter != mWatches.end(); ++iter)
{
if(directory == (*iter)->Watch->DirName)
{
removeWatch(*iter);
for ( ; iter != mWatches.end(); ++iter ) {
if ( directory == ( *iter )->Watch->DirName ) {
removeWatch( *iter );
break;
}
}
}
void FileWatcherWin32::removeWatch(WatchID watchid)
{
void FileWatcherWin32::removeWatch( WatchID watchid ) {
Lock lock( mWatchesLock );
Watches::iterator iter = mWatches.begin();
for(; iter != mWatches.end(); ++iter)
{
for ( ; iter != mWatches.end(); ++iter ) {
// Find the watch ID
if ( (*iter)->Watch->ID == watchid )
{
removeWatch(*iter);
if ( ( *iter )->Watch->ID == watchid ) {
removeWatch( *iter );
return;
}
}
}
void FileWatcherWin32::removeWatch(WatcherStructWin32* watch)
{
mWatchesRemoved.insert(watch);
if( NULL == mThread )
{
removeWatches();
}
}
void FileWatcherWin32::removeWatches()
{
void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) {
Lock lock( mWatchesLock );
Watches::iterator remWatchIter = mWatchesRemoved.begin();
for( ; remWatchIter != mWatchesRemoved.end(); ++remWatchIter )
{
Watches::iterator iter = mWatches.find(*remWatchIter);
if( iter != mWatches.end() )
{
DestroyWatch(*iter);
mWatches.erase( iter );
}
iter = mWatchesNew.find(*remWatchIter);
if( iter != mWatchesNew.end() )
{
mWatchesNew.erase( iter );
}
}
mWatchesRemoved.clear();
DestroyWatch( watch );
mWatches.erase( watch );
}
void FileWatcherWin32::watch()
{
if ( NULL == mThread )
{
void FileWatcherWin32::watch() {
if ( NULL == mThread ) {
mThread = new Thread( &FileWatcherWin32::run, this );
mThread->launch();
}
}
void FileWatcherWin32::removeAllWatches()
{
void FileWatcherWin32::removeAllWatches() {
Lock lock( mWatchesLock );
Watches::iterator iter = mWatches.begin();
for( ; iter != mWatches.end(); ++iter )
{
DestroyWatch((*iter));
for ( ; iter != mWatches.end(); ++iter ) {
DestroyWatch( ( *iter ) );
}
mWatches.clear();
mWatchesRemoved.clear();
mWatchesNew.clear();
}
void FileWatcherWin32::run()
{
do
{
if ( !mWatches.empty() )
{
{
Lock lock( mWatchesLock );
void FileWatcherWin32::run() {
do {
if ( mInitOK && !mWatches.empty() ) {
DWORD numOfBytes = 0;
OVERLAPPED* ov = NULL;
ULONG_PTR compKey = 0;
BOOL res = FALSE;
for( Watches::iterator iter = mWatches.begin() ; iter != mWatches.end(); ++iter )
{
WatcherStructWin32 * watch = *iter;
if ( HasOverlappedIoCompleted( &watch->Overlapped ) )
{
DWORD bytes;
if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) )
{
WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped );
}
}
while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov,
INFINITE ) ) != FALSE ) {
if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) {
break;
} else {
Lock lock( mWatchesLock );
WatchCallback( numOfBytes, ov );
}
}
if ( mInitOK )
{
System::sleep( 10 );
}
}
else
{
// Wait for a new handle to be added
} else {
System::sleep( 10 );
}
removeWatches();
for ( Watches::iterator it = mWatchesNew.begin(); it != mWatchesNew.end(); ++it )
{
RefreshWatch(*it);
}
mWatchesNew.clear();
} while ( mInitOK );
removeAllWatches();
}
void FileWatcherWin32::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
{
void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename,
unsigned long action, std::string /*oldFilename*/ ) {
Action fwAction;
switch(action)
{
case FILE_ACTION_RENAMED_OLD_NAME:
watch->OldFileName = filename;
return;
case FILE_ACTION_ADDED:
fwAction = Actions::Add;
break;
case FILE_ACTION_RENAMED_NEW_NAME:
{
fwAction = Actions::Moved;
switch ( action ) {
case FILE_ACTION_RENAMED_OLD_NAME:
watch->OldFileName = filename;
return;
case FILE_ACTION_ADDED:
fwAction = Actions::Add;
break;
case FILE_ACTION_RENAMED_NEW_NAME: {
fwAction = Actions::Moved;
std::string fpath( watch->Directory + filename );
std::string fpath( watch->Directory + filename );
// Update the directory path
if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
{
// Update the new directory path
std::string opath( watch->Directory + watch->OldFileName );
FileSystem::dirAddSlashAtEnd( opath );
FileSystem::dirAddSlashAtEnd( fpath );
// Update the directory path
if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) {
// Update the new directory path
std::string opath( watch->Directory + watch->OldFileName );
FileSystem::dirAddSlashAtEnd( opath );
FileSystem::dirAddSlashAtEnd( fpath );
for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
if ( (*it)->Watch->Directory == opath )
{
(*it)->Watch->Directory = fpath;
for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
if ( ( *it )->Watch->Directory == opath ) {
( *it )->Watch->Directory = fpath;
break;
break;
}
}
}
}
watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction, watch->OldFileName);
return;
}
case FILE_ACTION_REMOVED:
fwAction = Actions::Delete;
break;
case FILE_ACTION_MODIFIED:
fwAction = Actions::Modified;
break;
std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName );
std::string realFilename = filename;
std::size_t sepPos = filename.find_last_of( "/\\" );
std::string oldFolderPath =
static_cast<WatcherWin32*>( watch )->DirName +
watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) );
if ( sepPos != std::string::npos ) {
folderPath +=
filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos );
realFilename = filename.substr( sepPos + 1 );
}
if ( folderPath == oldFolderPath ) {
watch->Listener->handleFileAction(
watch->ID, folderPath, realFilename, fwAction,
FileSystem::fileNameFromPath( watch->OldFileName ) );
} else {
watch->Listener->handleFileAction( watch->ID,
static_cast<WatcherWin32*>( watch )->DirName,
filename, fwAction, watch->OldFileName );
}
return;
}
case FILE_ACTION_REMOVED:
fwAction = Actions::Delete;
break;
case FILE_ACTION_MODIFIED:
fwAction = Actions::Modified;
break;
default:
return;
};
std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName );
std::string realFilename = filename;
std::size_t sepPos = filename.find_last_of("/\\");
std::size_t sepPos = filename.find_last_of( "/\\" );
if ( sepPos != std::string::npos )
{
folderPath += filename.substr( 0, sepPos );
if ( sepPos != std::string::npos ) {
folderPath += filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos );
realFilename = filename.substr( sepPos + 1 );
}
watch->Listener->handleFileAction(watch->ID, folderPath, realFilename, fwAction);
FileSystem::dirAddSlashAtEnd( folderPath );
watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction );
}
std::list<std::string> FileWatcherWin32::directories()
{
std::list<std::string> dirs;
std::vector<std::string> FileWatcherWin32::directories() {
std::vector<std::string> dirs;
Lock lock( mWatchesLock );
for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
dirs.push_back( std::string( (*it)->Watch->DirName ) );
dirs.reserve( mWatches.size() );
for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
dirs.push_back( std::string( ( *it )->Watch->DirName ) );
}
return dirs;
}
bool FileWatcherWin32::pathInWatches( const std::string& path )
{
for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
if ( (*it)->Watch->DirName == path )
{
bool FileWatcherWin32::pathInWatches( const std::string& path ) {
Lock lock( mWatchesLock );
for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
if ( ( *it )->Watch->DirName == path ) {
return true;
}
}
@@ -308,6 +260,6 @@ bool FileWatcherWin32::pathInWatches( const std::string& path )
return false;
}
}
} // namespace efsw
#endif

View File

@@ -6,68 +6,65 @@
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#include <efsw/WatcherWin32.hpp>
#include <set>
#include <map>
#include <set>
#include <vector>
namespace efsw
{
namespace efsw {
/// Implementation for Win32 based on ReadDirectoryChangesW.
/// @class FileWatcherWin32
class FileWatcherWin32 : public FileWatcherImpl
{
public:
/// type for a map from WatchID to WatcherWin32 pointer
typedef std::set<WatcherStructWin32*> Watches;
class FileWatcherWin32 : public FileWatcherImpl {
public:
/// type for a map from WatchID to WatcherWin32 pointer
typedef std::set<WatcherStructWin32*> Watches;
FileWatcherWin32( FileWatcher * parent );
FileWatcherWin32( FileWatcher* parent );
virtual ~FileWatcherWin32();
virtual ~FileWatcherWin32();
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
/// Add a directory watch
/// On error returns WatchID with Error type.
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
const std::vector<WatcherOption> &options ) override;
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch(const std::string& directory);
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch( const std::string& directory ) override;
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch(WatchID watchid);
/// Remove a directory watch. This is a map lookup O(logn).
void removeWatch( WatchID watchid ) override;
/// Updates the watcher. Must be called often.
void watch();
/// Updates the watcher. Must be called often.
void watch() override;
/// Handles the action
void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
/// Handles the action
void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
std::string oldFilename = "" ) override;
/// @return Returns a list of the directories that are being watched
std::list<std::string> directories();
protected:
Watches mWatches;
Watches mWatchesRemoved;
Watches mWatchesNew;
/// @return Returns a list of the directories that are being watched
std::vector<std::string> directories() override;
/// The last watchid
WatchID mLastWatchID;
protected:
HANDLE mIOCP;
Watches mWatches;
Thread * mThread;
/// The last watchid
WatchID mLastWatchID;
Thread* mThread;
Mutex mWatchesLock;
Mutex mWatchesLock;
bool pathInWatches( const std::string& path ) override;
bool pathInWatches( const std::string& path );
/// Remove all directory watches.
void removeAllWatches();
/// Remove all directory watches.
void removeAllWatches();
void removeWatch( WatcherStructWin32* watch );
/// Remove needed directory watches.
void removeWatches();
void removeWatch(WatcherStructWin32* watch);
private:
void run();
private:
void run();
};
}
} // namespace efsw
#endif

View File

@@ -7,21 +7,15 @@ namespace efsw {
/** Simple mutex class */
class Lock {
public:
explicit Lock( Mutex& mutex ) :
mMutex( mutex )
{
mMutex.lock();
}
public:
explicit Lock( Mutex& mutex ) : mMutex( mutex ) { mMutex.lock(); }
~Lock()
{
mMutex.unlock();
}
private:
Mutex& mMutex;
~Lock() { mMutex.unlock(); }
private:
Mutex& mMutex;
};
}
} // namespace efsw
#endif

View File

@@ -1,27 +1,49 @@
#include <efsw/efsw.hpp>
#include <efsw/Debug.hpp>
namespace efsw { namespace Errors {
static std::string LastError;
static std::string LastError = "";
static Error LastErrorCode = NoError;
std::string Log::getLastErrorLog()
{
std::string Log::getLastErrorLog() {
return LastError;
}
Error Log::createLastError( Error err, std::string log )
{
switch ( err )
{
case FileNotFound: LastError = "File not found ( " + log + " )"; break;
case FileRepeated: LastError = "File reapeated in watches ( " + log + " )"; break;
case FileOutOfScope: LastError = "Symlink file out of scope ( " + log + " )"; break;
case FileRemote: LastError = "File is located in a remote file system, use a generic watcher. ( " + log + " )"; break;
Error Log::getLastErrorCode() {
return LastErrorCode;
}
void Log::clearLastError() {
LastErrorCode = NoError;
LastError = "";
}
Error Log::createLastError( Error err, std::string log ) {
switch ( err ) {
case FileNotFound:
LastError = "File not found ( " + log + " )";
break;
case FileRepeated:
LastError = "File repeated in watches ( " + log + " )";
break;
case FileOutOfScope:
LastError = "Symlink file out of scope ( " + log + " )";
break;
case FileRemote:
LastError =
"File is located in a remote file system, use a generic watcher. ( " + log + " )";
break;
case WatcherFailed:
LastError = "File system watcher failed ( " + log + " )";
break;
case Unspecified:
default: LastError = log;
default:
LastError = log;
}
efDEBUG( "%s\n", LastError.c_str() );
return err;
}
}}
}} // namespace efsw::Errors

View File

@@ -3,24 +3,18 @@
namespace efsw {
Mutex::Mutex() :
mMutexImpl( new Platform::MutexImpl() )
{
}
Mutex::Mutex() : mMutexImpl( new Platform::MutexImpl() ) {}
Mutex::~Mutex()
{
Mutex::~Mutex() {
efSAFE_DELETE( mMutexImpl );
}
void Mutex::lock()
{
void Mutex::lock() {
mMutexImpl->lock();
}
void Mutex::unlock()
{
void Mutex::unlock() {
mMutexImpl->unlock();
}
}
} // namespace efsw

View File

@@ -5,24 +5,27 @@
namespace efsw {
namespace Platform { class MutexImpl; }
namespace Platform {
class MutexImpl;
}
/** Simple mutex class */
class Mutex {
public:
Mutex();
public:
Mutex();
~Mutex();
~Mutex();
/** Lock the mutex */
void lock();
/** Lock the mutex */
void lock();
/** Unlock the mutex */
void unlock();
private:
Platform::MutexImpl * mMutexImpl;
/** Unlock the mutex */
void unlock();
private:
Platform::MutexImpl* mMutexImpl;
};
}
} // namespace efsw
#endif

View File

@@ -1,84 +1,66 @@
#include <iterator>
#include <efsw/String.hpp>
#include <efsw/Utf.hpp>
#include <iterator>
namespace efsw {
const std::size_t String::InvalidPos = StringType::npos;
std::vector < std::string > String::split ( const std::string& str, const char& splitchar, const bool& pushEmptyString )
{
std::vector < std::string > tmp;
std::vector<std::string> String::split( const std::string& str, const char& splitchar,
const bool& pushEmptyString ) {
std::vector<std::string> tmp;
std::string tmpstr;
for ( size_t i = 0; i < str.size(); i++ )
{
if ( str[i] == splitchar )
{
if ( pushEmptyString || tmpstr.size() )
{
tmp.push_back(tmpstr);
for ( size_t i = 0; i < str.size(); i++ ) {
if ( str[i] == splitchar ) {
if ( pushEmptyString || tmpstr.size() ) {
tmp.push_back( tmpstr );
tmpstr = "";
}
}
else
{
} else {
tmpstr += str[i];
}
}
if ( tmpstr.size() )
{
if ( tmpstr.size() ) {
tmp.push_back( tmpstr );
}
return tmp;
}
std::vector < String > String::split ( const String& str, const Uint32& splitchar, const bool& pushEmptyString )
{
std::vector < String > tmp;
std::vector<String> String::split( const String& str, const Uint32& splitchar,
const bool& pushEmptyString ) {
std::vector<String> tmp;
String tmpstr;
for ( size_t i = 0; i < str.size(); i++ )
{
if ( str[i] == splitchar )
{
if ( pushEmptyString || tmpstr.size() )
{
tmp.push_back(tmpstr);
for ( size_t i = 0; i < str.size(); i++ ) {
if ( str[i] == splitchar ) {
if ( pushEmptyString || tmpstr.size() ) {
tmp.push_back( tmpstr );
tmpstr = "";
}
}
else
{
} else {
tmpstr += str[i];
}
}
if ( tmpstr.size() )
{
if ( tmpstr.size() ) {
tmp.push_back( tmpstr );
}
return tmp;
}
int String::strStartsWith( const std::string& start, const std::string& str )
{
int pos = -1;
size_t size = start.size();
int String::strStartsWith( const std::string& start, const std::string& str ) {
int pos = -1;
size_t size = start.size();
if ( str.size() >= size )
{
for ( std::size_t i = 0; i < size; i++ )
{
if ( start[i] == str[i] )
{
if ( str.size() >= size ) {
for ( std::size_t i = 0; i < size; i++ ) {
if ( start[i] == str[i] ) {
pos = (int)i;
}
else
{
} else {
pos = -1;
break;
}
@@ -88,21 +70,15 @@ int String::strStartsWith( const std::string& start, const std::string& str )
return pos;
}
int String::strStartsWith( const String& start, const String& str )
{
int pos = -1;
size_t size = start.size();
int String::strStartsWith( const String& start, const String& str ) {
int pos = -1;
size_t size = start.size();
if ( str.size() >= size )
{
for ( std::size_t i = 0; i < size; i++ )
{
if ( start[i] == str[i] )
{
if ( str.size() >= size ) {
for ( std::size_t i = 0; i < size; i++ ) {
if ( start[i] == str[i] ) {
pos = (int)i;
}
else
{
} else {
pos = -1;
break;
}
@@ -112,37 +88,30 @@ int String::strStartsWith( const String& start, const String& str )
return pos;
}
String::String()
{
}
String::String() {}
String::String(char ansiChar, const std::locale& locale)
{
mString += Utf32::DecodeAnsi(ansiChar, locale);
String::String( char ansiChar, const std::locale& locale ) {
mString += Utf32::DecodeAnsi( ansiChar, locale );
}
#ifndef EFSW_NO_WIDECHAR
String::String(wchar_t wideChar)
{
mString += Utf32::DecodeWide(wideChar);
String::String( wchar_t wideChar ) {
mString += Utf32::DecodeWide( wideChar );
}
#endif
String::String(StringBaseType utf32Char)
{
String::String( StringBaseType utf32Char ) {
mString += utf32Char;
}
String::String( const char* uf8String ) {
if (uf8String)
{
std::size_t length = strlen(uf8String);
if ( uf8String ) {
std::size_t length = strlen( uf8String );
if (length > 0)
{
mString.reserve(length + 1);
if ( length > 0 ) {
mString.reserve( length + 1 );
Utf8::ToUtf32(uf8String, uf8String + length, std::back_inserter(mString));
Utf8::ToUtf32( uf8String, uf8String + length, std::back_inserter( mString ) );
}
}
}
@@ -153,64 +122,49 @@ String::String( const std::string& utf8String ) {
Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( mString ) );
}
String::String(const char* ansiString, const std::locale& locale)
{
if (ansiString)
{
std::size_t length = strlen(ansiString);
if (length > 0)
{
mString.reserve(length + 1);
Utf32::FromAnsi(ansiString, ansiString + length, std::back_inserter(mString), locale);
String::String( const char* ansiString, const std::locale& locale ) {
if ( ansiString ) {
std::size_t length = strlen( ansiString );
if ( length > 0 ) {
mString.reserve( length + 1 );
Utf32::FromAnsi( ansiString, ansiString + length, std::back_inserter( mString ),
locale );
}
}
}
String::String(const std::string& ansiString, const std::locale& locale)
{
mString.reserve(ansiString.length() + 1);
Utf32::FromAnsi(ansiString.begin(), ansiString.end(), std::back_inserter(mString), locale);
String::String( const std::string& ansiString, const std::locale& locale ) {
mString.reserve( ansiString.length() + 1 );
Utf32::FromAnsi( ansiString.begin(), ansiString.end(), std::back_inserter( mString ), locale );
}
#ifndef EFSW_NO_WIDECHAR
String::String(const wchar_t* wideString)
{
if (wideString)
{
std::size_t length = std::wcslen(wideString);
if (length > 0)
{
mString.reserve(length + 1);
Utf32::FromWide(wideString, wideString + length, std::back_inserter(mString));
String::String( const wchar_t* wideString ) {
if ( wideString ) {
std::size_t length = std::wcslen( wideString );
if ( length > 0 ) {
mString.reserve( length + 1 );
Utf32::FromWide( wideString, wideString + length, std::back_inserter( mString ) );
}
}
}
String::String(const std::wstring& wideString)
{
mString.reserve(wideString.length() + 1);
Utf32::FromWide(wideString.begin(), wideString.end(), std::back_inserter(mString));
String::String( const std::wstring& wideString ) {
mString.reserve( wideString.length() + 1 );
Utf32::FromWide( wideString.begin(), wideString.end(), std::back_inserter( mString ) );
}
#endif
String::String(const StringBaseType* utf32String)
{
if (utf32String)
String::String( const StringBaseType* utf32String ) {
if ( utf32String )
mString = utf32String;
}
String::String(const StringType& utf32String) :
mString(utf32String)
{
}
String::String( const StringType& utf32String ) : mString( utf32String ) {}
String::String(const String& str) :
mString(str.mString)
{
}
String::String( const String& str ) : mString( str.mString ) {}
String String::fromUtf8( const std::string& utf8String )
{
String String::fromUtf8( const std::string& utf8String ) {
String::StringType utf32;
utf32.reserve( utf8String.length() + 1 );
@@ -220,32 +174,29 @@ String String::fromUtf8( const std::string& utf8String )
return String( utf32 );
}
String::operator std::string() const
{
String::operator std::string() const {
return toAnsiString();
}
std::string String::toAnsiString(const std::locale& locale) const
{
std::string String::toAnsiString( const std::locale& locale ) const {
// Prepare the output string
std::string output;
output.reserve(mString.length() + 1);
output.reserve( mString.length() + 1 );
// Convert
Utf32::ToAnsi(mString.begin(), mString.end(), std::back_inserter(output), 0, locale);
Utf32::ToAnsi( mString.begin(), mString.end(), std::back_inserter( output ), 0, locale );
return output;
}
#ifndef EFSW_NO_WIDECHAR
std::wstring String::toWideString() const
{
std::wstring String::toWideString() const {
// Prepare the output string
std::wstring output;
output.reserve(mString.length() + 1);
output.reserve( mString.length() + 1 );
// Convert
Utf32::ToWide(mString.begin(), mString.end(), std::back_inserter(output), 0);
Utf32::ToWide( mString.begin(), mString.end(), std::back_inserter( output ), 0 );
return output;
}
@@ -254,103 +205,85 @@ std::wstring String::toWideString() const
std::string String::toUtf8() const {
// Prepare the output string
std::string output;
output.reserve(mString.length() + 1);
output.reserve( mString.length() + 1 );
// Convert
Utf32::toUtf8(mString.begin(), mString.end(), std::back_inserter(output) );
Utf32::toUtf8( mString.begin(), mString.end(), std::back_inserter( output ) );
return output;
}
String& String::operator =(const String& right)
{
String& String::operator=( const String& right ) {
mString = right.mString;
return *this;
}
String& String::operator =( const StringBaseType& right )
{
String& String::operator=( const StringBaseType& right ) {
mString = right;
return *this;
}
String& String::operator +=(const String& right)
{
String& String::operator+=( const String& right ) {
mString += right.mString;
return *this;
}
String& String::operator +=( const StringBaseType& right )
{
String& String::operator+=( const StringBaseType& right ) {
mString += right;
return *this;
}
String::StringBaseType String::operator [](std::size_t index) const
{
String::StringBaseType String::operator[]( std::size_t index ) const {
return mString[index];
}
String::StringBaseType& String::operator [](std::size_t index)
{
String::StringBaseType& String::operator[]( std::size_t index ) {
return mString[index];
}
String::StringBaseType String::at( std::size_t index ) const
{
String::StringBaseType String::at( std::size_t index ) const {
return mString.at( index );
}
void String::push_back( StringBaseType c )
{
void String::push_back( StringBaseType c ) {
mString.push_back( c );
}
void String::swap ( String& str )
{
void String::swap( String& str ) {
mString.swap( str.mString );
}
void String::clear()
{
void String::clear() {
mString.clear();
}
std::size_t String::size() const
{
std::size_t String::size() const {
return mString.size();
}
std::size_t String::length() const
{
std::size_t String::length() const {
return mString.length();
}
bool String::empty() const
{
bool String::empty() const {
return mString.empty();
}
void String::erase(std::size_t position, std::size_t count)
{
mString.erase(position, count);
void String::erase( std::size_t position, std::size_t count ) {
mString.erase( position, count );
}
String& String::insert(std::size_t position, const String& str)
{
mString.insert(position, str.mString);
String& String::insert( std::size_t position, const String& str ) {
mString.insert( position, str.mString );
return *this;
}
String& String::insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n )
{
String& String::insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n ) {
mString.insert( pos1, str.mString, pos2, n );
return *this;
}
String& String::insert ( size_t pos1, const char* s, size_t n )
{
String& String::insert( size_t pos1, const char* s, size_t n ) {
String tmp( s );
mString.insert( pos1, tmp.data(), n );
@@ -358,14 +291,12 @@ String& String::insert ( size_t pos1, const char* s, size_t n )
return *this;
}
String& String::insert ( size_t pos1, size_t n, char c )
{
String& String::insert( size_t pos1, size_t n, char c ) {
mString.insert( pos1, n, c );
return *this;
}
String& String::insert ( size_t pos1, const char* s )
{
String& String::insert( size_t pos1, const char* s ) {
String tmp( s );
mString.insert( pos1, tmp.data() );
@@ -373,105 +304,85 @@ String& String::insert ( size_t pos1, const char* s )
return *this;
}
String::Iterator String::insert ( Iterator p, char c )
{
String::Iterator String::insert( Iterator p, char c ) {
return mString.insert( p, c );
}
void String::insert ( Iterator p, size_t n, char c )
{
void String::insert( Iterator p, size_t n, char c ) {
mString.insert( p, n, c );
}
const String::StringBaseType* String::c_str() const
{
const String::StringBaseType* String::c_str() const {
return mString.c_str();
}
const String::StringBaseType* String::data() const
{
const String::StringBaseType* String::data() const {
return mString.data();
}
String::Iterator String::begin()
{
String::Iterator String::begin() {
return mString.begin();
}
String::ConstIterator String::begin() const
{
String::ConstIterator String::begin() const {
return mString.begin();
}
String::Iterator String::end()
{
String::Iterator String::end() {
return mString.end();
}
String::ConstIterator String::end() const
{
String::ConstIterator String::end() const {
return mString.end();
}
String::ReverseIterator String::rbegin()
{
String::ReverseIterator String::rbegin() {
return mString.rbegin();
}
String::ConstReverseIterator String::rbegin() const
{
String::ConstReverseIterator String::rbegin() const {
return mString.rbegin();
}
String::ReverseIterator String::rend()
{
String::ReverseIterator String::rend() {
return mString.rend();
}
String::ConstReverseIterator String::rend() const
{
String::ConstReverseIterator String::rend() const {
return mString.rend();
}
void String::resize( std::size_t n, StringBaseType c )
{
void String::resize( std::size_t n, StringBaseType c ) {
mString.resize( n, c );
}
void String::resize( std::size_t n )
{
void String::resize( std::size_t n ) {
mString.resize( n );
}
std::size_t String::max_size() const
{
std::size_t String::max_size() const {
return mString.max_size();
}
void String::reserve( size_t res_arg )
{
void String::reserve( size_t res_arg ) {
mString.reserve( res_arg );
}
std::size_t String::capacity() const
{
std::size_t String::capacity() const {
return mString.capacity();
}
String& String::assign ( const String& str )
{
String& String::assign( const String& str ) {
mString.assign( str.mString );
return *this;
}
String& String::assign ( const String& str, size_t pos, size_t n )
{
String& String::assign( const String& str, size_t pos, size_t n ) {
mString.assign( str.mString, pos, n );
return *this;
}
String& String::assign ( const char* s, size_t n )
{
String& String::assign( const char* s, size_t n ) {
String tmp( s );
mString.assign( tmp.mString );
@@ -479,8 +390,7 @@ String& String::assign ( const char* s, size_t n )
return *this;
}
String& String::assign ( const char* s )
{
String& String::assign( const char* s ) {
String tmp( s );
mString.assign( tmp.mString );
@@ -488,29 +398,25 @@ String& String::assign ( const char* s )
return *this;
}
String& String::assign ( size_t n, char c )
{
String& String::assign( size_t n, char c ) {
mString.assign( n, c );
return *this;
}
String& String::append ( const String& str )
{
String& String::append( const String& str ) {
mString.append( str.mString );
return *this;
}
String& String::append ( const String& str, size_t pos, size_t n )
{
String& String::append( const String& str, size_t pos, size_t n ) {
mString.append( str.mString, pos, n );
return *this;
}
String& String::append ( const char* s, size_t n )
{
String& String::append( const char* s, size_t n ) {
String tmp( s );
mString.append( tmp.mString );
@@ -518,8 +424,7 @@ String& String::append ( const char* s, size_t n )
return *this;
}
String& String::append ( const char* s )
{
String& String::append( const char* s ) {
String tmp( s );
mString.append( tmp.mString );
@@ -527,43 +432,37 @@ String& String::append ( const char* s )
return *this;
}
String& String::append ( size_t n, char c )
{
String& String::append( size_t n, char c ) {
mString.append( n, c );
return *this;
}
String& String::append ( std::size_t n, StringBaseType c )
{
String& String::append( std::size_t n, StringBaseType c ) {
mString.append( n, c );
return *this;
}
String& String::replace ( size_t pos1, size_t n1, const String& str )
{
String& String::replace( size_t pos1, size_t n1, const String& str ) {
mString.replace( pos1, n1, str.mString );
return *this;
}
String& String::replace ( Iterator i1, Iterator i2, const String& str )
{
String& String::replace( Iterator i1, Iterator i2, const String& str ) {
mString.replace( i1, i2, str.mString );
return *this;
}
String& String::replace ( size_t pos1, size_t n1, const String& str, size_t pos2, size_t n2 )
{
String& String::replace( size_t pos1, size_t n1, const String& str, size_t pos2, size_t n2 ) {
mString.replace( pos1, n1, str.mString, pos2, n2 );
return *this;
}
String& String::replace ( size_t pos1, size_t n1, const char* s, size_t n2 )
{
String& String::replace( size_t pos1, size_t n1, const char* s, size_t n2 ) {
String tmp( s );
mString.replace( pos1, n1, tmp.data(), n2 );
@@ -571,8 +470,7 @@ String& String::replace ( size_t pos1, size_t n1, const char* s, size_t n2 )
return *this;
}
String& String::replace ( Iterator i1, Iterator i2, const char* s, size_t n2 )
{
String& String::replace( Iterator i1, Iterator i2, const char* s, size_t n2 ) {
String tmp( s );
mString.replace( i1, i2, tmp.data(), n2 );
@@ -580,8 +478,7 @@ String& String::replace ( Iterator i1, Iterator i2, const char* s, size_t n2 )
return *this;
}
String& String::replace ( size_t pos1, size_t n1, const char* s )
{
String& String::replace( size_t pos1, size_t n1, const char* s ) {
String tmp( s );
mString.replace( pos1, n1, tmp.mString );
@@ -589,8 +486,7 @@ String& String::replace ( size_t pos1, size_t n1, const char* s )
return *this;
}
String& String::replace ( Iterator i1, Iterator i2, const char* s )
{
String& String::replace( Iterator i1, Iterator i2, const char* s ) {
String tmp( s );
mString.replace( i1, i2, tmp.mString );
@@ -598,216 +494,176 @@ String& String::replace ( Iterator i1, Iterator i2, const char* s )
return *this;
}
String& String::replace ( size_t pos1, size_t n1, size_t n2, char c )
{
String& String::replace( size_t pos1, size_t n1, size_t n2, char c ) {
mString.replace( pos1, n1, n2, (StringBaseType)c );
return *this;
}
String& String::replace ( Iterator i1, Iterator i2, size_t n2, char c )
{
String& String::replace( Iterator i1, Iterator i2, size_t n2, char c ) {
mString.replace( i1, i2, n2, (StringBaseType)c );
return *this;
}
std::size_t String::find( const String& str, std::size_t start ) const
{
std::size_t String::find( const String& str, std::size_t start ) const {
return mString.find( str.mString, start );
}
std::size_t String::find ( const char* s, std::size_t pos, std::size_t n ) const
{
std::size_t String::find( const char* s, std::size_t pos, std::size_t n ) const {
return find( String( s ), pos );
}
std::size_t String::find ( const char* s, std::size_t pos ) const
{
std::size_t String::find( const char* s, std::size_t pos ) const {
return find( String( s ), pos );
}
size_t String::find ( char c, std::size_t pos ) const
{
size_t String::find( char c, std::size_t pos ) const {
return mString.find( (StringBaseType)c, pos );
}
std::size_t String::rfind ( const String& str, std::size_t pos ) const
{
std::size_t String::rfind( const String& str, std::size_t pos ) const {
return mString.rfind( str.mString, pos );
}
std::size_t String::rfind ( const char* s, std::size_t pos, std::size_t n ) const
{
std::size_t String::rfind( const char* s, std::size_t pos, std::size_t n ) const {
return rfind( String( s ), pos );
}
std::size_t String::rfind ( const char* s, std::size_t pos ) const
{
std::size_t String::rfind( const char* s, std::size_t pos ) const {
return rfind( String( s ), pos );
}
std::size_t String::rfind ( char c, std::size_t pos ) const
{
std::size_t String::rfind( char c, std::size_t pos ) const {
return mString.rfind( c, pos );
}
std::size_t String::copy ( StringBaseType* s, std::size_t n, std::size_t pos ) const
{
std::size_t String::copy( StringBaseType* s, std::size_t n, std::size_t pos ) const {
return mString.copy( s, n, pos );
}
String String::substr ( std::size_t pos, std::size_t n ) const
{
String String::substr( std::size_t pos, std::size_t n ) const {
return String( mString.substr( pos, n ) );
}
int String::compare ( const String& str ) const
{
int String::compare( const String& str ) const {
return mString.compare( str.mString );
}
int String::compare ( const char* s ) const
{
int String::compare( const char* s ) const {
return compare( String( s ) );
}
int String::compare ( std::size_t pos1, std::size_t n1, const String& str ) const
{
int String::compare( std::size_t pos1, std::size_t n1, const String& str ) const {
return mString.compare( pos1, n1, str.mString );
}
int String::compare ( std::size_t pos1, std::size_t n1, const char* s) const
{
int String::compare( std::size_t pos1, std::size_t n1, const char* s ) const {
return compare( pos1, n1, String( s ) );
}
int String::compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const
{
int String::compare( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2,
std::size_t n2 ) const {
return mString.compare( pos1, n1, str.mString, pos2, n2 );
}
int String::compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const
{
int String::compare( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ) const {
return compare( pos1, n1, String( s ), 0, n2 );
}
std::size_t String::find_first_of ( const String& str, std::size_t pos ) const
{
std::size_t String::find_first_of( const String& str, std::size_t pos ) const {
return mString.find_first_of( str.mString, pos );
}
std::size_t String::find_first_of ( const char* s, std::size_t pos, std::size_t n ) const
{
std::size_t String::find_first_of( const char* s, std::size_t pos, std::size_t n ) const {
return find_first_of( String( s ), pos );
}
std::size_t String::find_first_of ( const char* s, std::size_t pos ) const
{
std::size_t String::find_first_of( const char* s, std::size_t pos ) const {
return find_first_of( String( s ), pos );
}
std::size_t String::find_first_of ( StringBaseType c, std::size_t pos ) const
{
std::size_t String::find_first_of( StringBaseType c, std::size_t pos ) const {
return mString.find_first_of( c, pos );
}
std::size_t String::find_last_of ( const String& str, std::size_t pos ) const
{
std::size_t String::find_last_of( const String& str, std::size_t pos ) const {
return mString.find_last_of( str.mString, pos );
}
std::size_t String::find_last_of ( const char* s, std::size_t pos, std::size_t n ) const
{
std::size_t String::find_last_of( const char* s, std::size_t pos, std::size_t n ) const {
return find_last_of( String( s ), pos );
}
std::size_t String::find_last_of ( const char* s, std::size_t pos ) const
{
std::size_t String::find_last_of( const char* s, std::size_t pos ) const {
return find_last_of( String( s ), pos );
}
std::size_t String::find_last_of ( StringBaseType c, std::size_t pos) const
{
std::size_t String::find_last_of( StringBaseType c, std::size_t pos ) const {
return mString.find_last_of( c, pos );
}
std::size_t String::find_first_not_of ( const String& str, std::size_t pos ) const
{
std::size_t String::find_first_not_of( const String& str, std::size_t pos ) const {
return mString.find_first_not_of( str.mString, pos );
}
std::size_t String::find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const
{
std::size_t String::find_first_not_of( const char* s, std::size_t pos, std::size_t n ) const {
return find_first_not_of( String( s ), pos );
}
std::size_t String::find_first_not_of ( const char* s, std::size_t pos ) const
{
std::size_t String::find_first_not_of( const char* s, std::size_t pos ) const {
return find_first_not_of( String( s ), pos );
}
std::size_t String::find_first_not_of ( StringBaseType c, std::size_t pos ) const
{
std::size_t String::find_first_not_of( StringBaseType c, std::size_t pos ) const {
return mString.find_first_not_of( c, pos );
}
std::size_t String::find_last_not_of ( const String& str, std::size_t pos ) const
{
std::size_t String::find_last_not_of( const String& str, std::size_t pos ) const {
return mString.find_last_not_of( str.mString, pos );
}
std::size_t String::find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const
{
std::size_t String::find_last_not_of( const char* s, std::size_t pos, std::size_t n ) const {
return find_last_not_of( String( s ), pos );
}
std::size_t String::find_last_not_of ( const char* s, std::size_t pos ) const
{
std::size_t String::find_last_not_of( const char* s, std::size_t pos ) const {
return find_last_not_of( String( s ), pos );
}
std::size_t String::find_last_not_of ( StringBaseType c, std::size_t pos ) const
{
std::size_t String::find_last_not_of( StringBaseType c, std::size_t pos ) const {
return mString.find_last_not_of( c, pos );
}
bool operator ==(const String& left, const String& right)
{
bool operator==( const String& left, const String& right ) {
return left.mString == right.mString;
}
bool operator !=(const String& left, const String& right)
{
return !(left == right);
bool operator!=( const String& left, const String& right ) {
return !( left == right );
}
bool operator <(const String& left, const String& right)
{
bool operator<( const String& left, const String& right ) {
return left.mString < right.mString;
}
bool operator >(const String& left, const String& right)
{
bool operator>( const String& left, const String& right ) {
return right < left;
}
bool operator <=(const String& left, const String& right)
{
return !(right < left);
bool operator<=( const String& left, const String& right ) {
return !( right < left );
}
bool operator >=(const String& left, const String& right)
{
return !(left < right);
bool operator>=( const String& left, const String& right ) {
return !( left < right );
}
String operator +(const String& left, const String& right)
{
String operator+( const String& left, const String& right ) {
String string = left;
string += right;
return string;
}
}
} // namespace efsw

View File

@@ -1,39 +1,39 @@
/** NOTE:
* This code is based on the Utf implementation from SFML2. License zlib/png ( http://www.sfml-dev.org/license.php )
* The class was modified to fit efsw own needs. This is not the original implementation from SFML2.
* Functions and methods are the same that in std::string to facilitate portability.
**/
* This code is based on the Utf implementation from SFML2. License zlib/png (
*http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not
*the original implementation from SFML2. Functions and methods are the same that in std::string to
*facilitate portability.
**/
#ifndef EFSW_STRING_HPP
#define EFSW_STRING_HPP
#include <efsw/base.hpp>
#include <locale>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <efsw/base.hpp>
#include <fstream>
#include <iostream>
#include <locale>
#include <sstream>
#include <string>
#include <vector>
namespace efsw {
/** @brief Utility string class that automatically handles conversions between types and encodings **/
class String
{
public :
typedef Uint32 StringBaseType;
typedef std::basic_string<StringBaseType> StringType;
typedef StringType::iterator Iterator; //! Iterator type
typedef StringType::const_iterator ConstIterator; //! Constant iterator type
typedef StringType::reverse_iterator ReverseIterator; //! Reverse Iterator type
typedef StringType::const_reverse_iterator ConstReverseIterator; //! Constant iterator type
/** @brief Utility string class that automatically handles conversions between types and encodings
* **/
class String {
public:
typedef Uint32 StringBaseType;
typedef std::basic_string<StringBaseType> StringType;
typedef StringType::iterator Iterator; //! Iterator type
typedef StringType::const_iterator ConstIterator; //! Constant iterator type
typedef StringType::reverse_iterator ReverseIterator; //! Reverse Iterator type
typedef StringType::const_reverse_iterator ConstReverseIterator; //! Constant iterator type
static const std::size_t InvalidPos; ///< Represents an invalid position in the string
template <class T>
static std::string toStr(const T& i) {
template <class T> static std::string toStr( const T& i ) {
std::ostringstream ss;
ss << i;
return ss.str();
@@ -41,23 +41,27 @@ class String
/** Converts from a string to type */
template <class T>
static bool fromString(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec ) {
std::istringstream iss(s);
return !(iss >> f >> t).fail();
static bool fromString( T& t, const std::string& s,
std::ios_base& ( *f )( std::ios_base& ) = std::dec ) {
std::istringstream iss( s );
return !( iss >> f >> t ).fail();
}
/** Converts from a String to type */
template <class T>
static bool fromString(T& t, const String& s, std::ios_base& (*f)(std::ios_base&) = std::dec ) {
static bool fromString( T& t, const String& s,
std::ios_base& ( *f )( std::ios_base& ) = std::dec ) {
std::istringstream iss( s.toUtf8() );
return !(iss >> f >> t).fail();
return !( iss >> f >> t ).fail();
}
/** Split a string and hold it on a vector */
static std::vector < std::string > split( const std::string& str, const char& splitchar, const bool& pushEmptyString = false );
static std::vector<std::string> split( const std::string& str, const char& splitchar,
const bool& pushEmptyString = false );
/** Split a string and hold it on a vector */
static std::vector < String > split( const String& str, const Uint32& splitchar, const bool& pushEmptyString = false );
static std::vector<String> split( const String& str, const Uint32& splitchar,
const bool& pushEmptyString = false );
/** Determine if a string starts with the string passed
** @param start The substring expected to start
@@ -149,7 +153,6 @@ class String
**/
String( const StringType& utf32String );
/** @brief Copy constructor
** @param str Instance to copy
**/
@@ -196,17 +199,17 @@ class String
** @param right Instance to assign
** @return Reference to self
**/
String& operator =(const String& right);
String& operator=( const String& right );
String& operator =( const StringBaseType& right );
String& operator=( const StringBaseType& right );
/** @brief Overload of += operator to append an UTF-32 string
** @param right String to append
** @return Reference to self
**/
String& operator +=(const String& right);
String& operator+=( const String& right );
String& operator +=( const StringBaseType& right );
String& operator+=( const StringBaseType& right );
/** @brief Overload of [] operator to access a character by its position
** This function provides read-only access to characters.
@@ -214,7 +217,7 @@ class String
** @param index Index of the character to get
** @return Character at position \a index
**/
StringBaseType operator [](std::size_t index) const;
StringBaseType operator[]( std::size_t index ) const;
/** @brief Overload of [] operator to access a character by its position
** This function provides read and write access to characters.
@@ -223,14 +226,15 @@ class String
** @return Reference to the character at position \a index
**/
StringBaseType& operator [](std::size_t index);
StringBaseType& operator[]( std::size_t index );
/** @brief Get character in string
** Performs a range check, throwing an exception of type out_of_range in case that pos is not an actual position in the string.
** Performs a range check, throwing an exception of type out_of_range in case that pos is not an
*actual position in the string.
** @return The character at position pos in the string.
*/
StringBaseType at( std::size_t index ) const;
/** @brief clear the string
** This function removes all the characters from the string.
** @see empty, erase
@@ -242,7 +246,7 @@ class String
** @see empty
**/
std::size_t size() const;
/** @see size() */
std::size_t length() const;
@@ -258,8 +262,7 @@ class String
** @param position Position of the first character to erase
** @param count Number of characters to erase
**/
void erase(std::size_t position, std::size_t count = 1);
void erase( std::size_t position, std::size_t count = 1 );
/** @brief Insert one or more characters into the string
** This function inserts the characters of \a str
@@ -267,23 +270,22 @@ class String
** @param position Position of insertion
** @param str Characters to insert
**/
String& insert(std::size_t position, const String& str);
String& insert( std::size_t position, const String& str );
String& insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n );
String& insert ( std::size_t pos1, const char* s, std::size_t n );
String& insert( std::size_t pos1, const char* s, std::size_t n );
String& insert ( std::size_t pos1, const char* s );
String& insert( std::size_t pos1, const char* s );
String& insert ( std::size_t pos1, size_t n, char c );
String& insert( std::size_t pos1, size_t n, char c );
Iterator insert ( Iterator p, char c );
Iterator insert( Iterator p, char c );
void insert ( Iterator p, std::size_t n, char c );
void insert( Iterator p, std::size_t n, char c );
template<class InputIterator>
void insert ( Iterator p, InputIterator first, InputIterator last )
{
template <class InputIterator>
void insert( Iterator p, InputIterator first, InputIterator last ) {
mString.insert( p, first, last );
}
@@ -296,11 +298,11 @@ class String
**/
std::size_t find( const String& str, std::size_t start = 0 ) const;
std::size_t find ( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find ( const char* s, std::size_t pos = 0 ) const;
std::size_t find( const char* s, std::size_t pos = 0 ) const;
std::size_t find ( char c, std::size_t pos = 0 ) const;
std::size_t find( char c, std::size_t pos = 0 ) const;
/** @brief Get a pointer to the C-style array of characters
** This functions provides a read-only access to a
@@ -310,11 +312,14 @@ class String
** @return Read-only pointer to the array of characters
**/
const StringBaseType* c_str() const;
/** @brief Get string data
** Notice that no terminating null character is appended (see member c_str for such a functionality).
** The returned array points to an internal location which should not be modified directly in the program.
** Its contents are guaranteed to remain unchanged only until the next call to a non-constant member function of the string object.
** Notice that no terminating null character is appended (see member c_str for such a
*functionality).
** The returned array points to an internal location which should not be modified directly in
*the program.
** Its contents are guaranteed to remain unchanged only until the next call to a non-constant
*member function of the string object.
** @return Pointer to an internal array containing the same content as the string.
**/
const StringBaseType* data() const;
@@ -348,7 +353,7 @@ class String
** @see begin
**/
ConstIterator end() const;
/** @brief Return an reverse iterator to the beginning of the string
** @return Read-write reverse iterator to the beginning of the string characters
** @see end
@@ -370,7 +375,6 @@ class String
**/
ReverseIterator rend();
/** @brief Return an reverse iterator to the beginning of the string
** The end reverse iterator refers to 1 position past the last character;
** thus it represents an invalid character and should never be
@@ -379,147 +383,145 @@ class String
** @see begin
**/
ConstReverseIterator rend() const;
/** @brief Resize String */
void resize ( std::size_t n, StringBaseType c );
void resize( std::size_t n, StringBaseType c );
/** @brief Resize String */
void resize ( std::size_t n );
void resize( std::size_t n );
/** @return Maximum size of string */
std::size_t max_size() const;
/** @brief Request a change in capacity */
void reserve ( size_t res_arg=0 );
void reserve( size_t res_arg = 0 );
/** @return Size of allocated storage */
std::size_t capacity() const;
/** @brief Append character to string */
void push_back( StringBaseType c );
/** @brief Swap contents with another string */
void swap ( String& str );
String& assign ( const String& str );
void swap( String& str );
String& assign ( const String& str, std::size_t pos, std::size_t n );
String& assign( const String& str );
String& assign ( const char* s, std::size_t n );
String& assign( const String& str, std::size_t pos, std::size_t n );
String& assign ( const char* s );
String& assign( const char* s, std::size_t n );
String& assign ( std::size_t n, char c );
String& assign( const char* s );
template <class InputIterator>
String& assign ( InputIterator first, InputIterator last )
{
String& assign( std::size_t n, char c );
template <class InputIterator> String& assign( InputIterator first, InputIterator last ) {
mString.assign( first, last );
return *this;
}
String& append ( const String& str );
String& append( const String& str );
String& append ( const String& str, std::size_t pos, std::size_t n );
String& append( const String& str, std::size_t pos, std::size_t n );
String& append ( const char* s, std::size_t n );
String& append( const char* s, std::size_t n );
String& append ( const char* s );
String& append( const char* s );
String& append ( std::size_t n, char c );
String& append( std::size_t n, char c );
String& append ( std::size_t n, StringBaseType c );
String& append( std::size_t n, StringBaseType c );
template <class InputIterator>
String& append ( InputIterator first, InputIterator last )
{
template <class InputIterator> String& append( InputIterator first, InputIterator last ) {
mString.append( first, last );
return *this;
}
String& replace ( std::size_t pos1, std::size_t n1, const String& str );
String& replace( std::size_t pos1, std::size_t n1, const String& str );
String& replace ( Iterator i1, Iterator i2, const String& str );
String& replace( Iterator i1, Iterator i2, const String& str );
String& replace ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 );
String& replace( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2,
std::size_t n2 );
String& replace ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 );
String& replace( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 );
String& replace ( Iterator i1, Iterator i2, const char* s, std::size_t n2 );
String& replace( Iterator i1, Iterator i2, const char* s, std::size_t n2 );
String& replace ( std::size_t pos1, std::size_t n1, const char* s );
String& replace( std::size_t pos1, std::size_t n1, const char* s );
String& replace ( Iterator i1, Iterator i2, const char* s );
String& replace( Iterator i1, Iterator i2, const char* s );
String& replace ( std::size_t pos1, std::size_t n1, std::size_t n2, char c );
String& replace( std::size_t pos1, std::size_t n1, std::size_t n2, char c );
String& replace ( Iterator i1, Iterator i2, std::size_t n2, char c );
String& replace( Iterator i1, Iterator i2, std::size_t n2, char c );
template<class InputIterator>
String& replace ( Iterator i1, Iterator i2, InputIterator j1, InputIterator j2 )
{
template <class InputIterator>
String& replace( Iterator i1, Iterator i2, InputIterator j1, InputIterator j2 ) {
mString.replace( i1, i2, j1, j2 );
return *this;
}
std::size_t rfind ( const String& str, std::size_t pos = StringType::npos ) const;
std::size_t rfind( const String& str, std::size_t pos = StringType::npos ) const;
std::size_t rfind ( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t rfind( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t rfind ( const char* s, std::size_t pos = StringType::npos ) const;
std::size_t rfind( const char* s, std::size_t pos = StringType::npos ) const;
std::size_t rfind ( char c, std::size_t pos = StringType::npos ) const;
std::size_t rfind( char c, std::size_t pos = StringType::npos ) const;
String substr ( std::size_t pos = 0, std::size_t n = StringType::npos ) const;
String substr( std::size_t pos = 0, std::size_t n = StringType::npos ) const;
std::size_t copy ( StringBaseType* s, std::size_t n, std::size_t pos = 0 ) const;
std::size_t copy( StringBaseType* s, std::size_t n, std::size_t pos = 0 ) const;
int compare ( const String& str ) const;
int compare( const String& str ) const;
int compare ( const char* s ) const;
int compare( const char* s ) const;
int compare ( std::size_t pos1, std::size_t n1, const String& str ) const;
int compare( std::size_t pos1, std::size_t n1, const String& str ) const;
int compare ( std::size_t pos1, std::size_t n1, const char* s) const;
int compare( std::size_t pos1, std::size_t n1, const char* s ) const;
int compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const;
int compare( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2,
std::size_t n2 ) const;
int compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const;
int compare( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ) const;
std::size_t find_first_of ( const String& str, std::size_t pos = 0 ) const;
std::size_t find_first_of( const String& str, std::size_t pos = 0 ) const;
std::size_t find_first_of ( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find_first_of( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find_first_of ( const char* s, std::size_t pos = 0 ) const;
std::size_t find_first_of( const char* s, std::size_t pos = 0 ) const;
std::size_t find_first_of ( StringBaseType c, std::size_t pos = 0 ) const;
std::size_t find_first_of( StringBaseType c, std::size_t pos = 0 ) const;
std::size_t find_last_of ( const String& str, std::size_t pos = StringType::npos ) const;
std::size_t find_last_of( const String& str, std::size_t pos = StringType::npos ) const;
std::size_t find_last_of ( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find_last_of( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find_last_of ( const char* s, std::size_t pos = StringType::npos ) const;
std::size_t find_last_of( const char* s, std::size_t pos = StringType::npos ) const;
std::size_t find_last_of ( StringBaseType c, std::size_t pos = StringType::npos ) const;
std::size_t find_last_of( StringBaseType c, std::size_t pos = StringType::npos ) const;
std::size_t find_first_not_of ( const String& str, std::size_t pos = 0 ) const;
std::size_t find_first_not_of( const String& str, std::size_t pos = 0 ) const;
std::size_t find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find_first_not_of( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find_first_not_of ( const char* s, std::size_t pos = 0 ) const;
std::size_t find_first_not_of( const char* s, std::size_t pos = 0 ) const;
std::size_t find_first_not_of ( StringBaseType c, std::size_t pos = 0 ) const;
std::size_t find_first_not_of( StringBaseType c, std::size_t pos = 0 ) const;
std::size_t find_last_not_of ( const String& str, std::size_t pos = StringType::npos ) const;
std::size_t find_last_not_of( const String& str, std::size_t pos = StringType::npos ) const;
std::size_t find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find_last_not_of( const char* s, std::size_t pos, std::size_t n ) const;
std::size_t find_last_not_of ( const char* s, std::size_t pos = StringType::npos ) const;
std::size_t find_last_not_of( const char* s, std::size_t pos = StringType::npos ) const;
std::size_t find_last_not_of ( StringBaseType c, std::size_t pos = StringType::npos ) const;
private :
friend bool operator ==(const String& left, const String& right);
friend bool operator <(const String& left, const String& right);
std::size_t find_last_not_of( StringBaseType c, std::size_t pos = StringType::npos ) const;
private:
friend bool operator==( const String& left, const String& right );
friend bool operator<( const String& left, const String& right );
StringType mString; ///< Internal string of UTF-32 characters
};
@@ -530,7 +532,7 @@ private :
** @param right Right operand (a string)
** @return True if both strings are equal
**/
bool operator ==(const String& left, const String& right);
bool operator==( const String& left, const String& right );
/** @relates String
** @brief Overload of != operator to compare two UTF-32 strings
@@ -538,7 +540,7 @@ private :
** @param right Right operand (a string)
** @return True if both strings are different
**/
bool operator !=(const String& left, const String& right);
bool operator!=( const String& left, const String& right );
/** @relates String
** @brief Overload of < operator to compare two UTF-32 strings
@@ -546,7 +548,7 @@ private :
** @param right Right operand (a string)
** @return True if \a left is alphabetically lesser than \a right
**/
bool operator <(const String& left, const String& right);
bool operator<( const String& left, const String& right );
/** @relates String
** @brief Overload of > operator to compare two UTF-32 strings
@@ -554,7 +556,7 @@ private :
** @param right Right operand (a string)
** @return True if \a left is alphabetically greater than \a right
**/
bool operator >(const String& left, const String& right);
bool operator>( const String& left, const String& right );
/** @relates String
** @brief Overload of <= operator to compare two UTF-32 strings
@@ -562,7 +564,7 @@ private :
** @param right Right operand (a string)
** @return True if \a left is alphabetically lesser or equal than \a right
**/
bool operator <=(const String& left, const String& right);
bool operator<=( const String& left, const String& right );
/** @relates String
** @brief Overload of >= operator to compare two UTF-32 strings
@@ -570,7 +572,7 @@ private :
** @param right Right operand (a string)
** @return True if \a left is alphabetically greater or equal than \a right
**/
bool operator >=(const String& left, const String& right);
bool operator>=( const String& left, const String& right );
/** @relates String
** @brief Overload of binary + operator to concatenate two strings
@@ -578,9 +580,9 @@ private :
** @param right Right operand (a string)
** @return Concatenated string
**/
String operator +( const String& left, const String& right );
String operator+( const String& left, const String& right );
}
} // namespace efsw
#endif

View File

@@ -3,24 +3,20 @@
namespace efsw {
void System::sleep( const unsigned long& ms )
{
void System::sleep( const unsigned long& ms ) {
Platform::System::sleep( ms );
}
std::string System::getProcessPath()
{
std::string System::getProcessPath() {
return Platform::System::getProcessPath();
}
void System::maxFD()
{
void System::maxFD() {
Platform::System::maxFD();
}
Uint64 System::getMaxFD()
{
Uint64 System::getMaxFD() {
return Platform::System::getMaxFD();
}
}
} // namespace efsw

View File

@@ -5,22 +5,21 @@
namespace efsw {
class System
{
public:
/// Sleep for x milliseconds
static void sleep( const unsigned long& ms );
class System {
public:
/// Sleep for x milliseconds
static void sleep( const unsigned long& ms );
/// @return The process binary path
static std::string getProcessPath();
/// @return The process binary path
static std::string getProcessPath();
/// Maximize the number of file descriptors allowed per process in the current OS
static void maxFD();
/// Maximize the number of file descriptors allowed per process in the current OS
static void maxFD();
/// @return The number of supported file descriptors for the process
static Uint64 getMaxFD();
/// @return The number of supported file descriptors for the process
static Uint64 getMaxFD();
};
}
} // namespace efsw
#endif

View File

@@ -3,49 +3,39 @@
namespace efsw {
Thread::Thread() :
mThreadImpl(NULL),
mEntryPoint(NULL)
{
}
Thread::Thread() : mThreadImpl( NULL ), mEntryPoint( NULL ) {}
Thread::~Thread()
{
Thread::~Thread() {
wait();
efSAFE_DELETE( mEntryPoint );
}
void Thread::launch()
{
void Thread::launch() {
wait();
mThreadImpl = new Platform::ThreadImpl( this );
}
void Thread::wait()
{
if ( mThreadImpl )
{
void Thread::wait() {
if ( mThreadImpl ) {
mThreadImpl->wait();
efSAFE_DELETE( mThreadImpl );
}
}
void Thread::terminate()
{
if ( mThreadImpl )
{
void Thread::terminate() {
if ( mThreadImpl ) {
mThreadImpl->terminate();
efSAFE_DELETE( mThreadImpl );
}
}
void Thread::run()
{
mEntryPoint->run();
void Thread::run() {
if ( mEntryPoint )
mEntryPoint->run();
}
}
} // namespace efsw

View File

@@ -5,107 +5,96 @@
namespace efsw {
namespace Platform { class ThreadImpl; }
namespace Private { struct ThreadFunc; }
namespace Platform {
class ThreadImpl;
}
namespace Private {
struct ThreadFunc;
}
/** @brief Thread manager class */
class Thread {
public:
typedef void (*FuncType)(void*);
public:
typedef void ( *FuncType )( void* );
template <typename F>
Thread( F function );
template <typename F> Thread( F function );
template <typename F, typename A>
Thread( F function, A argument );
template <typename F, typename A> Thread( F function, A argument );
template <typename C>
Thread( void(C::*function)(), C* object );
template <typename C> Thread( void ( C::*function )(), C* object );
virtual ~Thread();
virtual ~Thread();
/** Launch the thread */
virtual void launch();
/** Launch the thread */
virtual void launch();
/** Wait the thread until end */
void wait();
/** Wait the thread until end */
void wait();
/** Terminate the thread */
void terminate();
protected:
Thread();
private:
friend class Platform::ThreadImpl;
/** Terminate the thread */
void terminate();
/** The virtual function to run in the thread */
virtual void run();
protected:
Thread();
Platform::ThreadImpl * mThreadImpl; ///< OS-specific implementation of the thread
Private::ThreadFunc * mEntryPoint; ///< Abstraction of the function to run
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
};
//! NOTE: Taken from SFML2 threads
namespace Private {
// Base class for abstract thread functions
struct ThreadFunc
{
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();}
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);}
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)();
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) )
{
}
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) )
{
}
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) )
{
}
Thread::Thread( void ( C::*function )(), C* object ) :
mThreadImpl( NULL ), mEntryPoint( new Private::ThreadMemberFunc<C>( function, object ) ) {}
}
} // namespace efsw
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,20 +2,9 @@
namespace efsw {
Watcher::Watcher() :
ID(0),
Directory(""),
Listener(NULL),
Recursive(false)
{
}
Watcher::Watcher() : ID( 0 ), Directory( "" ), Listener( NULL ), Recursive( false ) {}
Watcher::Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ) :
ID( id ),
Directory( directory ),
Listener( listener ),
Recursive( recursive )
{
}
Watcher::Watcher( WatchID id, std::string directory, FileWatchListener* listener, bool recursive ) :
ID( id ), Directory( directory ), Listener( listener ), Recursive( recursive ) {}
}
} // namespace efsw

View File

@@ -7,24 +7,23 @@
namespace efsw {
/** @brief Base Watcher class */
class Watcher
{
public:
Watcher();
class Watcher {
public:
Watcher();
Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive );
Watcher( WatchID id, std::string directory, FileWatchListener* listener, bool recursive );
virtual ~Watcher() {}
virtual ~Watcher() {}
virtual void watch() {}
virtual void watch() {}
WatchID ID;
std::string Directory;
FileWatchListener * Listener;
bool Recursive;
std::string OldFileName;
WatchID ID;
std::string Directory;
FileWatchListener* Listener;
bool Recursive;
std::string OldFileName;
};
}
} // namespace efsw
#endif

View File

@@ -1,39 +1,25 @@
#include <efsw/WatcherFSEvents.hpp>
#include <efsw/FileWatcherFSEvents.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/Debug.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/FileWatcherFSEvents.hpp>
#include <efsw/WatcherFSEvents.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
namespace efsw {
WatcherFSEvents::WatcherFSEvents() :
Watcher(),
FWatcher( NULL ),
FSStream( NULL ),
WatcherGen( NULL ),
initializedAsync( false )
{
}
Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ) {}
WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent ) :
WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener,
bool recursive, WatcherFSEvents* parent ) :
Watcher( id, directory, listener, recursive ),
FWatcher( NULL ),
FSStream( NULL ),
WatcherGen( NULL ),
initializedAsync( false )
{
}
WatcherFSEvents::~WatcherFSEvents()
{
if ( NULL != FSStream )
{
if ( initializedAsync )
{
FSEventStreamStop( FSStream );
}
WatcherGen( NULL ) {}
WatcherFSEvents::~WatcherFSEvents() {
if ( NULL != FSStream ) {
FSEventStreamStop( FSStream );
FSEventStreamInvalidate( FSStream );
FSEventStreamRelease( FSStream );
}
@@ -41,22 +27,19 @@ WatcherFSEvents::~WatcherFSEvents()
efSAFE_DELETE( WatcherGen );
}
void WatcherFSEvents::init()
{
CFStringRef CFDirectory = CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 );
CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void **)&CFDirectory, 1, NULL );
void WatcherFSEvents::init() {
CFStringRef CFDirectory =
CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 );
CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void**)&CFDirectory, 1, NULL );
Uint32 streamFlags = kFSEventStreamCreateFlagNone;
if ( FileWatcherFSEvents::isGranular() )
{
streamFlags = efswFSEventStreamCreateFlagFileEvents;
if ( FileWatcherFSEvents::isGranular() ) {
streamFlags = efswFSEventStreamCreateFlagFileEvents | efswFSEventStreamCreateFlagNoDefer;
} else {
WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive );
}
else
{
WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher, Recursive );
}
FSEventStreamContext ctx;
/* Initialize context */
ctx.version = 0;
@@ -65,200 +48,161 @@ void WatcherFSEvents::init()
ctx.release = NULL;
ctx.copyDescription = NULL;
FSStream = FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags );
dispatch_queue_t queue = dispatch_queue_create(NULL, NULL);
FWatcher->mNeedInit.push_back( this );
FSStream =
FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx,
CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0., streamFlags );
FSEventStreamSetDispatchQueue(FSStream, queue);
FSEventStreamStart( FSStream );
CFRelease( CFDirectoryArray );
CFRelease( CFDirectory );
}
void WatcherFSEvents::initAsync()
{
FSEventStreamScheduleWithRunLoop( FSStream, FWatcher->mRunLoopRef, kCFRunLoopDefaultMode );
FSEventStreamStart( FSStream );
initializedAsync = true;
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 ) );
}
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, oldFilename );
}
void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, std::string& filePath )
{
if ( flags & efswFSEventStreamEventFlagItemCreated )
{
if ( FileInfo::exists( path ) )
{
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 );
}
}
if ( flags & efswFSEventsModified )
{
if ( flags & efswFSEventsModified ) {
sendFileAction( ID, dirPath, filePath, Actions::Modified );
}
if ( flags & efswFSEventStreamEventFlagItemRemoved )
{
// Since i don't know the order, at least i try to keep the data consistent with the real state
if ( !FileInfo::exists( path ) )
{
if ( flags & efswFSEventStreamEventFlagItemRemoved ) {
// 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 );
}
}
}
void WatcherFSEvents::handleActions( std::vector<FSEvent>& events )
{
void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
size_t esize = events.size();
for ( size_t i = 0; i < esize; i++ )
{
for ( size_t i = 0; i < esize; i++ ) {
FSEvent& event = events[i];
if ( event.Flags & ( kFSEventStreamEventFlagUserDropped |
kFSEventStreamEventFlagKernelDropped |
kFSEventStreamEventFlagEventIdsWrapped |
kFSEventStreamEventFlagHistoryDone |
kFSEventStreamEventFlagMount |
kFSEventStreamEventFlagUnmount |
kFSEventStreamEventFlagRootChanged ) )
{
if ( event.Flags &
( kFSEventStreamEventFlagUserDropped | kFSEventStreamEventFlagKernelDropped |
kFSEventStreamEventFlagEventIdsWrapped | kFSEventStreamEventFlagHistoryDone |
kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount |
kFSEventStreamEventFlagRootChanged ) ) {
continue;
}
if ( !Recursive )
{
if ( !Recursive ) {
/** In case that is not recursive the watcher, ignore the events from subfolders */
if ( event.Path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 )
{
if ( event.Path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 ) {
continue;
}
}
if ( FileWatcherFSEvents::isGranular() )
{
if ( FileWatcherFSEvents::isGranular() ) {
std::string dirPath( FileSystem::pathRemoveFileName( event.Path ) );
std::string filePath( FileSystem::fileNameFromPath( event.Path ) );
if ( event.Flags & ( efswFSEventStreamEventFlagItemCreated |
efswFSEventStreamEventFlagItemRemoved |
efswFSEventStreamEventFlagItemRenamed )
)
{
if ( dirPath != Directory )
{
if ( event.Flags &
( efswFSEventStreamEventFlagItemCreated | efswFSEventStreamEventFlagItemRemoved |
efswFSEventStreamEventFlagItemRenamed ) ) {
if ( dirPath != Directory ) {
DirsChanged.insert( dirPath );
}
}
// This is a mess. But it's FSEvents faults, because shrinks events from the same file in one single event ( so there's no order for them )
// For example a file could have 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", path.c_str(), event.Flags );
// This is a mess. But it's FSEvents faults, because shrinks events from the same file
// in one single event ( so there's no order for them ) For example a file could have
// 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 );
if ( event.Flags & efswFSEventStreamEventFlagItemRenamed )
{
if ( ( i + 1 < esize ) &&
( events[ i + 1 ].Flags & efswFSEventStreamEventFlagItemRenamed ) &&
( events[ i + 1 ].Id == event.Id + 1 )
)
{
FSEvent& nEvent = events[ i + 1 ];
if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) {
if ( ( i + 1 < esize ) &&
( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) &&
( events[i + 1].Id == event.Id + 1 ) ) {
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 ) )
{
sendFileAction( ID, dirPath, newFilepath, Actions::Moved, filePath );
if ( event.Path != nEvent.Path ) {
if ( dirPath == newDir ) {
if ( !FileInfo::exists( event.Path ) ) {
sendFileAction( ID, dirPath, newFilepath, Actions::Moved,
filePath );
} else {
sendFileAction( ID, dirPath, filePath, Actions::Moved,
newFilepath );
}
else
{
sendFileAction( ID, dirPath, filePath, Actions::Moved, newFilepath );
}
}
else
{
} else {
sendFileAction( ID, dirPath, filePath, Actions::Delete );
sendFileAction( ID, newDir, newFilepath, Actions::Add );
if ( nEvent.Flags & efswFSEventsModified )
{
if ( nEvent.Flags & efswFSEventsModified ) {
sendFileAction( ID, newDir, newFilepath, Actions::Modified );
}
}
}
else
{
} else {
handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath );
}
if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated |
efswFSEventStreamEventFlagItemRemoved |
efswFSEventStreamEventFlagItemRenamed )
)
{
if ( newDir != Directory )
{
if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated |
efswFSEventStreamEventFlagItemRemoved |
efswFSEventStreamEventFlagItemRenamed ) ) {
if ( newDir != Directory ) {
DirsChanged.insert( newDir );
}
}
// Skip the renamed file
i++;
}
else if ( FileInfo::exists( event.Path ) )
{
} else if ( FileInfo::exists( event.Path ) ) {
sendFileAction( ID, dirPath, filePath, Actions::Add );
if ( event.Flags & efswFSEventsModified )
{
if ( event.Flags & efswFSEventsModified ) {
sendFileAction( ID, dirPath, filePath, Actions::Modified );
}
}
else
{
} else {
sendFileAction( ID, dirPath, filePath, Actions::Delete );
}
}
else
{
} else {
handleAddModDel( event.Flags, event.Path, dirPath, filePath );
}
}
else
{
} else {
efDEBUG( "Directory: %s changed\n", event.Path.c_str() );
DirsChanged.insert( event.Path );
}
}
}
void WatcherFSEvents::process()
{
void WatcherFSEvents::process() {
std::set<std::string>::iterator it = DirsChanged.begin();
for ( ; it != DirsChanged.end(); it++ )
{
if ( !FileWatcherFSEvents::isGranular() )
{
WatcherGen->watchDir( (*it) );
}
else
{
sendFileAction( ID, FileSystem::pathRemoveFileName( (*it) ), FileSystem::fileNameFromPath( (*it) ), Actions::Modified );
for ( ; it != DirsChanged.end(); it++ ) {
if ( !FileWatcherFSEvents::isGranular() ) {
WatcherGen->watchDir( ( *it ) );
} else {
sendFileAction( ID, FileSystem::pathRemoveFileName( ( *it ) ),
FileSystem::fileNameFromPath( ( *it ) ), Actions::Modified );
}
}
DirsChanged.clear();
}
}
} // namespace efsw
#endif

View File

@@ -5,10 +5,10 @@
#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
#include <efsw/WatcherGeneric.hpp>
#include <efsw/FileInfo.hpp>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <efsw/FileInfo.hpp>
#include <efsw/WatcherGeneric.hpp>
#include <set>
#include <vector>
@@ -16,54 +16,46 @@ namespace efsw {
class FileWatcherFSEvents;
class FSEvent
{
public:
FSEvent( std::string path, long flags, Uint64 id ) :
Path( path ),
Flags( flags ),
Id ( id )
{
}
class FSEvent {
public:
FSEvent( std::string path, long flags, Uint64 id ) : Path( path ), Flags( flags ), Id( id ) {}
std::string Path;
long Flags;
Uint64 Id;
std::string Path;
long Flags;
Uint64 Id;
};
class WatcherFSEvents : public Watcher
{
public:
WatcherFSEvents();
WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent = NULL );
~WatcherFSEvents();
class WatcherFSEvents : public Watcher {
public:
WatcherFSEvents();
void init();
WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, bool recursive,
WatcherFSEvents* parent = NULL );
void initAsync();
~WatcherFSEvents();
void handleActions( std::vector<FSEvent> & events );
void init();
void process();
void handleActions( std::vector<FSEvent>& events );
FileWatcherFSEvents * FWatcher;
void process();
FSEventStreamRef FSStream;
protected:
void handleAddModDel( const Uint32 &flags, const std::string &path, std::string &dirPath, std::string &filePath );
Atomic<FileWatcherFSEvents*> FWatcher;
FSEventStreamRef FSStream;
WatcherGeneric * WatcherGen;
protected:
void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath,
std::string& filePath );
bool initializedAsync;
WatcherGeneric* WatcherGen;
std::set<std::string> DirsChanged;
std::set<std::string> DirsChanged;
void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" );
void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename,
Action action, std::string oldFilename = "" );
};
}
} // namespace efsw
#endif

View File

@@ -1,15 +1,12 @@
#include <efsw/WatcherGeneric.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/DirWatcherGeneric.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/WatcherGeneric.hpp>
namespace efsw
{
namespace efsw {
WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ) :
Watcher( id, directory, fwl, recursive ),
WatcherImpl( fw ),
DirWatch( NULL )
{
WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener* fwl,
FileWatcherImpl* fw, bool recursive ) :
Watcher( id, directory, fwl, recursive ), WatcherImpl( fw ), DirWatch( NULL ) {
FileSystem::dirAddSlashAtEnd( Directory );
DirWatch = new DirWatcherGeneric( NULL, this, directory, recursive, false );
@@ -17,24 +14,20 @@ WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWa
DirWatch->addChilds( false );
}
WatcherGeneric::~WatcherGeneric()
{
WatcherGeneric::~WatcherGeneric() {
efSAFE_DELETE( DirWatch );
}
void WatcherGeneric::watch()
{
void WatcherGeneric::watch() {
DirWatch->watch();
}
void WatcherGeneric::watchDir( std::string dir )
{
void WatcherGeneric::watchDir( std::string dir ) {
DirWatch->watchDir( dir );
}
bool WatcherGeneric::pathInWatches( std::string path )
{
bool WatcherGeneric::pathInWatches( std::string path ) {
return DirWatch->pathInWatches( path );
}
}
} // namespace efsw

View File

@@ -3,28 +3,27 @@
#include <efsw/FileWatcherImpl.hpp>
namespace efsw
{
namespace efsw {
class DirWatcherGeneric;
class WatcherGeneric : public Watcher
{
public:
FileWatcherImpl * WatcherImpl;
DirWatcherGeneric * DirWatch;
class WatcherGeneric : public Watcher {
public:
FileWatcherImpl* WatcherImpl;
DirWatcherGeneric* DirWatch;
WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive );
WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener* fwl,
FileWatcherImpl* fw, bool recursive );
~WatcherGeneric();
~WatcherGeneric();
void watch();
void watch() override;
void watchDir( std::string dir );
void watchDir( std::string dir );
bool pathInWatches( std::string path );
bool pathInWatches( std::string path );
};
}
} // namespace efsw
#endif

View File

@@ -2,27 +2,13 @@
namespace efsw {
WatcherInotify::WatcherInotify() :
Watcher(),
Parent( NULL )
{
}
WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {}
WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent ) :
Watcher( id, directory, listener, recursive ),
Parent( parent ),
DirInfo( directory )
{
}
bool WatcherInotify::inParentTree( WatcherInotify* parent ) {
WatcherInotify* tNext = Parent;
bool WatcherInotify::inParentTree( WatcherInotify * parent )
{
WatcherInotify * tNext = Parent;
while ( NULL != tNext )
{
if ( tNext == parent )
{
while ( NULL != tNext ) {
if ( tNext == parent ) {
return true;
}
@@ -31,5 +17,5 @@ bool WatcherInotify::inParentTree( WatcherInotify * parent )
return false;
}
}
} // namespace efsw

View File

@@ -1,25 +1,23 @@
#ifndef EFSW_WATCHERINOTIFY_HPP
#ifndef EFSW_WATCHERINOTIFY_HPP
#define EFSW_WATCHERINOTIFY_HPP
#include <efsw/FileWatcherImpl.hpp>
#include <efsw/FileInfo.hpp>
#include <efsw/FileWatcherImpl.hpp>
namespace efsw {
class WatcherInotify : public Watcher
{
public:
WatcherInotify();
WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent = NULL );
class WatcherInotify : public Watcher {
public:
WatcherInotify();
bool inParentTree( WatcherInotify * parent );
bool inParentTree( WatcherInotify* parent );
WatcherInotify * Parent;
WatcherInotify* Parent;
WatchID InotifyID;
FileInfo DirInfo;
FileInfo DirInfo;
};
}
} // namespace efsw
#endif

View File

@@ -2,38 +2,36 @@
#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <dirent.h>
#include <efsw/Debug.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/FileWatcherKqueue.hpp>
#include <efsw/String.hpp>
#include <efsw/System.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/WatcherGeneric.hpp>
#include <efsw/FileWatcherKqueue.hpp>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#define KEVENT_RESERVE_VALUE (10)
#define KEVENT_RESERVE_VALUE ( 10 )
#ifndef O_EVTONLY
#define O_EVTONLY (O_RDONLY | O_NONBLOCK)
#define O_EVTONLY ( O_RDONLY | O_NONBLOCK )
#endif
namespace efsw {
int comparator(const void* ke1, const void* ke2)
{
const KEvent * kev1 = reinterpret_cast<const KEvent*>( ke1 );
const KEvent * kev2 = reinterpret_cast<const KEvent*>( ke2 );
int comparator( const void* ke1, const void* ke2 ) {
const KEvent* kev1 = reinterpret_cast<const KEvent*>( ke1 );
const KEvent* kev2 = reinterpret_cast<const KEvent*>( ke2 );
if ( NULL != kev2->udata )
{
FileInfo * fi1 = reinterpret_cast<FileInfo*>( kev1->udata );
FileInfo * fi2 = reinterpret_cast<FileInfo*>( kev2->udata );
if ( NULL != kev2->udata ) {
FileInfo* fi1 = reinterpret_cast<FileInfo*>( kev1->udata );
FileInfo* fi2 = reinterpret_cast<FileInfo*>( kev2->udata );
return strcmp( fi1->Filepath.c_str(), fi2->Filepath.c_str() );
}
@@ -41,75 +39,68 @@ int comparator(const void* ke1, const void* ke2)
return 1;
}
WatcherKqueue::WatcherKqueue(WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent ) :
WatcherKqueue::WatcherKqueue( WatchID watchid, const std::string& dirname,
FileWatchListener* listener, bool recursive,
FileWatcherKqueue* watcher, WatcherKqueue* parent ) :
Watcher( watchid, dirname, listener, recursive ),
mLastWatchID(0),
mLastWatchID( 0 ),
mChangeListCount( 0 ),
mKqueue( kqueue() ),
mWatcher( watcher ),
mParent( parent ),
mInitOK( true ),
mErrno(0)
{
if ( -1 == mKqueue )
{
efDEBUG( "kqueue() returned invalid descriptor for directory %s. File descriptors count: %ld\n", Directory.c_str(), mWatcher->mFileDescriptorCount );
mErrno( 0 ) {
if ( -1 == mKqueue ) {
efDEBUG(
"kqueue() returned invalid descriptor for directory %s. File descriptors count: %ld\n",
Directory.c_str(), mWatcher->mFileDescriptorCount );
mInitOK = false;
mErrno = errno;
}
else
{
} else {
mWatcher->addFD();
}
}
WatcherKqueue::~WatcherKqueue()
{
WatcherKqueue::~WatcherKqueue() {
// Remove the childs watchers ( sub-folders watches )
removeAll();
for ( size_t i = 0; i < mChangeListCount; i++ )
{
if ( NULL != mChangeList[i].udata )
{
FileInfo * fi = reinterpret_cast<FileInfo*>( mChangeList[i].udata );
for ( size_t i = 0; i < mChangeListCount; i++ ) {
if ( NULL != mChangeList[i].udata ) {
FileInfo* fi = reinterpret_cast<FileInfo*>( mChangeList[i].udata );
efSAFE_DELETE( fi );
}
}
close( mKqueue );
mWatcher->removeFD();
}
void WatcherKqueue::addAll()
{
if ( -1 == mKqueue )
{
void WatcherKqueue::addAll() {
if ( -1 == mKqueue ) {
return;
}
// scan directory and call addFile(name, false) on each file
FileSystem::dirAddSlashAtEnd( Directory );
efDEBUG( "addAll(): Added folder: %s\n", Directory.c_str());
efDEBUG( "addAll(): Added folder: %s\n", Directory.c_str() );
// add base dir
int fd = open( Directory.c_str(), O_EVTONLY );
if ( -1 == fd )
{
if ( -1 == fd ) {
efDEBUG( "addAll(): Couldn't open folder: %s\n", Directory.c_str() );
if ( EACCES != errno )
{
if ( EACCES != errno ) {
mInitOK = false;
}
mErrno = errno;
return;
}
@@ -119,83 +110,66 @@ void WatcherKqueue::addAll()
mChangeList.resize( KEVENT_RESERVE_VALUE );
// Creates the kevent for the folder
EV_SET(
&mChangeList[0],
fd,
EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_ONESHOT,
NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
0,
0
);
EV_SET( &mChangeList[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, 0, 0 );
mWatcher->addFD();
// Get the files and directories from the directory
FileInfoMap files = FileSystem::filesInfoFromPath( Directory );
for ( FileInfoMap::iterator it = files.begin(); it != files.end(); it++ )
{
for ( FileInfoMap::iterator it = files.begin(); it != files.end(); it++ ) {
FileInfo& fi = it->second;
if ( fi.isRegularFile() )
{
if ( fi.isRegularFile() ) {
// Add the regular files kevent
addFile( fi.Filepath , false );
}
else if ( Recursive && fi.isDirectory() && fi.isReadable() )
{
addFile( fi.Filepath, false );
} else if ( Recursive && fi.isDirectory() && fi.isReadable() ) {
// Create another watcher for the subfolders ( if recursive )
WatchID id = addWatch( fi.Filepath, Listener, Recursive, this );
// If the watcher is not adding the watcher means that the directory was created
if ( id > 0 && !mWatcher->isAddingWatcher() )
{
if ( id > 0 && !mWatcher->isAddingWatcher() ) {
handleFolderAction( fi.Filepath, Actions::Add );
}
}
}
}
void WatcherKqueue::removeAll()
{
void WatcherKqueue::removeAll() {
efDEBUG( "removeAll(): Removing all child watchers\n" );
std::list<WatchID> erase;
std::vector<WatchID> erase;
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
{
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) {
efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() );
erase.push_back( it->second->ID );
}
for ( std::list<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ )
{
for ( std::vector<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) {
removeWatch( *eit );
}
}
void WatcherKqueue::addFile(const std::string& name, bool emitEvents)
{
void WatcherKqueue::addFile( const std::string& name, bool emitEvents ) {
efDEBUG( "addFile(): Added: %s\n", name.c_str() );
// Open the file to get the file descriptor
int fd = open( name.c_str(), O_EVTONLY );
if( fd == -1 )
{
efDEBUG( "addFile(): Could open file descriptor for %s. File descriptor count: %ld\n", name.c_str(), mWatcher->mFileDescriptorCount );
if ( fd == -1 ) {
efDEBUG( "addFile(): Could open file descriptor for %s. File descriptor count: %ld\n",
name.c_str(), mWatcher->mFileDescriptorCount );
Errors::Log::createLastError( Errors::FileNotReadable, name );
if ( EACCES != errno )
{
if ( EACCES != errno ) {
mInitOK = false;
}
mErrno = errno;
return;
}
@@ -205,39 +179,31 @@ void WatcherKqueue::addFile(const std::string& name, bool emitEvents)
mChangeListCount++;
if ( mChangeListCount + KEVENT_RESERVE_VALUE > mChangeList.size() &&
mChangeListCount % KEVENT_RESERVE_VALUE == 0 )
{
mChangeListCount % KEVENT_RESERVE_VALUE == 0 ) {
size_t reserve_size = mChangeList.size() + KEVENT_RESERVE_VALUE;
mChangeList.resize( reserve_size );
efDEBUG( "addFile(): Reserverd more KEvents space for %s, space reserved %ld, list actual size %ld.\n", Directory.c_str(), reserve_size, mChangeListCount );
efDEBUG( "addFile(): Reserverd more KEvents space for %s, space reserved %ld, list actual "
"size %ld.\n",
Directory.c_str(), reserve_size, mChangeListCount );
}
// create entry
FileInfo * entry = new FileInfo( name );
FileInfo* entry = new FileInfo( name );
// set the event data at the end of the list
EV_SET(
&mChangeList[mChangeListCount],
fd,
EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_ONESHOT,
NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
0,
(void*)entry
);
EV_SET( &mChangeList[mChangeListCount], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, 0, (void*)entry );
// qsort sort the list by name
qsort(&mChangeList[1], mChangeListCount, sizeof(KEvent), comparator);
qsort( &mChangeList[1], mChangeListCount, sizeof( KEvent ), comparator );
// handle action
if( emitEvents )
{
handleAction(name, Actions::Add);
if ( emitEvents ) {
handleAction( name, Actions::Add );
}
}
void WatcherKqueue::removeFile( const std::string& name, bool emitEvents )
{
void WatcherKqueue::removeFile( const std::string& name, bool emitEvents ) {
efDEBUG( "removeFile(): Trying to remove file: %s\n", name.c_str() );
// bsearch
@@ -249,11 +215,11 @@ void WatcherKqueue::removeFile( const std::string& name, bool emitEvents )
target.udata = &tempEntry;
// Search the kevent
KEvent * ke = (KEvent*)bsearch(&target, &mChangeList[0], mChangeListCount + 1, sizeof(KEvent), comparator);
KEvent* ke = (KEvent*)bsearch( &target, &mChangeList[0], mChangeListCount + 1, sizeof( KEvent ),
comparator );
// Trying to remove a non-existing file?
if( !ke )
{
if ( !ke ) {
Errors::Log::createLastError( Errors::FileNotFound, name );
efDEBUG( "File not removed\n" );
return;
@@ -262,13 +228,12 @@ void WatcherKqueue::removeFile( const std::string& name, bool emitEvents )
efDEBUG( "File removed\n" );
// handle action
if ( emitEvents )
{
if ( emitEvents ) {
handleAction( name, Actions::Delete );
}
// Delete the user data ( FileInfo ) from the kevent closed
FileInfo * del = reinterpret_cast<FileInfo*>( ke->udata );
FileInfo* del = reinterpret_cast<FileInfo*>( ke->udata );
efSAFE_DELETE( del );
@@ -277,121 +242,104 @@ void WatcherKqueue::removeFile( const std::string& name, bool emitEvents )
mWatcher->removeFD();
memset(ke, 0, sizeof(KEvent));
memset( ke, 0, sizeof( KEvent ) );
// move end to current
memcpy(ke, &mChangeList[mChangeListCount], sizeof(KEvent));
memset(&mChangeList[mChangeListCount], 0, sizeof(KEvent));
memcpy( ke, &mChangeList[mChangeListCount], sizeof( KEvent ) );
memset( &mChangeList[mChangeListCount], 0, sizeof( KEvent ) );
--mChangeListCount;
}
void WatcherKqueue::rescan()
{
void WatcherKqueue::rescan() {
efDEBUG( "rescan(): Rescanning: %s\n", Directory.c_str() );
DirectorySnapshotDiff Diff = mDirSnap.scan();
if ( Diff.DirChanged )
{
if ( Diff.DirChanged ) {
sendDirChanged();
}
if ( Diff.changed() )
{
if ( Diff.changed() ) {
FileInfoList::iterator it;
MovedList::iterator mit;
/// Files
DiffIterator( FilesCreated )
{
addFile( (*it).Filepath );
DiffIterator( FilesCreated ) {
addFile( ( *it ).Filepath );
}
DiffIterator( FilesModified )
{
handleAction( (*it).Filepath, Actions::Modified );
DiffIterator( FilesModified ) {
handleAction( ( *it ).Filepath, Actions::Modified );
}
DiffIterator( FilesDeleted )
{
removeFile( (*it).Filepath );
DiffIterator( FilesDeleted ) {
removeFile( ( *it ).Filepath );
}
DiffMovedIterator( FilesMoved )
{
handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
removeFile( Directory + (*mit).first, false );
addFile( (*mit).second.Filepath, false );
DiffMovedIterator( FilesMoved ) {
handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first );
removeFile( Directory + ( *mit ).first, false );
addFile( ( *mit ).second.Filepath, false );
}
/// Directories
DiffIterator( DirsCreated )
{
handleFolderAction( (*it).Filepath, Actions::Add );
addWatch( (*it).Filepath, Listener, Recursive, this );
DiffIterator( DirsCreated ) {
handleFolderAction( ( *it ).Filepath, Actions::Add );
addWatch( ( *it ).Filepath, Listener, Recursive, this );
}
DiffIterator( DirsModified )
{
handleFolderAction( (*it).Filepath, Actions::Modified );
DiffIterator( DirsModified ) {
handleFolderAction( ( *it ).Filepath, Actions::Modified );
}
DiffIterator( DirsDeleted )
{
handleFolderAction( (*it).Filepath, Actions::Delete );
DiffIterator( DirsDeleted ) {
handleFolderAction( ( *it ).Filepath, Actions::Delete );
Watcher * watch = findWatcher( (*it).Filepath );
Watcher* watch = findWatcher( ( *it ).Filepath );
if ( NULL != watch )
{
if ( NULL != watch ) {
removeWatch( watch->ID );
}
}
DiffMovedIterator( DirsMoved )
{
moveDirectory( Directory + (*mit).first, (*mit).second.Filepath );
DiffMovedIterator( DirsMoved ) {
moveDirectory( Directory + ( *mit ).first, ( *mit ).second.Filepath );
}
}
}
WatchID WatcherKqueue::watchingDirectory( std::string dir )
{
Watcher * watch = findWatcher( dir );
WatchID WatcherKqueue::watchingDirectory( std::string dir ) {
Watcher* watch = findWatcher( dir );
if ( NULL != watch )
{
if ( NULL != watch ) {
return watch->ID;
}
return Errors::FileNotFound;
}
void WatcherKqueue::handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename )
{
Listener->handleFileAction( ID, Directory, FileSystem::fileNameFromPath( filename ), action, FileSystem::fileNameFromPath( oldFilename ) );
void WatcherKqueue::handleAction( const std::string& filename, efsw::Action action,
const std::string& oldFilename ) {
Listener->handleFileAction( ID, Directory, FileSystem::fileNameFromPath( filename ), action,
FileSystem::fileNameFromPath( oldFilename ) );
}
void WatcherKqueue::handleFolderAction( std::string filename, efsw::Action action , const std::string &oldFilename )
{
void WatcherKqueue::handleFolderAction( std::string filename, efsw::Action action,
const std::string& oldFilename ) {
FileSystem::dirRemoveSlashAtEnd( filename );
handleAction( filename, action, oldFilename );
}
void WatcherKqueue::sendDirChanged()
{
if ( NULL != mParent )
{
Listener->handleFileAction( mParent->ID, mParent->Directory, FileSystem::fileNameFromPath( Directory ), Actions::Modified );
void WatcherKqueue::sendDirChanged() {
if ( NULL != mParent ) {
Listener->handleFileAction( mParent->ID, mParent->Directory,
FileSystem::fileNameFromPath( Directory ), Actions::Modified );
}
}
void WatcherKqueue::watch()
{
if ( -1 == mKqueue )
{
void WatcherKqueue::watch() {
if ( -1 == mKqueue ) {
return;
}
@@ -399,89 +347,70 @@ void WatcherKqueue::watch()
KEvent event;
// First iterate the childs, to get the events from the deepest folder, to the watcher childs
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
{
for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
it->second->watch();
}
bool needScan = false;
// Then we get the the events of the current folder
while( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, &mWatcher->mTimeOut ) ) != 0 )
{
while ( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1,
&mWatcher->mTimeOut ) ) != 0 ) {
// An error ocurred?
if( nev == -1 )
{
if ( nev == -1 ) {
efDEBUG( "watch(): Error on directory %s\n", Directory.c_str() );
perror("kevent");
perror( "kevent" );
break;
}
else
{
FileInfo * entry = NULL;
} else {
FileInfo* entry = NULL;
// If udate == NULL means that it is the fisrt element of the change list, the folder.
// otherwise it is an event of some file inside the folder
if( ( entry = reinterpret_cast<FileInfo*> ( event.udata ) ) != NULL )
{
if ( ( entry = reinterpret_cast<FileInfo*>( event.udata ) ) != NULL ) {
efDEBUG( "watch(): File: %s ", entry->Filepath.c_str() );
// If the event flag is delete... the file was deleted
if ( event.fflags & NOTE_DELETE )
{
if ( event.fflags & NOTE_DELETE ) {
efDEBUG( "deleted\n" );
mDirSnap.removeFile( entry->Filepath );
removeFile( entry->Filepath );
}
else if ( event.fflags & NOTE_EXTEND ||
event.fflags & NOTE_WRITE ||
event.fflags & NOTE_ATTRIB
)
{
} else if ( event.fflags & NOTE_EXTEND || event.fflags & NOTE_WRITE ||
event.fflags & NOTE_ATTRIB ) {
// The file was modified
efDEBUG( "modified\n" );
FileInfo fi( entry->Filepath );
if ( fi != *entry )
{
if ( fi != *entry ) {
*entry = fi;
mDirSnap.updateFile( entry->Filepath );
handleAction( entry->Filepath, efsw::Actions::Modified );
}
}
else if ( event.fflags & NOTE_RENAME )
{
} else if ( event.fflags & NOTE_RENAME ) {
efDEBUG( "moved\n" );
needScan = true;
}
}
else
{
} else {
needScan = true;
}
}
}
if ( needScan )
{
if ( needScan ) {
rescan();
}
}
Watcher * WatcherKqueue::findWatcher( const std::string path )
{
Watcher* WatcherKqueue::findWatcher( const std::string path ) {
WatchMap::iterator it = mWatches.begin();
for ( ; it != mWatches.end(); it++ )
{
if ( it->second->Directory == path )
{
for ( ; it != mWatches.end(); it++ ) {
if ( it->second->Directory == path ) {
return it->second;
}
}
@@ -489,28 +418,24 @@ Watcher * WatcherKqueue::findWatcher( const std::string path )
return NULL;
}
void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, bool emitEvents )
{
void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, bool emitEvents ) {
// Update the directory path if it's a watcher
std::string opath2( oldPath );
FileSystem::dirAddSlashAtEnd( opath2 );
Watcher * watch = findWatcher( opath2 );
Watcher* watch = findWatcher( opath2 );
if ( NULL != watch )
{
if ( NULL != watch ) {
watch->Directory = opath2;
}
if ( emitEvents )
{
if ( emitEvents ) {
handleFolderAction( newPath, efsw::Actions::Moved, oldPath );
}
}
WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive , WatcherKqueue *parent)
{
static long s_fc = 0;
WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher,
bool recursive, WatcherKqueue* parent ) {
static bool s_ug = false;
std::string dir( directory );
@@ -518,57 +443,42 @@ WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener
FileSystem::dirAddSlashAtEnd( dir );
// This should never happen here
if( !FileSystem::isDirectory( dir ) )
{
if ( !FileSystem::isDirectory( dir ) ) {
return Errors::Log::createLastError( Errors::FileNotFound, dir );
}
else if ( pathInWatches( dir ) || pathInParent( dir ) )
{
} else if ( pathInWatches( dir ) || pathInParent( dir ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, directory );
}
else if ( NULL != parent && FileSystem::isRemoteFS( dir ) )
{
} else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) {
return Errors::Log::createLastError( Errors::FileRemote, dir );
}
std::string curPath;
std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
if ( "" != link )
{
if ( "" != link ) {
/// Avoid adding symlinks directories if it's now enabled
if ( NULL != parent && !mWatcher->mFileWatcher->followSymlinks() )
{
if ( NULL != parent && !mWatcher->mFileWatcher->followSymlinks() ) {
return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
}
if ( pathInWatches( link ) || pathInParent( link ) )
{
if ( pathInWatches( link ) || pathInParent( link ) ) {
return Errors::Log::createLastError( Errors::FileRepeated, link );
}
else if ( !mWatcher->linkAllowed( curPath, link ) )
{
} else if ( !mWatcher->linkAllowed( curPath, link ) ) {
return Errors::Log::createLastError( Errors::FileOutOfScope, link );
}
else
{
} else {
dir = link;
}
}
if ( mWatcher->availablesFD() )
{
WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, mWatcher, parent );
if ( mWatcher->availablesFD() ) {
WatcherKqueue* watch =
new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, mWatcher, parent );
mWatches.insert(std::make_pair(mLastWatchID, watch));
mWatches.insert( std::make_pair( mLastWatchID, watch ) );
watch->addAll();
s_fc++;
// if failed to open the directory... erase the watcher
if ( !watch->initOK() )
{
if ( !watch->initOK() ) {
int le = watch->lastErrno();
mWatches.erase( watch->ID );
@@ -578,90 +488,78 @@ WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener
mLastWatchID--;
// Probably the folder has too many files, create a generic watcher
if ( EACCES != le )
{
WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive );
if ( EACCES != le ) {
WatcherGeneric* watch =
new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive );
mWatches.insert(std::make_pair(mLastWatchID, watch));
}
else
{
mWatches.insert( std::make_pair( mLastWatchID, watch ) );
} else {
return Errors::Log::createLastError( Errors::Unspecified, link );
}
}
}
else
{
if ( !s_ug )
{
efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders added: %ld\n", mWatcher->mFileDescriptorCount, s_fc );
} else {
if ( !s_ug ) {
efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld.\n",
mWatcher->mFileDescriptorCount );
s_ug = true;
}
WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive );
WatcherGeneric* watch =
new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive );
mWatches.insert(std::make_pair(mLastWatchID, watch));
mWatches.insert( std::make_pair( mLastWatchID, watch ) );
}
return mLastWatchID;
}
bool WatcherKqueue::initOK()
{
bool WatcherKqueue::initOK() {
return mInitOK;
}
void WatcherKqueue::removeWatch( WatchID watchid )
{
WatchMap::iterator iter = mWatches.find(watchid);
void WatcherKqueue::removeWatch( WatchID watchid ) {
WatchMap::iterator iter = mWatches.find( watchid );
if(iter == mWatches.end())
if ( iter == mWatches.end() )
return;
Watcher * watch = iter->second;
Watcher* watch = iter->second;
mWatches.erase(iter);
mWatches.erase( iter );
efSAFE_DELETE( watch );
}
bool WatcherKqueue::pathInWatches( const std::string& path )
{
bool WatcherKqueue::pathInWatches( const std::string& path ) {
return NULL != findWatcher( path );
}
bool WatcherKqueue::pathInParent( const std::string &path )
{
WatcherKqueue * pNext = mParent;
bool WatcherKqueue::pathInParent( const std::string& path ) {
WatcherKqueue* pNext = mParent;
while ( NULL != pNext )
{
if ( pNext->pathInWatches( path ) )
{
while ( NULL != pNext ) {
if ( pNext->pathInWatches( path ) ) {
return true;
}
pNext = pNext->mParent;
}
if ( mWatcher->pathInWatches( path ) )
{
if ( mWatcher->pathInWatches( path ) ) {
return true;
}
if ( path == Directory )
{
if ( path == Directory ) {
return true;
}
return false;
}
int WatcherKqueue::lastErrno()
{
int WatcherKqueue::lastErrno() {
return mErrno;
}
}
} // namespace efsw
#endif

View File

@@ -5,14 +5,13 @@
#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
#include <map>
#include <vector>
#include <sys/types.h>
#include <sys/event.h>
#include <efsw/DirectorySnapshot.hpp>
#include <map>
#include <sys/event.h>
#include <sys/types.h>
#include <vector>
namespace efsw
{
namespace efsw {
class FileWatcherKqueue;
class WatcherKqueue;
@@ -22,72 +21,76 @@ typedef struct kevent KEvent;
/// type for a map from WatchID to WatcherKqueue pointer
typedef std::map<WatchID, Watcher*> WatchMap;
class WatcherKqueue : public Watcher
{
public:
WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent = NULL );
class WatcherKqueue : public Watcher {
public:
WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener,
bool recursive, FileWatcherKqueue* watcher, WatcherKqueue* parent = NULL );
virtual ~WatcherKqueue();
virtual ~WatcherKqueue();
void addFile( const std::string& name, bool emitEvents = true );
void addFile( const std::string& name, bool emitEvents = true );
void removeFile( const std::string& name, bool emitEvents = true );
void removeFile( const std::string& name, bool emitEvents = true );
// called when the directory is actually changed
// means a file has been added or removed
// rescans the watched directory adding/removing files and sending notices
void rescan();
// called when the directory is actually changed
// means a file has been added or removed
// rescans the watched directory adding/removing files and sending notices
void rescan();
void handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename = "" );
void handleAction( const std::string& filename, efsw::Action action,
const std::string& oldFilename = "" );
void handleFolderAction( std::string filename, efsw::Action action, const std::string& oldFilename = "" );
void handleFolderAction( std::string filename, efsw::Action action,
const std::string& oldFilename = "" );
void addAll();
void addAll();
void removeAll();
void removeAll();
WatchID watchingDirectory( std::string dir );
WatchID watchingDirectory( std::string dir );
void watch();
void watch() override;
WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherKqueue * parent);
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
WatcherKqueue* parent );
void removeWatch (WatchID watchid );
bool initOK();
void removeWatch( WatchID watchid );
int lastErrno();
protected:
WatchMap mWatches;
int mLastWatchID;
bool initOK();
// index 0 is always the directory
std::vector<KEvent> mChangeList;
size_t mChangeListCount;
DirectorySnapshot mDirSnap;
int lastErrno();
/// The descriptor for the kqueue
int mKqueue;
protected:
WatchMap mWatches;
int mLastWatchID;
FileWatcherKqueue * mWatcher;
// index 0 is always the directory
std::vector<KEvent> mChangeList;
size_t mChangeListCount;
DirectorySnapshot mDirSnap;
WatcherKqueue * mParent;
bool mInitOK;
int mErrno;
/// The descriptor for the kqueue
int mKqueue;
bool pathInWatches( const std::string& path );
bool pathInParent( const std::string& path );
FileWatcherKqueue* mWatcher;
Watcher * findWatcher( const std::string path );
WatcherKqueue* mParent;
void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true );
bool mInitOK;
int mErrno;
void sendDirChanged();
bool pathInWatches( const std::string& path );
bool pathInParent( const std::string& path );
Watcher* findWatcher( const std::string path );
void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true );
void sendDirChanged();
};
}
} // namespace efsw
#endif

View File

@@ -1,144 +1,130 @@
#include <efsw/WatcherWin32.hpp>
#include <efsw/Debug.hpp>
#include <efsw/String.hpp>
#include <efsw/WatcherWin32.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
namespace efsw
{
#include <algorithm>
namespace efsw {
/// Unpacks events and passes them to a user defined callback.
void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
char szFile[MAX_PATH];
PFILE_NOTIFY_INFORMATION pNotify;
WatcherStructWin32 * tWatch = (WatcherStructWin32*) lpOverlapped;
WatcherWin32 * pWatch = tWatch->Watch;
size_t offset = 0;
void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) {
if (dwNumberOfBytesTransfered == 0)
{
RefreshWatch(tWatch); // If dwNumberOfBytesTransfered == 0, it means the buffer overflowed (too many changes between GetOverlappedResults calls). Those events are lost, but at least we can refresh so subsequent changes are seen again.
if ( NULL == lpOverlapped ) {
return;
}
if (dwErrorCode == ERROR_SUCCESS)
{
do
{
bool skip = false;
PFILE_NOTIFY_INFORMATION pNotify;
WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped;
WatcherWin32* pWatch = tWatch->Watch;
size_t offset = 0;
pNotify = (PFILE_NOTIFY_INFORMATION) &pWatch->mBuffer[offset];
offset += pNotify->NextEntryOffset;
int count = WideCharToMultiByte(CP_UTF8, 0, pNotify->FileName,
pNotify->FileNameLength / sizeof(WCHAR),
szFile, MAX_PATH - 1, NULL, NULL);
szFile[count] = TEXT('\0');
std::string nfile( szFile );
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;
}
if ( !skip )
{
pWatch->Watch->handleAction(pWatch, nfile, pNotify->Action);
}
} while (pNotify->NextEntryOffset != 0);
if ( dwNumberOfBytesTransfered == 0 ) {
if ( nullptr != pWatch && !pWatch->StopNow ) {
RefreshWatch( tWatch );
} else {
return;
}
}
if (!pWatch->StopNow)
{
RefreshWatch(tWatch);
do {
bool skip = false;
pNotify = (PFILE_NOTIFY_INFORMATION)&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;
}
if ( !skip ) {
pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action );
}
} while ( pNotify->NextEntryOffset != 0 );
if ( !pWatch->StopNow ) {
RefreshWatch( tWatch );
}
}
/// Refreshes the directory monitoring.
bool RefreshWatch(WatcherStructWin32* pWatch)
{
return ReadDirectoryChangesW(
pWatch->Watch->DirHandle,
pWatch->Watch->mBuffer,
sizeof(pWatch->Watch->mBuffer),
pWatch->Watch->Recursive,
pWatch->Watch->NotifyFilter,
NULL,
&pWatch->Overlapped,
NULL
) != 0;
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;
if ( !bRet ) {
std::string error = std::to_string( GetLastError() );
Errors::Log::createLastError( Errors::WatcherFailed, error );
}
return bRet;
}
/// Stops monitoring a directory.
void DestroyWatch(WatcherStructWin32* pWatch)
{
if (pWatch)
{
WatcherWin32 * tWatch = pWatch->Watch;
void DestroyWatch( WatcherStructWin32* pWatch ) {
if ( pWatch ) {
WatcherWin32* tWatch = pWatch->Watch;
tWatch->StopNow = true;
CancelIoEx(tWatch->DirHandle, &pWatch->Overlapped);
RefreshWatch(pWatch);
CloseHandle(pWatch->Overlapped.hEvent);
CloseHandle(pWatch->Watch->DirHandle);
CancelIoEx( pWatch->Watch->DirHandle, &pWatch->Overlapped );
CloseHandle( pWatch->Watch->DirHandle );
efSAFE_DELETE_ARRAY( pWatch->Watch->DirName );
efSAFE_DELETE( pWatch->Watch );
HeapFree(GetProcessHeap(), 0, pWatch);
}
}
/// Starts monitoring a directory.
WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter)
{
WatcherStructWin32 * tWatch;
size_t ptrsize = sizeof(*tWatch);
tWatch = static_cast<WatcherStructWin32*>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize));
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 ) );
WatcherWin32 * pWatch = new WatcherWin32();
WatcherWin32* pWatch = new WatcherWin32(bufferSize);
tWatch->Watch = pWatch;
pWatch->DirHandle = CreateFileW(
szDirectory,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL
);
szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL );
if (pWatch->DirHandle != INVALID_HANDLE_VALUE)
{
tWatch->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pWatch->NotifyFilter = NotifyFilter;
if ( pWatch->DirHandle != INVALID_HANDLE_VALUE &&
CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) {
pWatch->NotifyFilter = notifyFilter;
pWatch->Recursive = recursive;
if (RefreshWatch(tWatch))
{
if ( RefreshWatch( tWatch ) ) {
return tWatch;
}
else
{
CloseHandle(tWatch->Overlapped.hEvent);
CloseHandle(pWatch->DirHandle);
}
}
HeapFree(GetProcessHeap(), 0, tWatch);
CloseHandle( pWatch->DirHandle );
efSAFE_DELETE( pWatch->Watch );
HeapFree( GetProcessHeap(), 0, tWatch );
return NULL;
}
}
} // namespace efsw
#endif
#endif

View File

@@ -1,76 +1,73 @@
#ifndef EFSW_WATCHERWIN32_HPP
#define EFSW_WATCHERWIN32_HPP
#include <efsw/FileWatcherImpl.hpp>
#include <efsw/FileInfo.hpp>
#include <efsw/FileWatcherImpl.hpp>
#include <vector>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#include <windows.h>
#ifdef EFSW_COMPILER_MSVC
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment( lib, "comctl32.lib" )
#pragma comment( lib, "user32.lib" )
#pragma comment( lib, "ole32.lib" )
// disable secure warnings
#pragma warning (disable: 4996)
// disable secure warnings
#pragma warning( disable : 4996 )
#endif
namespace efsw
{
namespace efsw {
class WatcherWin32;
/// Internal watch data
struct WatcherStructWin32
{
struct WatcherStructWin32 {
OVERLAPPED Overlapped;
WatcherWin32 * Watch;
WatcherWin32* Watch;
};
class cLastModifiedEvent
{
public:
cLastModifiedEvent() {}
FileInfo file;
std::string fileName;
struct sLastModifiedEvent {
FileInfo file;
std::string fileName;
};
bool RefreshWatch(WatcherStructWin32* pWatch);
bool RefreshWatch( WatcherStructWin32* pWatch );
void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped);
void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped );
void DestroyWatch(WatcherStructWin32* pWatch);
void DestroyWatch( WatcherStructWin32* pWatch );
WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter);
WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive,
DWORD bufferSize, DWORD notifyFilter, HANDLE iocp );
class WatcherWin32 : public Watcher
{
public:
WatcherWin32() :
Struct( NULL ),
DirHandle( NULL ),
lParam( 0 ),
NotifyFilter( 0 ),
StopNow( false ),
Watch( NULL ),
DirName( NULL )
{
class WatcherWin32 : public Watcher {
public:
WatcherWin32(DWORD dwBufferSize) :
Struct( NULL ),
DirHandle( NULL ),
Buffer(),
lParam( 0 ),
NotifyFilter( 0 ),
StopNow( false ),
Watch( NULL ),
DirName( NULL ) {
Buffer.resize(dwBufferSize);
}
WatcherStructWin32 * Struct;
HANDLE DirHandle;
BYTE mBuffer[63 * 1024]; // do NOT make this bigger than 64K because it will fail if the folder being watched is on the network! (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx)
LPARAM lParam;
DWORD NotifyFilter;
bool StopNow;
FileWatcherImpl* Watch;
char* DirName;
cLastModifiedEvent LastModifiedEvent;
WatcherStructWin32* Struct;
HANDLE DirHandle;
std::vector<BYTE> Buffer;
LPARAM lParam;
DWORD NotifyFilter;
bool StopNow;
FileWatcherImpl* Watch;
char* DirName;
sLastModifiedEvent LastModifiedEvent;
};
}
} // namespace efsw
#endif

View File

@@ -1,115 +1,129 @@
#ifndef EFSW_BASE
#define EFSW_BASE
#include <efsw/sophist.h>
#include <efsw/efsw.hpp>
#include <efsw/sophist.h>
namespace efsw {
typedef SOPHIST_int8 Int8;
typedef SOPHIST_uint8 Uint8;
typedef SOPHIST_int16 Int16;
typedef SOPHIST_uint16 Uint16;
typedef SOPHIST_int32 Int32;
typedef SOPHIST_uint32 Uint32;
typedef SOPHIST_int64 Int64;
typedef SOPHIST_uint64 Uint64;
typedef SOPHIST_int8 Int8;
typedef SOPHIST_uint8 Uint8;
typedef SOPHIST_int16 Int16;
typedef SOPHIST_uint16 Uint16;
typedef SOPHIST_int32 Int32;
typedef SOPHIST_uint32 Uint32;
typedef SOPHIST_int64 Int64;
typedef SOPHIST_uint64 Uint64;
#define EFSW_OS_WIN 1
#define EFSW_OS_LINUX 2
#define EFSW_OS_MACOSX 3
#define EFSW_OS_BSD 4
#define EFSW_OS_SOLARIS 5
#define EFSW_OS_HAIKU 6
#define EFSW_OS_ANDROID 7
#define EFSW_OS_IOS 8
#define EFSW_OS_WIN 1
#define EFSW_OS_LINUX 2
#define EFSW_OS_MACOSX 3
#define EFSW_OS_BSD 4
#define EFSW_OS_SOLARIS 5
#define EFSW_OS_HAIKU 6
#define EFSW_OS_ANDROID 7
#define EFSW_OS_IOS 8
#define EFSW_PLATFORM_WIN32 1
#define EFSW_PLATFORM_INOTIFY 2
#define EFSW_PLATFORM_KQUEUE 3
#define EFSW_PLATFORM_FSEVENTS 4
#define EFSW_PLATFORM_GENERIC 5
#define EFSW_PLATFORM_WIN32 1
#define EFSW_PLATFORM_INOTIFY 2
#define EFSW_PLATFORM_KQUEUE 3
#define EFSW_PLATFORM_FSEVENTS 4
#define EFSW_PLATFORM_GENERIC 5
#if defined(_WIN32)
/// Any Windows platform
#define EFSW_OS EFSW_OS_WIN
#define EFSW_PLATFORM EFSW_PLATFORM_WIN32
#if defined( _WIN32 )
/// Any Windows platform
#define EFSW_OS EFSW_OS_WIN
#define EFSW_PLATFORM EFSW_PLATFORM_WIN32
#if ( defined( _MSCVER ) || defined( _MSC_VER ) )
#define EFSW_COMPILER_MSVC
#endif
/// Force windows target version above or equal to Windows Server 2008 or Windows Vista
#if _WIN32_WINNT < 0x600
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x600
#endif
#elif defined( __FreeBSD__ ) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined( __DragonFly__ )
#define EFSW_OS EFSW_OS_BSD
#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
#if ( defined( _MSCVER ) || defined( _MSC_VER ) )
#define EFSW_COMPILER_MSVC
#endif
#elif defined( __APPLE_CC__ ) || defined ( __APPLE__ )
#include <TargetConditionals.h>
/// Force windows target version above or equal to Windows Server 2008 or Windows Vista
#if _WIN32_WINNT < 0x600
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x600
#endif
#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) || \
defined( __DragonFly__ )
#define EFSW_OS EFSW_OS_BSD
#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
#if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR )
#define EFSW_OS EFSW_OS_IOS
#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
#else
#define EFSW_OS EFSW_OS_MACOSX
#elif defined( __APPLE_CC__ ) || defined( __APPLE__ )
#include <TargetConditionals.h>
#if defined(EFSW_FSEVENTS_NOT_SUPPORTED)
#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
#else
#define EFSW_PLATFORM EFSW_PLATFORM_FSEVENTS
#endif
#endif
#if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || \
( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR )
#define EFSW_OS EFSW_OS_IOS
#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
#else
#define EFSW_OS EFSW_OS_MACOSX
#elif defined(__linux__)
/// This includes Linux and Android
#ifndef EFSW_KQUEUE
#define EFSW_PLATFORM EFSW_PLATFORM_INOTIFY
#else
/// This is for testing libkqueue, sadly it doesnt work
#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
#endif
#if defined( EFSW_FSEVENTS_NOT_SUPPORTED )
#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
#else
#define EFSW_PLATFORM EFSW_PLATFORM_FSEVENTS
#endif
#endif
#if defined( __ANDROID__ ) || defined( ANDROID )
#define EFSW_OS EFSW_OS_ANDROID
#else
#define EFSW_OS EFSW_OS_LINUX
#endif
#elif defined( __linux__ )
/// This includes Linux and Android
#ifndef EFSW_KQUEUE
#define EFSW_PLATFORM EFSW_PLATFORM_INOTIFY
#else
/// This is for testing libkqueue, sadly it doesnt work
#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
#endif
#if defined( __ANDROID__ ) || defined( ANDROID )
#define EFSW_OS EFSW_OS_ANDROID
#else
#define EFSW_OS EFSW_OS_LINUX
#endif
#else
#if defined( __SVR4 )
#define EFSW_OS EFSW_OS_SOLARIS
#elif defined( __HAIKU__ ) || defined( __BEOS__ )
#define EFSW_OS EFSW_OS_HAIKU
#endif
#if defined( __SVR4 )
#define EFSW_OS EFSW_OS_SOLARIS
#elif defined( __HAIKU__ ) || defined( __BEOS__ )
#define EFSW_OS EFSW_OS_HAIKU
#endif
/// Everything else
#define EFSW_PLATFORM EFSW_PLATFORM_GENERIC
/// Everything else
#define EFSW_PLATFORM EFSW_PLATFORM_GENERIC
#endif
#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
#define EFSW_PLATFORM_POSIX
#define EFSW_PLATFORM_POSIX
#endif
#if 1 == SOPHIST_pointer64
#define EFSW_64BIT
#define EFSW_64BIT
#else
#define EFSW_32BIT
#define EFSW_32BIT
#endif
#if defined(arm) || defined(__arm__)
#define EFSW_ARM
#if defined( arm ) || defined( __arm__ )
#define EFSW_ARM
#endif
#define efCOMMA ,
#define efSAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define efSAFE_DELETE_ARRAY(p) { if(p) { delete [] (p); (p)=NULL; } }
#define efARRAY_SIZE(__array) ( sizeof(__array) / sizeof(__array[0]) )
#define efSAFE_DELETE( p ) \
{ \
if ( p ) { \
delete ( p ); \
( p ) = NULL; \
} \
}
#define efSAFE_DELETE_ARRAY( p ) \
{ \
if ( p ) { \
delete[] ( p ); \
( p ) = NULL; \
} \
}
#define efARRAY_SIZE( __array ) ( sizeof( __array ) / sizeof( __array[0] ) )
}
} // namespace efsw
#endif

View File

@@ -4,17 +4,17 @@
#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>
#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>
#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
#error Thread, Mutex, and System not implemented for this platform.
#error Thread, Mutex, and System not implemented for this platform.
#endif
#endif

View File

@@ -2,11 +2,11 @@
#if defined( EFSW_PLATFORM_POSIX )
#include <cstring>
#include <dirent.h>
#include <efsw/FileInfo.hpp>
#include <efsw/FileSystem.hpp>
#include <dirent.h>
#include <unistd.h>
#include <cstring>
#ifndef _DARWIN_FEATURE_64_BIT_INODE
#define _DARWIN_FEATURE_64_BIT_INODE
@@ -16,15 +16,15 @@
#define _FILE_OFFSET_BITS 64
#endif
#include <sys/stat.h>
#include <cstdlib>
#include <climits>
#include <cstdlib>
#include <sys/stat.h>
#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID
#include <sys/vfs.h>
#elif EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_IOS
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/param.h>
#endif
/** Remote file systems codes */
@@ -52,43 +52,15 @@
#define S_MAGIC_VXFS 0xA501FCF5
#if EFSW_OS == EFSW_OS_LINUX
#include <mntent.h>
#include <cstdio>
#include <mntent.h>
#endif
namespace efsw { namespace Platform {
#if EFSW_OS == EFSW_OS_LINUX
#pragma pack(push, 1)
struct ntfs_super_block
{
char jump[3];
char oem_id[8];
};
#pragma pack(pop)
bool isNTFS( std::string device )
{
FILE * fd = fopen( device.c_str(), "r" );
ntfs_super_block ns;
if ( fd != NULL )
{
fread( &ns, 1, sizeof(ntfs_super_block), fd );
fclose( fd );
std::string oemId( ns.oem_id );
return oemId.compare(0, 4, "NTFS") == 0;
}
return false;
}
std::string findMountPoint( std::string file )
{
std::string findMountPoint( std::string file ) {
std::string cwd = FileSystem::getCurrentWorkingDirectory();
struct stat last_stat;
struct stat file_stat;
@@ -108,22 +80,20 @@ std::string findMountPoint( std::string file )
if ( !FileSystem::changeWorkingDirectory( dir ) )
return "";
if (stat (".", &last_stat) < 0)
if ( stat( ".", &last_stat ) < 0 )
return "";
}
while (true)
{
while ( true ) {
struct stat st;
if ( stat("..", &st) < 0 )
if ( stat( "..", &st ) < 0 )
goto done;
if ( st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino )
break;
if ( !FileSystem::changeWorkingDirectory("..") )
{
if ( !FileSystem::changeWorkingDirectory( ".." ) ) {
goto done;
}
@@ -139,46 +109,41 @@ done:
return mp;
}
std::string findDevicePath( const std::string& directory )
{
struct mntent *ent;
FILE *aFile;
std::string findDevicePath( const std::string& directory ) {
struct mntent* ent;
FILE* aFile;
aFile = setmntent("/proc/mounts", "r");
aFile = setmntent( "/proc/mounts", "r" );
if ( aFile == NULL )
return "";
while ( NULL != ( ent = getmntent( aFile ) ) )
{
while ( NULL != ( ent = getmntent( aFile ) ) ) {
std::string dirName( ent->mnt_dir );
if ( dirName == directory )
{
if ( dirName == directory ) {
std::string fsName( ent->mnt_fsname );
endmntent(aFile);
endmntent( aFile );
return fsName;
}
}
endmntent(aFile);
endmntent( aFile );
return "";
}
bool isLocalFUSEDirectory( std::string directory )
{
bool isLocalFUSEDirectory( std::string directory ) {
efsw::FileSystem::dirRemoveSlashAtEnd( directory );
directory = findMountPoint( directory );
if ( !directory.empty() )
{
if ( !directory.empty() ) {
std::string devicePath = findDevicePath( directory );
return ( !devicePath.empty() && isNTFS( devicePath ) );
return !devicePath.empty();
}
return false;
@@ -186,102 +151,93 @@ bool isLocalFUSEDirectory( std::string directory )
#endif
bool FileSystem::changeWorkingDirectory( const std::string & path )
{
bool FileSystem::changeWorkingDirectory( const std::string& path ) {
return -1 != chdir( path.c_str() );
}
std::string FileSystem::getCurrentWorkingDirectory() {
char dir[PATH_MAX + 1];
getcwd( dir, PATH_MAX + 1 );
return std::string( dir );
char* result = getcwd( dir, PATH_MAX + 1 );
return result != NULL ? std::string( result ) : std::string();
}
FileInfoMap FileSystem::filesInfoFromPath( const std::string& path )
{
FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) {
FileInfoMap files;
DIR *dp;
struct dirent *dirp;
DIR* dp;
struct dirent* dirp;
if( ( dp = opendir( path.c_str() ) ) == NULL)
if ( ( dp = opendir( path.c_str() ) ) == NULL )
return files;
while ( ( dirp = readdir(dp) ) != NULL)
{
if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 )
{
while ( ( dirp = readdir( dp ) ) != NULL ) {
if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 ) {
std::string name( dirp->d_name );
std::string fpath( path + name );
files[ name ] = FileInfo( fpath );
files[name] = FileInfo( fpath );
}
}
closedir(dp);
closedir( dp );
return files;
}
char FileSystem::getOSSlash()
{
char FileSystem::getOSSlash() {
return '/';
}
bool FileSystem::isDirectory( const std::string& path )
{
bool FileSystem::isDirectory( const std::string& path ) {
struct stat st;
int res = stat( path.c_str(), &st );
if ( 0 == res )
{
return static_cast<bool>( S_ISDIR(st.st_mode) );
if ( 0 == res ) {
return static_cast<bool>( S_ISDIR( st.st_mode ) );
}
return false;
}
bool FileSystem::isRemoteFS( const std::string& directory )
{
#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID || EFSW_OS == EFSW_OS_IOS
bool FileSystem::isRemoteFS( const std::string& directory ) {
#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || \
EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID || EFSW_OS == EFSW_OS_IOS
struct statfs statfsbuf;
statfs( directory.c_str(), &statfsbuf );
switch ( statfsbuf.f_type | 0UL )
{
switch ( statfsbuf.f_type | 0UL ) {
case S_MAGIC_FUSEBLK: /* 0x65735546 remote */
{
#if EFSW_OS == EFSW_OS_LINUX
#if EFSW_OS == EFSW_OS_LINUX
return !isLocalFUSEDirectory( directory );
#endif
#endif
}
case S_MAGIC_AFS: /* 0x5346414F remote */
case S_MAGIC_AUFS: /* 0x61756673 remote */
case S_MAGIC_CEPH: /* 0x00C36400 remote */
case S_MAGIC_CIFS: /* 0xFF534D42 remote */
case S_MAGIC_CODA: /* 0x73757245 remote */
case S_MAGIC_FHGFS: /* 0x19830326 remote */
case S_MAGIC_AFS: /* 0x5346414F remote */
case S_MAGIC_AUFS: /* 0x61756673 remote */
case S_MAGIC_CEPH: /* 0x00C36400 remote */
case S_MAGIC_CIFS: /* 0xFF534D42 remote */
case S_MAGIC_CODA: /* 0x73757245 remote */
case S_MAGIC_FHGFS: /* 0x19830326 remote */
case S_MAGIC_FUSECTL: /* 0x65735543 remote */
case S_MAGIC_GFS: /* 0x01161970 remote */
case S_MAGIC_GPFS: /* 0x47504653 remote */
case S_MAGIC_KAFS: /* 0x6B414653 remote */
case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */
case S_MAGIC_NCP: /* 0x564C remote */
case S_MAGIC_NFS: /* 0x6969 remote */
case S_MAGIC_NFSD: /* 0x6E667364 remote */
case S_MAGIC_OCFS2: /* 0x7461636F remote */
case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */
case S_MAGIC_PIPEFS: /* 0x50495045 remote */
case S_MAGIC_SMB: /* 0x517B remote */
case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */
case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */
case S_MAGIC_VXFS: /* 0xA501FCF5 remote */
case S_MAGIC_GFS: /* 0x01161970 remote */
case S_MAGIC_GPFS: /* 0x47504653 remote */
case S_MAGIC_KAFS: /* 0x6B414653 remote */
case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */
case S_MAGIC_NCP: /* 0x564C remote */
case S_MAGIC_NFS: /* 0x6969 remote */
case S_MAGIC_NFSD: /* 0x6E667364 remote */
case S_MAGIC_OCFS2: /* 0x7461636F remote */
case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */
case S_MAGIC_PIPEFS: /* 0x50495045 remote */
case S_MAGIC_SMB: /* 0x517B remote */
case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */
case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */
case S_MAGIC_VXFS: /* 0xA501FCF5 remote */
{
return true;
}
default:
{
default: {
return false;
}
}
@@ -290,6 +246,6 @@ bool FileSystem::isRemoteFS( const std::string& directory )
return false;
}
}}
}} // namespace efsw::Platform
#endif

View File

@@ -1,30 +1,29 @@
#ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP
#define EFSW_FILESYSTEMIMPLPOSIX_HPP
#include <efsw/base.hpp>
#include <efsw/FileInfo.hpp>
#include <efsw/base.hpp>
#if defined( EFSW_PLATFORM_POSIX )
namespace efsw { namespace Platform {
class FileSystem
{
public:
static FileInfoMap filesInfoFromPath( const std::string& path );
class FileSystem {
public:
static FileInfoMap filesInfoFromPath( const std::string& path );
static char getOSSlash();
static char getOSSlash();
static bool isDirectory( const std::string& path );
static bool isDirectory( const std::string& path );
static bool isRemoteFS( const std::string& directory );
static bool isRemoteFS( const std::string& directory );
static bool changeWorkingDirectory( const std::string & path );
static bool changeWorkingDirectory( const std::string& path );
static std::string getCurrentWorkingDirectory();
static std::string getCurrentWorkingDirectory();
};
}}
}} // namespace efsw::Platform
#endif

View File

@@ -4,29 +4,25 @@
namespace efsw { namespace Platform {
MutexImpl::MutexImpl()
{
MutexImpl::MutexImpl() {
pthread_mutexattr_t attributes;
pthread_mutexattr_init(&attributes);
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mMutex, &attributes);
pthread_mutexattr_init( &attributes );
pthread_mutexattr_settype( &attributes, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &mMutex, &attributes );
}
MutexImpl::~MutexImpl()
{
pthread_mutex_destroy(&mMutex);
MutexImpl::~MutexImpl() {
pthread_mutex_destroy( &mMutex );
}
void MutexImpl::lock()
{
pthread_mutex_lock(&mMutex);
void MutexImpl::lock() {
pthread_mutex_lock( &mMutex );
}
void MutexImpl::unlock()
{
pthread_mutex_unlock(&mMutex);
void MutexImpl::unlock() {
pthread_mutex_unlock( &mMutex );
}
}}
}} // namespace efsw::Platform
#endif

View File

@@ -9,23 +9,22 @@
namespace efsw { namespace Platform {
class MutexImpl
{
public:
MutexImpl();
class MutexImpl {
public:
MutexImpl();
~MutexImpl();
~MutexImpl();
void lock();
void lock();
void unlock();
private:
pthread_mutex_t mMutex;
void unlock();
private:
pthread_mutex_t mMutex;
};
}}
}} // namespace efsw::Platform
#endif
#endif

View File

@@ -3,32 +3,31 @@
#if defined( EFSW_PLATFORM_POSIX )
#include <cstdio>
#include <pthread.h>
#include <sys/time.h>
#include <limits.h>
#include <pthread.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <efsw/FileSystem.hpp>
#include <efsw/Debug.hpp>
#include <efsw/FileSystem.hpp>
#if EFSW_OS == EFSW_OS_MACOSX
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CoreFoundation.h>
#elif EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_ANDROID
#include <libgen.h>
#include <unistd.h>
#include <libgen.h>
#include <unistd.h>
#elif EFSW_OS == EFSW_OS_HAIKU
#include <kernel/OS.h>
#include <kernel/image.h>
#include <kernel/OS.h>
#include <kernel/image.h>
#elif EFSW_OS == EFSW_OS_SOLARIS
#include <stdlib.h>
#include <stdlib.h>
#elif EFSW_OS == EFSW_OS_BSD
#include <sys/sysctl.h>
#include <sys/sysctl.h>
#endif
namespace efsw { namespace Platform {
void System::sleep( const unsigned long& ms )
{
void System::sleep( const unsigned long& ms ) {
// usleep( static_cast<unsigned long>( ms * 1000 ) );
// usleep is not reliable enough (it might block the
@@ -42,47 +41,44 @@ void System::sleep( const unsigned long& ms )
// get the current time
timeval tv;
gettimeofday(&tv, NULL);
gettimeofday( &tv, NULL );
// construct the time limit (current time + time to wait)
timespec ti;
ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000;
ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000);
ti.tv_nsec = ( tv.tv_usec + ( usecs % 1000000 ) ) * 1000;
ti.tv_sec = tv.tv_sec + ( usecs / 1000000 ) + ( ti.tv_nsec / 1000000000 );
ti.tv_nsec %= 1000000000;
// create a mutex and thread condition
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, 0);
pthread_mutex_init( &mutex, 0 );
pthread_cond_t condition;
pthread_cond_init(&condition, 0);
pthread_cond_init( &condition, 0 );
// wait...
pthread_mutex_lock(&mutex);
pthread_cond_timedwait(&condition, &mutex, &ti);
pthread_mutex_unlock(&mutex);
pthread_mutex_lock( &mutex );
pthread_cond_timedwait( &condition, &mutex, &ti );
pthread_mutex_unlock( &mutex );
// destroy the mutex and condition
pthread_cond_destroy(&condition);
pthread_cond_destroy( &condition );
}
std::string System::getProcessPath()
{
std::string System::getProcessPath() {
#if EFSW_OS == EFSW_OS_MACOSX
char exe_file[FILENAME_MAX + 1];
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle)
{
CFURLRef mainURL = CFBundleCopyBundleURL(mainBundle);
if ( mainBundle ) {
CFURLRef mainURL = CFBundleCopyBundleURL( mainBundle );
if (mainURL)
{
int ok = CFURLGetFileSystemRepresentation ( mainURL, (Boolean) true, (UInt8*)exe_file, FILENAME_MAX );
if ( mainURL ) {
int ok = CFURLGetFileSystemRepresentation( mainURL, ( Boolean ) true, (UInt8*)exe_file,
FILENAME_MAX );
if (ok)
{
return std::string(exe_file) + "/";
if ( ok ) {
return std::string( exe_file ) + "/";
}
}
}
@@ -93,14 +89,11 @@ std::string System::getProcessPath()
int size;
size = readlink("/proc/self/exe", exe_file, FILENAME_MAX);
size = readlink( "/proc/self/exe", exe_file, FILENAME_MAX );
if (size < 0)
{
return std::string( "./" );
}
else
{
if ( size < 0 ) {
return std::string( "./" );
} else {
exe_file[size] = '\0';
return std::string( dirname( exe_file ) ) + "/";
}
@@ -112,8 +105,8 @@ std::string System::getProcessPath()
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
char buf[1024];
size_t cb = sizeof(buf);
sysctl(mib, 4, buf, &cb, NULL, 0);
size_t cb = sizeof( buf );
sysctl( mib, 4, buf, &cb, NULL, 0 );
return FileSystem::pathRemoveFileName( std::string( buf ) );
@@ -124,8 +117,7 @@ std::string System::getProcessPath()
image_info info;
int32 cookie = 0;
while ( B_OK == get_next_image_info( 0, &cookie, &info ) )
{
while ( B_OK == get_next_image_info( 0, &cookie, &info ) ) {
if ( info.type == B_APP_IMAGE )
break;
}
@@ -136,18 +128,16 @@ std::string System::getProcessPath()
return "/sdcard/";
#else
#warning getProcessPath() not implemented on this platform. ( will return "./" )
#warning getProcessPath() not implemented on this platform. ( will return "./" )
return "./";
#endif
}
void System::maxFD()
{
void System::maxFD() {
static bool maxed = false;
if ( !maxed )
{
if ( !maxed ) {
struct rlimit limit;
getrlimit( RLIMIT_NOFILE, &limit );
limit.rlim_cur = limit.rlim_max;
@@ -161,12 +151,10 @@ void System::maxFD()
}
}
Uint64 System::getMaxFD()
{
Uint64 System::getMaxFD() {
static rlim_t max_fd = 0;
if ( max_fd == 0 )
{
if ( max_fd == 0 ) {
struct rlimit limit;
getrlimit( RLIMIT_NOFILE, &limit );
max_fd = limit.rlim_cur;
@@ -175,6 +163,6 @@ Uint64 System::getMaxFD()
return max_fd;
}
}}
}} // namespace efsw::Platform
#endif

View File

@@ -7,19 +7,18 @@
namespace efsw { namespace Platform {
class System
{
public:
static void sleep( const unsigned long& ms );
class System {
public:
static void sleep( const unsigned long& ms );
static std::string getProcessPath();
static std::string getProcessPath();
static void maxFD();
static void maxFD();
static Uint64 getMaxFD();
static Uint64 getMaxFD();
};
}}
}} // namespace efsw::Platform
#endif

View File

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

View File

@@ -5,6 +5,7 @@
#if defined( EFSW_PLATFORM_POSIX )
#include <efsw/Atomic.hpp>
#include <pthread.h>
namespace efsw {
@@ -13,22 +14,25 @@ class Thread;
namespace Platform {
class ThreadImpl
{
public:
ThreadImpl( Thread * owner );
void wait();
void terminate();
protected:
static void * entryPoint( void* userData );
class ThreadImpl {
public:
explicit ThreadImpl( efsw::Thread* owner );
pthread_t mThread;
bool mIsActive;
~ThreadImpl();
void wait();
void terminate();
protected:
static void* entryPoint( void* userData );
pthread_t mThread;
Atomic<bool> mIsActive;
};
}}
} // namespace Platform
} // namespace efsw
#endif

View File

@@ -4,7 +4,7 @@
#include <climits>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
@@ -16,31 +16,30 @@
namespace efsw { namespace Platform {
bool FileSystem::changeWorkingDirectory( const std::string & path )
{
bool FileSystem::changeWorkingDirectory( const std::string& path ) {
int res;
#ifdef EFSW_COMPILER_MSVC
#ifdef UNICODE
#ifdef UNICODE
res = _wchdir( String::fromUtf8( path.c_str() ).toWideString().c_str() );
#else
#else
res = _chdir( String::fromUtf8( path.c_str() ).toAnsiString().c_str() );
#endif
#endif
#else
res = chdir( path.c_str() );
#endif
return -1 != res;
}
std::string FileSystem::getCurrentWorkingDirectory()
{
std::string FileSystem::getCurrentWorkingDirectory() {
#ifdef EFSW_COMPILER_MSVC
#if defined( UNICODE ) AND !defined( EFSW_NO_WIDECHAR )
#if defined( UNICODE ) && !defined( EFSW_NO_WIDECHAR )
wchar_t dir[_MAX_PATH];
return ( 0 != GetCurrentDirectoryW( _MAX_PATH, dir ) ) ? String( dir ).toUtf8() : std::string();
#else
#else
char dir[_MAX_PATH];
return ( 0 != GetCurrentDirectory( _MAX_PATH, dir ) ) ? String( dir, std::locale() ).toUtf8() : std::string();
#endif
return ( 0 != GetCurrentDirectory( _MAX_PATH, dir ) ) ? String( dir, std::locale() ).toUtf8()
: std::string();
#endif
#else
char dir[PATH_MAX + 1];
getcwd( dir, PATH_MAX + 1 );
@@ -48,42 +47,34 @@ std::string FileSystem::getCurrentWorkingDirectory()
#endif
}
FileInfoMap FileSystem::filesInfoFromPath( const std::string& path )
{
FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) {
FileInfoMap files;
String tpath( path );
if ( tpath[ tpath.size() - 1 ] == '/' || tpath[ tpath.size() - 1 ] == '\\' )
{
if ( tpath[tpath.size() - 1] == '/' || tpath[tpath.size() - 1] == '\\' ) {
tpath += "*";
}
else
{
} else {
tpath += "\\*";
}
WIN32_FIND_DATAW findFileData;
HANDLE hFind = FindFirstFileW( (LPCWSTR)tpath.toWideString().c_str(), &findFileData );
if( hFind != INVALID_HANDLE_VALUE )
{
if ( hFind != INVALID_HANDLE_VALUE ) {
std::string name( String( findFileData.cFileName ).toUtf8() );
std::string fpath( path + name );
if ( name != "." && name != ".." )
{
files[ name ] = FileInfo( fpath );
if ( name != "." && name != ".." ) {
files[name] = FileInfo( fpath );
}
while( FindNextFileW( hFind, &findFileData ) )
{
while ( FindNextFileW( hFind, &findFileData ) ) {
name = String( findFileData.cFileName ).toUtf8();
fpath = path + name;
if ( name != "." && name != ".." )
{
files[ name ] = FileInfo( fpath );
if ( name != "." && name != ".." ) {
files[name] = FileInfo( fpath );
}
}
@@ -93,32 +84,28 @@ FileInfoMap FileSystem::filesInfoFromPath( const std::string& path )
return files;
}
char FileSystem::getOSSlash()
{
char FileSystem::getOSSlash() {
return '\\';
}
bool FileSystem::isDirectory( const std::string& path )
{
return 0 != ( GetFileAttributesW( String( path ).toWideString().c_str() ) & FILE_ATTRIBUTE_DIRECTORY );
bool FileSystem::isDirectory( const std::string& path ) {
DWORD attrs = GetFileAttributesW( String( path ).toWideString().c_str() );
return attrs != INVALID_FILE_ATTRIBUTES && ( attrs & FILE_ATTRIBUTE_DIRECTORY ) != 0;
}
bool FileSystem::isRemoteFS( const std::string& directory )
{
if ((directory[0] == '\\' || directory[0] == '/') &&
(directory[1] == '\\' || directory[1] == '/'))
{
bool FileSystem::isRemoteFS( const std::string& directory ) {
if ( ( directory[0] == '\\' || directory[0] == '/' ) &&
( directory[1] == '\\' || directory[1] == '/' ) ) {
return true;
}
if ( directory.size() >= 3 )
{
if ( directory.size() >= 3 ) {
return 4 == GetDriveTypeA( directory.substr( 0, 3 ).c_str() );
}
return false;
}
}}
}} // namespace efsw::Platform
#endif

View File

@@ -1,31 +1,30 @@
#ifndef EFSW_FILESYSTEMIMPLWIN_HPP
#define EFSW_FILESYSTEMIMPLWIN_HPP
#include <efsw/base.hpp>
#include <efsw/String.hpp>
#include <efsw/FileInfo.hpp>
#include <efsw/String.hpp>
#include <efsw/base.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
namespace efsw { namespace Platform {
class FileSystem
{
public:
static FileInfoMap filesInfoFromPath( const std::string& path );
class FileSystem {
public:
static FileInfoMap filesInfoFromPath( const std::string& path );
static char getOSSlash();
static char getOSSlash();
static bool isDirectory( const std::string& path );
static bool isDirectory( const std::string& path );
static bool isRemoteFS( const std::string& directory );
static bool isRemoteFS( const std::string& directory );
static bool changeWorkingDirectory( const std::string & path );
static bool changeWorkingDirectory( const std::string& path );
static std::string getCurrentWorkingDirectory();
static std::string getCurrentWorkingDirectory();
};
}}
}} // namespace efsw::Platform
#endif

View File

@@ -4,26 +4,22 @@
namespace efsw { namespace Platform {
MutexImpl::MutexImpl()
{
InitializeCriticalSection(&mMutex);
MutexImpl::MutexImpl() {
InitializeCriticalSection( &mMutex );
}
MutexImpl::~MutexImpl()
{
DeleteCriticalSection(&mMutex);
MutexImpl::~MutexImpl() {
DeleteCriticalSection( &mMutex );
}
void MutexImpl::lock()
{
EnterCriticalSection(&mMutex);
void MutexImpl::lock() {
EnterCriticalSection( &mMutex );
}
void MutexImpl::unlock()
{
LeaveCriticalSection(&mMutex);
void MutexImpl::unlock() {
LeaveCriticalSection( &mMutex );
}
}}
}} // namespace efsw::Platform
#endif

View File

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

View File

@@ -1,23 +1,21 @@
#include <efsw/platform/win/SystemImpl.hpp>
#include <efsw/String.hpp>
#include <efsw/platform/win/SystemImpl.hpp>
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <cstdlib>
#include <windows.h>
namespace efsw { namespace Platform {
void System::sleep( const unsigned long& ms )
{
void System::sleep( const unsigned long& ms ) {
::Sleep( ms );
}
std::string System::getProcessPath()
{
std::string System::getProcessPath() {
// Get path to executable:
WCHAR szDrive[_MAX_DRIVE];
WCHAR szDir[_MAX_DIR];
@@ -25,26 +23,24 @@ std::string System::getProcessPath()
WCHAR szExt[_MAX_DIR];
std::wstring dllName( _MAX_DIR, 0 );
GetModuleFileNameW(0, &dllName[0], _MAX_PATH);
GetModuleFileNameW( 0, &dllName[0], _MAX_PATH );
#ifdef EFSW_COMPILER_MSVC
_wsplitpath_s( dllName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, szExt, _MAX_DIR );
#else
_wsplitpath( dllName.c_str(), szDrive, szDir, szFilename, szExt);
#endif
#ifdef EFSW_COMPILER_MSVC
_wsplitpath_s( dllName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR,
szExt, _MAX_DIR );
#else
_wsplitpath( dllName.c_str(), szDrive, szDir, szFilename, szExt );
#endif
return String( szDrive ).toUtf8() + String( szDir ).toUtf8();
}
void System::maxFD()
{
}
void System::maxFD() {}
Uint64 System::getMaxFD()
{ // Number of ReadDirectory per thread
Uint64 System::getMaxFD() { // Number of ReadDirectory per thread
return 60;
}
}}
}} // namespace efsw::Platform
#endif

View File

@@ -7,19 +7,18 @@
namespace efsw { namespace Platform {
class System
{
public:
static void sleep( const unsigned long& ms );
class System {
public:
static void sleep( const unsigned long& ms );
static std::string getProcessPath();
static std::string getProcessPath();
static void maxFD();
static void maxFD();
static Uint64 getMaxFD();
static Uint64 getMaxFD();
};
}}
}} // namespace efsw::Platform
#endif

View File

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

View File

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

View File

@@ -0,0 +1,164 @@
#include <efsw/efsw.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
const char PATH_SEPARATOR =
#ifdef _WIN32
'\\';
#else
'/';
#endif
bool STOP = false;
void sigend( int sig ) {
printf( "Bye bye" );
STOP = true;
}
void sleepMsecs( int msecs ) {
#ifdef _WIN32
Sleep( msecs );
#else
sleep( msecs );
#endif
}
const char * getActionName( enum efsw_action action ) {
switch ( action ) {
case EFSW_ADD:
return "Add";
case EFSW_MODIFIED:
return "Modified";
case EFSW_DELETE:
return "Delete";
case EFSW_MOVED:
return "Moved";
default:
return "Bad Action";
}
}
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 ));
} else {
printf( "Watch ID %ld DIR (%s) FILE (from file %s to %s) has event %s\n",
watchid, dir, oldFilename, filename, getActionName( action ));
}
}
efsw_watchid handleWatchID( efsw_watchid watchid ) {
switch ( watchid ) {
case EFSW_NOTFOUND:
case EFSW_REPEATED:
case EFSW_OUTOFSCOPE:
case EFSW_REMOTE:
case EFSW_WATCHER_FAILED:
case EFSW_UNSPECIFIED: {
printf( "%s\n", efsw_getlasterror() );
break;
}
default: {
printf( "Added WatchID: %ld\n", watchid );
}
}
return watchid;
}
int main( int argc, char** argv ) {
signal( SIGABRT, sigend );
signal( SIGINT, sigend );
signal( SIGTERM, sigend );
printf("Press ^C to exit demo\n");
bool commonTest = true;
bool useGeneric = false;
char *path = 0;
if ( argc >= 2 ) {
path = argv[1];
struct stat s;
if( stat(path,&s) == 0 && (s.st_mode & S_IFDIR) == S_IFDIR ) {
commonTest = false;
}
if ( argc >= 3 ) {
if ( strcmp( argv[2], "true" ) == 0 ) {
useGeneric = true;
}
}
}
/// create the file watcher object
efsw_watcher fileWatcher = efsw_create( useGeneric );
efsw_follow_symlinks( fileWatcher, false );
efsw_allow_outofscopelinks( fileWatcher, false );
if ( commonTest ) {
char cwd[256];
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 ) );
/// 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 ) );
/// delete the watch
if ( watchID > 0 ) {
sleepMsecs( 1000 );
efsw_removewatch_byid( fileWatcher, watchID );
}
} else {
if ( efsw_addwatch( fileWatcher, path, handleFileAction, true, 0 ) > 0 ) {
efsw_watch( fileWatcher );
printf( "Watching directory: %s\n", path );
if ( useGeneric ) {
printf( "Using generic backend watcher\n" );
}
} else {
printf( "Error trying to watch directory: %s\n", path );
printf( "%s\n", efsw_getlasterror() );
}
}
while ( !STOP ) {
sleepMsecs( 100 );
}
efsw_release( fileWatcher );
return 0;
}

View File

@@ -1,56 +1,59 @@
#include <efsw/efsw.hpp>
#include <efsw/System.hpp>
#include <efsw/FileSystem.hpp>
#include <signal.h>
#include <efsw/System.hpp>
#include <efsw/efsw.hpp>
#include <iostream>
#include <signal.h>
bool STOP = false;
void sigend(int signal)
{
void sigend( int ) {
std::cout << std::endl << "Bye bye" << std::endl;
STOP = true;
}
/// Processes a file action
class UpdateListener : public efsw::FileWatchListener
{
public:
UpdateListener() {}
class UpdateListener : public efsw::FileWatchListener {
public:
UpdateListener() {}
std::string getActionName( efsw::Action action )
{
switch ( action )
{
case efsw::Actions::Add: return "Add";
case efsw::Actions::Modified: return "Modified";
case efsw::Actions::Delete: return "Delete";
case efsw::Actions::Moved: return "Moved";
default: return "Bad Action";
}
std::string getActionName( efsw::Action action ) {
switch ( action ) {
case efsw::Actions::Add:
return "Add";
case efsw::Actions::Modified:
return "Modified";
case efsw::Actions::Delete:
return "Delete";
case efsw::Actions::Moved:
return "Moved";
default:
return "Bad Action";
}
}
void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" )
{
std::cout << "DIR (" << dir + ") FILE (" + ( oldFilename.empty() ? "" : "from file " + oldFilename + " to " ) + filename + ") has event " << getActionName( action ) << std::endl;
}
void handleFileAction( efsw::WatchID watchid, const std::string& dir,
const std::string& filename, efsw::Action action,
std::string oldFilename = "" ) override {
std::cout << "Watch ID " << watchid << " DIR ("
<< dir + ") FILE (" +
( oldFilename.empty() ? "" : "from file " + oldFilename + " to " ) +
filename + ") has event "
<< getActionName( action ) << std::endl;
}
};
efsw::WatchID handleWatchID( efsw::WatchID watchid )
{
switch ( watchid )
{
efsw::WatchID handleWatchID( efsw::WatchID watchid ) {
switch ( watchid ) {
case efsw::Errors::FileNotFound:
case efsw::Errors::FileRepeated:
case efsw::Errors::FileOutOfScope:
case efsw::Errors::FileRemote:
case efsw::Errors::Unspecified:
{
case efsw::Errors::WatcherFailed:
case efsw::Errors::Unspecified: {
std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl;
break;
}
default:
{
default: {
std::cout << "Added WatchID: " << watchid << std::endl;
}
}
@@ -58,11 +61,10 @@ efsw::WatchID handleWatchID( efsw::WatchID watchid )
return watchid;
}
int main(int argc, char **argv)
{
signal( SIGABRT , sigend );
signal( SIGINT , sigend );
signal( SIGTERM , sigend );
int main( int argc, char** argv ) {
signal( SIGABRT, sigend );
signal( SIGINT, sigend );
signal( SIGTERM, sigend );
std::cout << "Press ^C to exit demo" << std::endl;
@@ -70,25 +72,21 @@ int main(int argc, char **argv)
bool useGeneric = false;
std::string path;
if ( argc >= 2 )
{
if ( argc >= 2 ) {
path = std::string( argv[1] );
if ( efsw::FileSystem::isDirectory( path ) )
{
commonTest = false;
if ( efsw::FileSystem::isDirectory( path ) ) {
commonTest = false;
}
if ( argc >= 3 )
{
if ( std::string( argv[2] ) == "true" )
{
if ( argc >= 3 ) {
if ( std::string( argv[2] ) == "true" ) {
useGeneric = true;
}
}
}
UpdateListener * ul = new UpdateListener();
UpdateListener* ul = new UpdateListener();
/// create the file watcher object
efsw::FileWatcher fileWatcher( useGeneric );
@@ -96,54 +94,44 @@ int main(int argc, char **argv)
fileWatcher.followSymlinks( false );
fileWatcher.allowOutOfScopeLinks( false );
if ( commonTest )
{
if ( commonTest ) {
std::string CurPath( efsw::System::getProcessPath() );
std::cout << "CurPath: " << CurPath.c_str() << std::endl;
/// starts watching
fileWatcher.watch();
/// add a watch to the system
handleWatchID( fileWatcher.addWatch( CurPath + "test", ul, true ) );
/// starts watching
fileWatcher.watch();
/// adds another watch after started watching...
efsw::System::sleep( 100 );
efsw::WatchID watchID = handleWatchID( fileWatcher.addWatch( CurPath + "test2", ul, true ) );
efsw::WatchID watchID =
handleWatchID( fileWatcher.addWatch( CurPath + "test2", ul, true ) );
/// delete the watch
if ( watchID > 0 )
{
if ( watchID > 0 ) {
efsw::System::sleep( 1000 );
fileWatcher.removeWatch( watchID );
}
}
else
{
efsw::WatchID err;
if ( ( err = fileWatcher.addWatch( path, ul, true ) ) > 0 )
{
} else {
if ( fileWatcher.addWatch( path, ul, true ) > 0 ) {
fileWatcher.watch();
std::cout << "Watching directory: " << path.c_str() << std::endl;
if ( useGeneric )
{
if ( useGeneric ) {
std::cout << "Using generic backend watcher" << std::endl;
}
}
else
{
} else {
std::cout << "Error trying to watch directory: " << path.c_str() << std::endl;
std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl;
}
}
while( !STOP )
{
while ( !STOP ) {
efsw::System::sleep( 100 );
}