mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Dep/efsw: Update to SpartanJ/efsw@36c1c7004a
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
repo: 78c2ea8c48b213ee0078d6326a1dd719d0844764
|
||||
node: e6afbec564e249771046c714b0c7f2154e4c7fef
|
||||
branch: default
|
||||
latesttag: 1.0.0
|
||||
latesttagdistance: 12
|
||||
changessincelatesttag: 12
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
Entropia File System Watcher
|
||||
Entropia File System Watcher 
|
||||
============================
|
||||
|
||||
[](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.
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
33
dep/efsw/src/efsw/Atomic.hpp
Normal file
33
dep/efsw/src/efsw/Atomic.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
164
dep/efsw/src/test/efsw-test.c
Normal file
164
dep/efsw/src/test/efsw-test.c
Normal 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;
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user