├── .gitignore ├── .hgignore ├── LICENSE ├── README.md ├── include └── efsw │ └── efsw.hpp ├── premake4.lua ├── project ├── qtcreator-linux │ ├── efsw.config │ ├── efsw.creator │ ├── efsw.creator.user │ ├── efsw.files │ └── efsw.includes ├── qtcreator-osx │ ├── efsw.config │ ├── efsw.creator │ ├── efsw.creator.user │ ├── efsw.files │ └── efsw.includes └── qtcreator-win │ ├── efsw.config │ ├── efsw.creator │ ├── efsw.creator.user │ ├── efsw.files │ └── efsw.includes └── src ├── efsw ├── Debug.cpp ├── Debug.hpp ├── DirWatcherGeneric.cpp ├── DirWatcherGeneric.hpp ├── DirectorySnapshot.cpp ├── DirectorySnapshot.hpp ├── DirectorySnapshotDiff.cpp ├── DirectorySnapshotDiff.hpp ├── FileInfo.cpp ├── FileInfo.hpp ├── FileSystem.cpp ├── FileSystem.hpp ├── FileWatcher.cpp ├── FileWatcherFSEvents.cpp ├── FileWatcherFSEvents.hpp ├── FileWatcherGeneric.cpp ├── FileWatcherGeneric.hpp ├── FileWatcherImpl.cpp ├── FileWatcherImpl.hpp ├── FileWatcherInotify.cpp ├── FileWatcherInotify.hpp ├── FileWatcherKqueue.cpp ├── FileWatcherKqueue.hpp ├── FileWatcherWin32.cpp ├── FileWatcherWin32.hpp ├── Log.cpp ├── Mutex.cpp ├── Mutex.hpp ├── String.cpp ├── String.hpp ├── System.cpp ├── System.hpp ├── Thread.cpp ├── Thread.hpp ├── Utf.hpp ├── Utf.inl ├── Watcher.cpp ├── Watcher.hpp ├── WatcherFSEvents.cpp ├── WatcherFSEvents.hpp ├── WatcherGeneric.cpp ├── WatcherGeneric.hpp ├── WatcherInotify.cpp ├── WatcherInotify.hpp ├── WatcherKqueue.cpp ├── WatcherKqueue.hpp ├── WatcherWin32.cpp ├── WatcherWin32.hpp ├── base.hpp ├── platform │ ├── platformimpl.hpp │ ├── posix │ │ ├── FileSystemImpl.cpp │ │ ├── FileSystemImpl.hpp │ │ ├── MutexImpl.cpp │ │ ├── MutexImpl.hpp │ │ ├── SystemImpl.cpp │ │ ├── SystemImpl.hpp │ │ ├── ThreadImpl.cpp │ │ └── ThreadImpl.hpp │ └── win │ │ ├── FileSystemImpl.cpp │ │ ├── FileSystemImpl.hpp │ │ ├── MutexImpl.cpp │ │ ├── MutexImpl.hpp │ │ ├── SystemImpl.cpp │ │ ├── SystemImpl.hpp │ │ ├── ThreadImpl.cpp │ │ └── ThreadImpl.hpp └── sophist.h └── test └── efsw-test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .hg 2 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | bin/* 3 | obj/* 4 | make/* 5 | lib/* 6 | *.DS_Store* 7 | project/qtcreator-osx/efsw.creator.user.2.6pre1 8 | project/qtcreator-osx/efsw.creator.user.4bdfc43 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Martín Lucas Golini 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) 22 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Entropia File System Watcher 2 | ============================ 3 | **efsw** is a C++ cross-platform file system watcher and notifier. 4 | 5 | **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. 6 | 7 | **efsw** supports recursive directories watch, tracking the entire sub directory tree. 8 | 9 | **efsw** currently supports the following platforms: 10 | 11 | * Linux via [inotify](http://en.wikipedia.org/wiki/Inotify) 12 | 13 | * Windows via [I/O Completion Ports](http://en.wikipedia.org/wiki/IOCP) 14 | 15 | * Mac OS X via [FSEvents](http://en.wikipedia.org/wiki/FSEvents) or [kqueue](http://en.wikipedia.org/wiki/Kqueue) 16 | 17 | * FreeBSD/BSD via [kqueue](http://en.wikipedia.org/wiki/Kqueue) 18 | 19 | * OS-independent generic watcher 20 | (polling the disk for directory snapshots and comparing them periodically) 21 | 22 | If any of the backend fails to start by any reason, it will fallback to the OS-independent implementation. 23 | This should never happen, except for the Kqueue implementation, see `Platform limitations and clarifications`. 24 | 25 | **Code License** 26 | -------------- 27 | [MIT License](http://www.opensource.org/licenses/mit-license.php) 28 | 29 | **Some example code:** 30 | -------------------- 31 | 32 | :::c++ 33 | // Inherits from the abstract listener class, and implements the the file action handler 34 | class UpdateListener : public efsw::FileWatchListener 35 | { 36 | public: 37 | UpdateListener() {} 38 | 39 | void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" ) 40 | { 41 | switch( action ) 42 | { 43 | case efsw::Actions::Add: 44 | std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Added" << std::endl; 45 | break; 46 | case efsw::Actions::Delete: 47 | std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Delete" << std::endl; 48 | break; 49 | case efsw::Actions::Modified: 50 | std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Modified" << std::endl; 51 | break; 52 | case efsw::Actions::Moved: 53 | std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Moved from (" << oldFilename << ")" << std::endl; 54 | break; 55 | default: 56 | std::cout << "Should never happen!" << std::endl; 57 | } 58 | } 59 | }; 60 | 61 | // Create the file system watcher instance 62 | // efsw::FileWatcher allow a first boolean parameter that indicates if it should start with the generic file watcher instead of the platform specific backend 63 | efsw::FileWatcher * fileWatcher = new efsw::FileWatcher(); 64 | 65 | // Create the instance of your efsw::FileWatcherListener implementation 66 | UpdateListener * listener = new UpdateListener(); 67 | 68 | // Add a folder to watch, and get the efsw::WatchID 69 | // It will watch the /tmp folder recursively ( the third parameter indicates that is recursive ) 70 | // Reporting the files and directories changes to the instance of the listener 71 | efsw::WatchID watchID = fileWatcher->addWatch( "/tmp", listener, true ); 72 | 73 | // Adds another directory to watch. This time as non-recursive. 74 | efsw::WatchID watchID2 = fileWatcher->addWatch( "/usr", listener, false ); 75 | 76 | // Start watching asynchronously the directories 77 | fileWatcher.watch(); 78 | 79 | // Remove the second watcher added 80 | // 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 ) 81 | fileWatcher->removeWatch( watchID2 ); 82 | 83 | **Dependencies** 84 | -------------- 85 | None :) 86 | 87 | **Compiling** 88 | ------------ 89 | To generate project files you will need to [download and install](http://industriousone.com/premake/download) [Premake](http://industriousone.com/what-premake) 90 | 91 | 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: 92 | 93 | `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 ). 94 | 95 | or 96 | 97 | `premake4 vs2010` to generate Visual Studio 2010 project. 98 | 99 | or 100 | 101 | `premake4 xcode4` to generate Xcode 4 project. 102 | 103 | 104 | **Platform limitations and clarifications** 105 | ------------------------------------------- 106 | 107 | Windows and FSEvents Mac OS X implementation can't follow symlinks ( it will ignore followSymlinks() and allowOutOfScopeLinks() ). 108 | 109 | 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. 110 | 111 | 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. 112 | 113 | 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. 114 | 115 | Generic watcher relies on the inode information to detect file and directories renames/move. Since Windows has no concept of inodes as Unix-y platforms do, there is no current reliable way of determining file/directory movement on Windows without help from the Windows API. 116 | 117 | 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. 118 | 119 | 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. 120 | 121 | **Clarifications** 122 | ---------------- 123 | 124 | This software started as a fork of the [simplefilewatcher](http://code.google.com/p/simplefilewatcher/) by James Wynn (james[at]jameswynn.com), [MIT licensed](http://www.opensource.org/licenses/mit-license.html). 125 | 126 | The icon used for the project is part of the [Haiku®'s Icons](http://www.haiku-inc.org/haiku-icons.html), [MIT licensed](http://www.opensource.org/licenses/mit-license.html). 127 | -------------------------------------------------------------------------------- /include/efsw/efsw.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | @author Martín Lucas Golini 3 | 4 | Copyright (c) 2012 Martín Lucas Golini 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | 24 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) 25 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. 26 | */ 27 | 28 | #ifndef ESFW_HPP 29 | #define ESFW_HPP 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #if defined(_WIN32) 36 | #ifdef EFSW_DYNAMIC 37 | // Windows platforms 38 | #ifdef EFSW_EXPORTS 39 | // From DLL side, we must export 40 | #define EFSW_API __declspec(dllexport) 41 | #else 42 | // From client application side, we must import 43 | #define EFSW_API __declspec(dllimport) 44 | #endif 45 | #else 46 | // No specific directive needed for static build 47 | #ifndef EFSW_API 48 | #define EFSW_API 49 | #endif 50 | #endif 51 | #else 52 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) 53 | #define EFSW_API __attribute__ ((visibility("default"))) 54 | #endif 55 | 56 | // Other platforms don't need to define anything 57 | #ifndef EFSW_API 58 | #define EFSW_API 59 | #endif 60 | #endif 61 | 62 | namespace efsw { 63 | 64 | /// Type for a watch id 65 | typedef long WatchID; 66 | 67 | // forward declarations 68 | class FileWatcherImpl; 69 | class FileWatchListener; 70 | 71 | /// Actions to listen for. Rename will send two events, one for 72 | /// the deletion of the old file, and one for the creation of the 73 | /// new file. 74 | namespace Actions { 75 | enum Action 76 | { 77 | /// Sent when a file is created or renamed 78 | Add = 1, 79 | /// Sent when a file is deleted or renamed 80 | Delete = 2, 81 | /// Sent when a file is modified 82 | Modified = 3, 83 | /// Sent when a file is moved 84 | Moved = 4 85 | }; 86 | } 87 | typedef Actions::Action Action; 88 | 89 | /// Errors log namespace 90 | namespace Errors { 91 | 92 | enum Error 93 | { 94 | FileNotFound = -1, 95 | FileRepeated = -2, 96 | FileOutOfScope = -3, 97 | FileNotReadable = -4, 98 | Unspecified = -5 99 | }; 100 | 101 | class EFSW_API Log 102 | { 103 | public: 104 | /// @return The last error logged 105 | static std::string getLastErrorLog(); 106 | 107 | /// Creates an error of the type specified 108 | static Error createLastError( Error err, std::string log ); 109 | }; 110 | 111 | } 112 | typedef Errors::Error Error; 113 | 114 | /// Listens to files and directories and dispatches events 115 | /// to notify the listener of files and directories changes. 116 | /// @class FileWatcher 117 | class EFSW_API FileWatcher 118 | { 119 | public: 120 | /// Default constructor, will use the default platform file watcher 121 | FileWatcher(); 122 | 123 | /// Constructor that lets you force the use of the Generic File Watcher 124 | FileWatcher( bool useGenericFileWatcher ); 125 | 126 | virtual ~FileWatcher(); 127 | 128 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. 129 | /// For backwards compatibility. 130 | /// On error returns WatchID with Error type. 131 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher); 132 | 133 | /// Add a directory watch 134 | /// On error returns WatchID with Error type. 135 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 136 | 137 | /// Remove a directory watch. This is a brute force search O(nlogn). 138 | void removeWatch(const std::string& directory); 139 | 140 | /// Remove a directory watch. This is a map lookup O(logn). 141 | void removeWatch(WatchID watchid); 142 | 143 | /// Starts watching ( in other thread ) 144 | void watch(); 145 | 146 | /// @return Returns a list of the directories that are being watched 147 | std::list directories(); 148 | 149 | /** Allow recursive watchers to follow symbolic links to other directories 150 | * followSymlinks is disabled by default 151 | */ 152 | void followSymlinks( bool follow ); 153 | 154 | /** @return If can follow symbolic links to directorioes */ 155 | const bool& followSymlinks() const; 156 | 157 | /** When enable this it will allow symlinks to watch recursively out of the pointed directory. 158 | * follorSymlinks must be enabled to this work. 159 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed, 160 | * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion. 161 | * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ). 162 | * Buy enabling out of scope links, it will allow this behavior. 163 | * allowOutOfScopeLinks are disabled by default. 164 | */ 165 | void allowOutOfScopeLinks( bool allow ); 166 | 167 | /// @return Returns if out of scope links are allowed 168 | const bool& allowOutOfScopeLinks() const; 169 | private: 170 | /// The implementation 171 | FileWatcherImpl * mImpl; 172 | bool mFollowSymlinks; 173 | bool mOutOfScopeLinks; 174 | }; 175 | 176 | /// Basic interface for listening for file events. 177 | /// @class FileWatchListener 178 | class FileWatchListener 179 | { 180 | public: 181 | FileWatchListener() {} 182 | 183 | virtual ~FileWatchListener() {} 184 | 185 | /// Handles the action file action 186 | /// @param watchid The watch id for the directory 187 | /// @param dir The directory 188 | /// @param filename The filename that was accessed (not full path) 189 | /// @param action Action that was performed 190 | /// @param oldFilename The name of the file or directory moved 191 | virtual void handleFileAction(WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" ) = 0; 192 | 193 | }; 194 | 195 | } 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /premake4.lua: -------------------------------------------------------------------------------- 1 | function args_contains( element ) 2 | for _, value in pairs(_ARGS) do 3 | if value == element then 4 | return true 5 | end 6 | end 7 | return false 8 | end 9 | 10 | solution "efsw" 11 | location("./make/" .. os.get() .. "/") 12 | targetdir("./bin") 13 | configurations { "debug", "release" } 14 | 15 | if os.is("windows") then 16 | osfiles = "src/efsw/platform/win/*.cpp" 17 | else 18 | osfiles = "src/efsw/platform/posix/*.cpp" 19 | end 20 | 21 | -- This is for testing in other platforms that don't support kqueue 22 | if args_contains( "kqueue" ) then 23 | links { "kqueue" } 24 | defines { "EFSW_KQUEUE" } 25 | printf("Forced Kqueue backend build.") 26 | end 27 | 28 | -- Activates verbose mode 29 | if args_contains( "verbose" ) then 30 | defines { "EFSW_VERBOSE" } 31 | end 32 | 33 | if os.is("macosx") then 34 | -- Premake 4.4 needed for this 35 | if not string.match(_PREMAKE_VERSION, "^4.[123]") then 36 | local ver = os.getversion(); 37 | 38 | if not ( ver.majorversion >= 10 and ver.minorversion >= 5 ) then 39 | defines { "EFSW_FSEVENTS_NOT_SUPPORTED" } 40 | end 41 | end 42 | end 43 | 44 | objdir("obj/" .. os.get() .. "/") 45 | 46 | project "efsw-static-lib" 47 | kind "StaticLib" 48 | language "C++" 49 | targetdir("./lib") 50 | includedirs { "include", "src" } 51 | files { "src/efsw/*.cpp", osfiles } 52 | 53 | configuration "debug" 54 | defines { "DEBUG" } 55 | flags { "Symbols" } 56 | buildoptions{ "-Wall -pedantic -Wno-long-long" } 57 | targetname "efsw-static-debug" 58 | 59 | configuration "release" 60 | defines { "NDEBUG" } 61 | flags { "Optimize" } 62 | targetname "efsw-static-release" 63 | 64 | project "efsw-test" 65 | kind "ConsoleApp" 66 | language "C++" 67 | links { "efsw-static-lib" } 68 | files { "src/test/*.cpp" } 69 | includedirs { "include", "src" } 70 | 71 | if not os.is("windows") and not os.is("haiku") then 72 | links { "pthread" } 73 | end 74 | 75 | if os.is("macosx") then 76 | links { "CoreFoundation.framework", "CoreServices.framework" } 77 | end 78 | 79 | configuration "debug" 80 | defines { "DEBUG" } 81 | flags { "Symbols" } 82 | buildoptions{ "-Wall" } 83 | targetname "efsw-test-debug" 84 | 85 | configuration "release" 86 | defines { "NDEBUG" } 87 | flags { "Optimize" } 88 | buildoptions{ "-Wall" } 89 | targetname "efsw-test-release" 90 | 91 | project "efsw-shared-lib" 92 | kind "SharedLib" 93 | language "C++" 94 | targetdir("./lib") 95 | includedirs { "include", "src" } 96 | files { "src/efsw/*.cpp", osfiles } 97 | defines { "EFSW_DYNAMIC", "EFSW_EXPORTS" } 98 | 99 | configuration "debug" 100 | defines { "DEBUG" } 101 | buildoptions{ "-Wall" } 102 | flags { "Symbols" } 103 | targetname "efsw-debug" 104 | 105 | configuration "release" 106 | defines { "NDEBUG" } 107 | flags { "Optimize" } 108 | buildoptions{ "-Wall" } 109 | targetname "efsw" 110 | -------------------------------------------------------------------------------- /project/qtcreator-linux/efsw.config: -------------------------------------------------------------------------------- 1 | // ADD PREDEFINED MACROS HERE! 2 | -------------------------------------------------------------------------------- /project/qtcreator-linux/efsw.creator: -------------------------------------------------------------------------------- 1 | [General] 2 | -------------------------------------------------------------------------------- /project/qtcreator-linux/efsw.files: -------------------------------------------------------------------------------- 1 | ../../include/efsw/efsw.hpp 2 | ../../src/efsw/FileWatcher.cpp 3 | ../../src/efsw/FileWatcherInotify.cpp 4 | ../../src/efsw/FileWatcherKqueue.cpp 5 | ../../src/efsw/FileWatcherWin32.cpp 6 | ../../src/efsw/FileWatcherWin32.hpp 7 | ../../src/efsw/FileWatcherKqueue.hpp 8 | ../../src/efsw/FileWatcherInotify.hpp 9 | ../../src/efsw/FileWatcherImpl.hpp 10 | ../../src/efsw/FileWatcherWin32.cpp 11 | ../../src/efsw/FileWatcherKqueue.cpp 12 | ../../src/efsw/FileWatcherInotify.cpp 13 | ../../src/efsw/FileWatcher.cpp 14 | ../../src/efsw/Thread.cpp 15 | ../../src/efsw/Mutex.cpp 16 | ../../src/efsw/System.cpp 17 | ../../src/efsw/platform/platformimpl.hpp 18 | ../../src/efsw/platform/posix/ThreadImpl.hpp 19 | ../../src/efsw/platform/posix/MutexImpl.hpp 20 | ../../src/efsw/platform/posix/SystemImpl.hpp 21 | ../../src/efsw/platform/posix/ThreadImpl.cpp 22 | ../../src/efsw/platform/posix/MutexImpl.cpp 23 | ../../src/efsw/platform/posix/SystemImpl.cpp 24 | ../../src/efsw/platform/win/ThreadImpl.hpp 25 | ../../src/efsw/platform/win/MutexImpl.hpp 26 | ../../src/efsw/platform/win/SystemImpl.hpp 27 | ../../src/efsw/platform/win/ThreadImpl.cpp 28 | ../../src/efsw/platform/win/MutexImpl.cpp 29 | ../../src/efsw/platform/win/SystemImpl.cpp 30 | ../../src/efsw/base.hpp 31 | ../../src/efsw/FileWatcherGeneric.hpp 32 | ../../src/efsw/FileWatcherGeneric.cpp 33 | ../../src/efsw/FileSystem.cpp 34 | ../../src/efsw/platform/posix/FileSystemImpl.hpp 35 | ../../src/efsw/platform/posix/FileSystemImpl.cpp 36 | ../../src/efsw/platform/win/FileSystemImpl.hpp 37 | ../../src/efsw/platform/win/FileSystemImpl.cpp 38 | ../../src/efsw/FileInfo.cpp 39 | ../../src/efsw/base.hpp 40 | ../../src/efsw/Thread.hpp 41 | ../../src/efsw/System.hpp 42 | ../../src/efsw/Mutex.hpp 43 | ../../src/efsw/FileWatcherWin32.hpp 44 | ../../src/efsw/FileWatcherKqueue.hpp 45 | ../../src/efsw/FileWatcherInotify.hpp 46 | ../../src/efsw/FileWatcherImpl.hpp 47 | ../../src/efsw/FileWatcherGeneric.hpp 48 | ../../src/efsw/FileSystem.hpp 49 | ../../src/efsw/FileInfo.hpp 50 | ../../src/efsw/Thread.cpp 51 | ../../src/efsw/System.cpp 52 | ../../src/efsw/Mutex.cpp 53 | ../../src/efsw/FileWatcherWin32.cpp 54 | ../../src/efsw/FileWatcherKqueue.cpp 55 | ../../src/efsw/FileWatcherInotify.cpp 56 | ../../src/efsw/FileWatcherGeneric.cpp 57 | ../../src/efsw/FileWatcher.cpp 58 | ../../src/efsw/FileSystem.cpp 59 | ../../src/efsw/FileInfo.cpp 60 | ../../src/efsw/sophist.h 61 | ../../src/efsw/base.hpp 62 | ../../src/efsw/Utf.hpp 63 | ../../src/efsw/Thread.hpp 64 | ../../src/efsw/System.hpp 65 | ../../src/efsw/String.hpp 66 | ../../src/efsw/Mutex.hpp 67 | ../../src/efsw/FileWatcherWin32.hpp 68 | ../../src/efsw/FileWatcherKqueue.hpp 69 | ../../src/efsw/FileWatcherInotify.hpp 70 | ../../src/efsw/FileWatcherImpl.hpp 71 | ../../src/efsw/FileWatcherGeneric.hpp 72 | ../../src/efsw/FileSystem.hpp 73 | ../../src/efsw/FileInfo.hpp 74 | ../../src/efsw/Utf.inl 75 | ../../src/efsw/Thread.cpp 76 | ../../src/efsw/System.cpp 77 | ../../src/efsw/String.cpp 78 | ../../src/efsw/Mutex.cpp 79 | ../../src/efsw/FileWatcherWin32.cpp 80 | ../../src/efsw/FileWatcherKqueue.cpp 81 | ../../src/efsw/FileWatcherInotify.cpp 82 | ../../src/efsw/FileWatcherGeneric.cpp 83 | ../../src/efsw/FileWatcher.cpp 84 | ../../src/efsw/FileSystem.cpp 85 | ../../src/efsw/FileInfo.cpp 86 | ../../src/test/efsw-test.cpp 87 | ../../premake4.lua 88 | ../../src/efsw/WatcherKqueue.hpp 89 | ../../src/efsw/WatcherKqueue.cpp 90 | ../../src/efsw/Debug.hpp 91 | ../../src/efsw/Debug.cpp 92 | ../../src/efsw/WatcherGeneric.hpp 93 | ../../src/efsw/WatcherGeneric.cpp 94 | ../../src/efsw/DirWatcherGeneric.hpp 95 | ../../src/efsw/DirWatcherGeneric.cpp 96 | ../../src/efsw/Log.cpp 97 | ../../src/efsw/WatcherInotify.hpp 98 | ../../src/efsw/WatcherInotify.cpp 99 | ../../src/efsw/FileWatcherImpl.cpp 100 | ../../src/efsw/DirectorySnapshot.hpp 101 | ../../src/efsw/DirectorySnapshot.cpp 102 | ../../src/efsw/DirectorySnapshotDiff.hpp 103 | ../../src/efsw/DirectorySnapshotDiff.cpp 104 | ../../src/efsw/WatcherFSEvents.hpp 105 | ../../src/efsw/FileWatcherFSEvents.hpp 106 | ../../src/efsw/WatcherFSEvents.cpp 107 | ../../src/efsw/FileWatcherFSEvents.cpp 108 | ../../src/efsw/Watcher.hpp 109 | ../../src/efsw/Watcher.cpp 110 | ../../src/efsw/WatcherWin32.hpp 111 | ../../src/efsw/WatcherWin32.cpp 112 | ../../README.md 113 | -------------------------------------------------------------------------------- /project/qtcreator-linux/efsw.includes: -------------------------------------------------------------------------------- 1 | src 2 | include -------------------------------------------------------------------------------- /project/qtcreator-osx/efsw.config: -------------------------------------------------------------------------------- 1 | // ADD PREDEFINED MACROS HERE! 2 | #define EFSW_FSEVENTS_SUPPORTED 3 | -------------------------------------------------------------------------------- /project/qtcreator-osx/efsw.creator: -------------------------------------------------------------------------------- 1 | [General] 2 | -------------------------------------------------------------------------------- /project/qtcreator-osx/efsw.files: -------------------------------------------------------------------------------- 1 | ../../include/efsw/efsw.hpp 2 | ../../src/efsw/FileWatcher.cpp 3 | ../../src/efsw/FileWatcherInotify.cpp 4 | ../../src/efsw/FileWatcherKqueue.cpp 5 | ../../src/efsw/FileWatcherWin32.cpp 6 | ../../src/efsw/FileWatcherWin32.hpp 7 | ../../src/efsw/FileWatcherKqueue.hpp 8 | ../../src/efsw/FileWatcherInotify.hpp 9 | ../../src/efsw/FileWatcherImpl.hpp 10 | ../../src/efsw/FileWatcherWin32.cpp 11 | ../../src/efsw/FileWatcherKqueue.cpp 12 | ../../src/efsw/FileWatcherInotify.cpp 13 | ../../src/efsw/FileWatcher.cpp 14 | ../../src/efsw/Thread.cpp 15 | ../../src/efsw/Mutex.cpp 16 | ../../src/efsw/System.cpp 17 | ../../src/efsw/platform/platformimpl.hpp 18 | ../../src/efsw/platform/posix/ThreadImpl.hpp 19 | ../../src/efsw/platform/posix/MutexImpl.hpp 20 | ../../src/efsw/platform/posix/SystemImpl.hpp 21 | ../../src/efsw/platform/posix/ThreadImpl.cpp 22 | ../../src/efsw/platform/posix/MutexImpl.cpp 23 | ../../src/efsw/platform/posix/SystemImpl.cpp 24 | ../../src/efsw/platform/win/ThreadImpl.hpp 25 | ../../src/efsw/platform/win/MutexImpl.hpp 26 | ../../src/efsw/platform/win/SystemImpl.hpp 27 | ../../src/efsw/platform/win/ThreadImpl.cpp 28 | ../../src/efsw/platform/win/MutexImpl.cpp 29 | ../../src/efsw/platform/win/SystemImpl.cpp 30 | ../../src/efsw/base.hpp 31 | ../../src/efsw/FileWatcherGeneric.hpp 32 | ../../src/efsw/FileWatcherGeneric.cpp 33 | ../../src/efsw/FileSystem.cpp 34 | ../../src/efsw/platform/posix/FileSystemImpl.hpp 35 | ../../src/efsw/platform/posix/FileSystemImpl.cpp 36 | ../../src/efsw/platform/win/FileSystemImpl.hpp 37 | ../../src/efsw/platform/win/FileSystemImpl.cpp 38 | ../../src/efsw/FileInfo.cpp 39 | ../../src/efsw/base.hpp 40 | ../../src/efsw/Thread.hpp 41 | ../../src/efsw/System.hpp 42 | ../../src/efsw/Mutex.hpp 43 | ../../src/efsw/FileWatcherWin32.hpp 44 | ../../src/efsw/FileWatcherKqueue.hpp 45 | ../../src/efsw/FileWatcherInotify.hpp 46 | ../../src/efsw/FileWatcherImpl.hpp 47 | ../../src/efsw/FileWatcherGeneric.hpp 48 | ../../src/efsw/FileSystem.hpp 49 | ../../src/efsw/FileInfo.hpp 50 | ../../src/efsw/Thread.cpp 51 | ../../src/efsw/System.cpp 52 | ../../src/efsw/Mutex.cpp 53 | ../../src/efsw/FileWatcherWin32.cpp 54 | ../../src/efsw/FileWatcherKqueue.cpp 55 | ../../src/efsw/FileWatcherInotify.cpp 56 | ../../src/efsw/FileWatcherGeneric.cpp 57 | ../../src/efsw/FileWatcher.cpp 58 | ../../src/efsw/FileSystem.cpp 59 | ../../src/efsw/FileInfo.cpp 60 | ../../src/efsw/sophist.h 61 | ../../src/efsw/base.hpp 62 | ../../src/efsw/Utf.hpp 63 | ../../src/efsw/Thread.hpp 64 | ../../src/efsw/System.hpp 65 | ../../src/efsw/String.hpp 66 | ../../src/efsw/Mutex.hpp 67 | ../../src/efsw/FileWatcherWin32.hpp 68 | ../../src/efsw/FileWatcherKqueue.hpp 69 | ../../src/efsw/FileWatcherInotify.hpp 70 | ../../src/efsw/FileWatcherImpl.hpp 71 | ../../src/efsw/FileWatcherGeneric.hpp 72 | ../../src/efsw/FileSystem.hpp 73 | ../../src/efsw/FileInfo.hpp 74 | ../../src/efsw/Utf.inl 75 | ../../src/efsw/Thread.cpp 76 | ../../src/efsw/System.cpp 77 | ../../src/efsw/String.cpp 78 | ../../src/efsw/Mutex.cpp 79 | ../../src/efsw/FileWatcherWin32.cpp 80 | ../../src/efsw/FileWatcherKqueue.cpp 81 | ../../src/efsw/FileWatcherInotify.cpp 82 | ../../src/efsw/FileWatcherGeneric.cpp 83 | ../../src/efsw/FileWatcher.cpp 84 | ../../src/efsw/FileSystem.cpp 85 | ../../src/efsw/FileInfo.cpp 86 | ../../src/test/efsw-test.cpp 87 | ../../premake4.lua 88 | ../../src/efsw/WatcherKqueue.hpp 89 | ../../src/efsw/WatcherKqueue.cpp 90 | ../../src/efsw/WatcherKqueue.hpp 91 | ../../src/efsw/WatcherInotify.hpp 92 | ../../src/efsw/WatcherGeneric.hpp 93 | ../../src/efsw/Utf.hpp 94 | ../../src/efsw/Thread.hpp 95 | ../../src/efsw/System.hpp 96 | ../../src/efsw/String.hpp 97 | ../../src/efsw/sophist.h 98 | ../../src/efsw/Mutex.hpp 99 | ../../src/efsw/FileWatcherWin32.hpp 100 | ../../src/efsw/FileWatcherKqueue.hpp 101 | ../../src/efsw/FileWatcherInotify.hpp 102 | ../../src/efsw/FileWatcherImpl.hpp 103 | ../../src/efsw/FileWatcherGeneric.hpp 104 | ../../src/efsw/FileSystem.hpp 105 | ../../src/efsw/FileInfo.hpp 106 | ../../src/efsw/DirWatcherGeneric.hpp 107 | ../../src/efsw/Debug.hpp 108 | ../../src/efsw/base.hpp 109 | ../../src/efsw/WatcherKqueue.cpp 110 | ../../src/efsw/WatcherInotify.cpp 111 | ../../src/efsw/WatcherGeneric.cpp 112 | ../../src/efsw/Utf.inl 113 | ../../src/efsw/Thread.cpp 114 | ../../src/efsw/System.cpp 115 | ../../src/efsw/String.cpp 116 | ../../src/efsw/Mutex.cpp 117 | ../../src/efsw/Log.cpp 118 | ../../src/efsw/FileWatcherWin32.cpp 119 | ../../src/efsw/FileWatcherKqueue.cpp 120 | ../../src/efsw/FileWatcherInotify.cpp 121 | ../../src/efsw/FileWatcherGeneric.cpp 122 | ../../src/efsw/FileWatcher.cpp 123 | ../../src/efsw/FileSystem.cpp 124 | ../../src/efsw/FileInfo.cpp 125 | ../../src/efsw/DirWatcherGeneric.cpp 126 | ../../src/efsw/Debug.cpp 127 | ../../src/efsw/FileWatcherImpl.cpp 128 | ../../src/efsw/DirectorySnapshotDiff.hpp 129 | ../../src/efsw/DirectorySnapshot.hpp 130 | ../../src/efsw/DirectorySnapshotDiff.cpp 131 | ../../src/efsw/DirectorySnapshot.cpp 132 | ../../src/efsw/WatcherFSEvents.hpp 133 | ../../src/efsw/FileWatcherFSEvents.hpp 134 | ../../src/efsw/WatcherFSEvents.cpp 135 | ../../src/efsw/FileWatcherFSEvents.cpp 136 | ../../src/efsw/WatcherWin32.hpp 137 | ../../src/efsw/WatcherKqueue.hpp 138 | ../../src/efsw/WatcherInotify.hpp 139 | ../../src/efsw/WatcherGeneric.hpp 140 | ../../src/efsw/WatcherFSEvents.hpp 141 | ../../src/efsw/Watcher.hpp 142 | ../../src/efsw/Utf.hpp 143 | ../../src/efsw/Thread.hpp 144 | ../../src/efsw/System.hpp 145 | ../../src/efsw/String.hpp 146 | ../../src/efsw/sophist.h 147 | ../../src/efsw/Mutex.hpp 148 | ../../src/efsw/FileWatcherWin32.hpp 149 | ../../src/efsw/FileWatcherKqueue.hpp 150 | ../../src/efsw/FileWatcherInotify.hpp 151 | ../../src/efsw/FileWatcherImpl.hpp 152 | ../../src/efsw/FileWatcherGeneric.hpp 153 | ../../src/efsw/FileWatcherFSEvents.hpp 154 | ../../src/efsw/FileSystem.hpp 155 | ../../src/efsw/FileInfo.hpp 156 | ../../src/efsw/DirWatcherGeneric.hpp 157 | ../../src/efsw/DirectorySnapshotDiff.hpp 158 | ../../src/efsw/DirectorySnapshot.hpp 159 | ../../src/efsw/Debug.hpp 160 | ../../src/efsw/base.hpp 161 | ../../src/efsw/WatcherWin32.cpp 162 | ../../src/efsw/WatcherKqueue.cpp 163 | ../../src/efsw/WatcherInotify.cpp 164 | ../../src/efsw/WatcherGeneric.cpp 165 | ../../src/efsw/WatcherFSEvents.cpp 166 | ../../src/efsw/Watcher.cpp 167 | ../../src/efsw/Utf.inl 168 | ../../src/efsw/Thread.cpp 169 | ../../src/efsw/System.cpp 170 | ../../src/efsw/String.cpp 171 | ../../src/efsw/Mutex.cpp 172 | ../../src/efsw/Log.cpp 173 | ../../src/efsw/FileWatcherWin32.cpp 174 | ../../src/efsw/FileWatcherKqueue.cpp 175 | ../../src/efsw/FileWatcherInotify.cpp 176 | ../../src/efsw/FileWatcherImpl.cpp 177 | ../../src/efsw/FileWatcherGeneric.cpp 178 | ../../src/efsw/FileWatcherFSEvents.cpp 179 | ../../src/efsw/FileWatcher.cpp 180 | ../../src/efsw/FileSystem.cpp 181 | ../../src/efsw/FileInfo.cpp 182 | ../../src/efsw/DirWatcherGeneric.cpp 183 | ../../src/efsw/DirectorySnapshotDiff.cpp 184 | ../../src/efsw/DirectorySnapshot.cpp 185 | ../../src/efsw/Debug.cpp 186 | -------------------------------------------------------------------------------- /project/qtcreator-osx/efsw.includes: -------------------------------------------------------------------------------- 1 | src 2 | include -------------------------------------------------------------------------------- /project/qtcreator-win/efsw.config: -------------------------------------------------------------------------------- 1 | // ADD PREDEFINED MACROS HERE! 2 | -------------------------------------------------------------------------------- /project/qtcreator-win/efsw.creator: -------------------------------------------------------------------------------- 1 | [General] 2 | -------------------------------------------------------------------------------- /project/qtcreator-win/efsw.files: -------------------------------------------------------------------------------- 1 | ../../include/efsw/efsw.hpp 2 | ../../src/efsw/FileWatcher.cpp 3 | ../../src/efsw/FileWatcherInotify.cpp 4 | ../../src/efsw/FileWatcherKqueue.cpp 5 | ../../src/efsw/FileWatcherWin32.cpp 6 | ../../src/efsw/FileWatcherWin32.hpp 7 | ../../src/efsw/FileWatcherKqueue.hpp 8 | ../../src/efsw/FileWatcherInotify.hpp 9 | ../../src/efsw/FileWatcherImpl.hpp 10 | ../../src/efsw/FileWatcherWin32.cpp 11 | ../../src/efsw/FileWatcherKqueue.cpp 12 | ../../src/efsw/FileWatcherInotify.cpp 13 | ../../src/efsw/FileWatcher.cpp 14 | ../../src/efsw/Thread.cpp 15 | ../../src/efsw/Mutex.cpp 16 | ../../src/efsw/System.cpp 17 | ../../src/efsw/platform/platformimpl.hpp 18 | ../../src/efsw/platform/posix/ThreadImpl.hpp 19 | ../../src/efsw/platform/posix/MutexImpl.hpp 20 | ../../src/efsw/platform/posix/SystemImpl.hpp 21 | ../../src/efsw/platform/posix/ThreadImpl.cpp 22 | ../../src/efsw/platform/posix/MutexImpl.cpp 23 | ../../src/efsw/platform/posix/SystemImpl.cpp 24 | ../../src/efsw/platform/win/ThreadImpl.hpp 25 | ../../src/efsw/platform/win/MutexImpl.hpp 26 | ../../src/efsw/platform/win/SystemImpl.hpp 27 | ../../src/efsw/platform/win/ThreadImpl.cpp 28 | ../../src/efsw/platform/win/MutexImpl.cpp 29 | ../../src/efsw/platform/win/SystemImpl.cpp 30 | ../../src/efsw/base.hpp 31 | ../../src/efsw/FileWatcherGeneric.hpp 32 | ../../src/efsw/FileWatcherGeneric.cpp 33 | ../../src/efsw/FileSystem.cpp 34 | ../../src/efsw/platform/posix/FileSystemImpl.hpp 35 | ../../src/efsw/platform/posix/FileSystemImpl.cpp 36 | ../../src/efsw/platform/win/FileSystemImpl.hpp 37 | ../../src/efsw/platform/win/FileSystemImpl.cpp 38 | ../../src/efsw/FileInfo.cpp 39 | ../../src/efsw/base.hpp 40 | ../../src/efsw/Thread.hpp 41 | ../../src/efsw/System.hpp 42 | ../../src/efsw/Mutex.hpp 43 | ../../src/efsw/FileWatcherWin32.hpp 44 | ../../src/efsw/FileWatcherKqueue.hpp 45 | ../../src/efsw/FileWatcherInotify.hpp 46 | ../../src/efsw/FileWatcherImpl.hpp 47 | ../../src/efsw/FileWatcherGeneric.hpp 48 | ../../src/efsw/FileSystem.hpp 49 | ../../src/efsw/FileInfo.hpp 50 | ../../src/efsw/Thread.cpp 51 | ../../src/efsw/System.cpp 52 | ../../src/efsw/Mutex.cpp 53 | ../../src/efsw/FileWatcherWin32.cpp 54 | ../../src/efsw/FileWatcherKqueue.cpp 55 | ../../src/efsw/FileWatcherInotify.cpp 56 | ../../src/efsw/FileWatcherGeneric.cpp 57 | ../../src/efsw/FileWatcher.cpp 58 | ../../src/efsw/FileSystem.cpp 59 | ../../src/efsw/FileInfo.cpp 60 | ../../src/efsw/sophist.h 61 | ../../src/efsw/base.hpp 62 | ../../src/efsw/Utf.hpp 63 | ../../src/efsw/Thread.hpp 64 | ../../src/efsw/System.hpp 65 | ../../src/efsw/String.hpp 66 | ../../src/efsw/Mutex.hpp 67 | ../../src/efsw/FileWatcherWin32.hpp 68 | ../../src/efsw/FileWatcherKqueue.hpp 69 | ../../src/efsw/FileWatcherInotify.hpp 70 | ../../src/efsw/FileWatcherImpl.hpp 71 | ../../src/efsw/FileWatcherGeneric.hpp 72 | ../../src/efsw/FileSystem.hpp 73 | ../../src/efsw/FileInfo.hpp 74 | ../../src/efsw/Utf.inl 75 | ../../src/efsw/Thread.cpp 76 | ../../src/efsw/System.cpp 77 | ../../src/efsw/String.cpp 78 | ../../src/efsw/Mutex.cpp 79 | ../../src/efsw/FileWatcherWin32.cpp 80 | ../../src/efsw/FileWatcherKqueue.cpp 81 | ../../src/efsw/FileWatcherInotify.cpp 82 | ../../src/efsw/FileWatcherGeneric.cpp 83 | ../../src/efsw/FileWatcher.cpp 84 | ../../src/efsw/FileSystem.cpp 85 | ../../src/efsw/FileInfo.cpp 86 | ../../src/test/efsw-test.cpp 87 | ../../src/efsw/WatcherKqueue.hpp 88 | ../../src/efsw/WatcherInotify.hpp 89 | ../../src/efsw/WatcherGeneric.hpp 90 | ../../src/efsw/Utf.hpp 91 | ../../src/efsw/Thread.hpp 92 | ../../src/efsw/System.hpp 93 | ../../src/efsw/String.hpp 94 | ../../src/efsw/Mutex.hpp 95 | ../../src/efsw/FileWatcherWin32.hpp 96 | ../../src/efsw/FileWatcherKqueue.hpp 97 | ../../src/efsw/FileWatcherInotify.hpp 98 | ../../src/efsw/FileWatcherImpl.hpp 99 | ../../src/efsw/FileWatcherGeneric.hpp 100 | ../../src/efsw/FileSystem.hpp 101 | ../../src/efsw/FileInfo.hpp 102 | ../../src/efsw/DirWatcherGeneric.hpp 103 | ../../src/efsw/Debug.hpp 104 | ../../src/efsw/base.hpp 105 | ../../src/efsw/sophist.h 106 | ../../src/efsw/Utf.inl 107 | ../../src/efsw/WatcherKqueue.cpp 108 | ../../src/efsw/WatcherInotify.cpp 109 | ../../src/efsw/WatcherGeneric.cpp 110 | ../../src/efsw/Thread.cpp 111 | ../../src/efsw/System.cpp 112 | ../../src/efsw/String.cpp 113 | ../../src/efsw/Mutex.cpp 114 | ../../src/efsw/Log.cpp 115 | ../../src/efsw/FileWatcherWin32.cpp 116 | ../../src/efsw/FileWatcherKqueue.cpp 117 | ../../src/efsw/FileWatcherInotify.cpp 118 | ../../src/efsw/FileWatcherGeneric.cpp 119 | ../../src/efsw/FileWatcher.cpp 120 | ../../src/efsw/FileSystem.cpp 121 | ../../src/efsw/FileInfo.cpp 122 | ../../src/efsw/DirWatcherGeneric.cpp 123 | ../../src/efsw/Debug.cpp 124 | ../../premake4.lua 125 | ../../src/efsw/WatcherKqueue.hpp 126 | ../../src/efsw/WatcherInotify.hpp 127 | ../../src/efsw/WatcherGeneric.hpp 128 | ../../src/efsw/Utf.hpp 129 | ../../src/efsw/Thread.hpp 130 | ../../src/efsw/System.hpp 131 | ../../src/efsw/String.hpp 132 | ../../src/efsw/sophist.h 133 | ../../src/efsw/Mutex.hpp 134 | ../../src/efsw/FileWatcherWin32.hpp 135 | ../../src/efsw/FileWatcherKqueue.hpp 136 | ../../src/efsw/FileWatcherInotify.hpp 137 | ../../src/efsw/FileWatcherImpl.hpp 138 | ../../src/efsw/FileWatcherGeneric.hpp 139 | ../../src/efsw/FileSystem.hpp 140 | ../../src/efsw/FileInfo.hpp 141 | ../../src/efsw/DirWatcherGeneric.hpp 142 | ../../src/efsw/Debug.hpp 143 | ../../src/efsw/base.hpp 144 | ../../src/efsw/Utf.inl 145 | ../../src/efsw/WatcherKqueue.cpp 146 | ../../src/efsw/WatcherInotify.cpp 147 | ../../src/efsw/WatcherGeneric.cpp 148 | ../../src/efsw/Thread.cpp 149 | ../../src/efsw/System.cpp 150 | ../../src/efsw/String.cpp 151 | ../../src/efsw/Mutex.cpp 152 | ../../src/efsw/Log.cpp 153 | ../../src/efsw/FileWatcherWin32.cpp 154 | ../../src/efsw/FileWatcherKqueue.cpp 155 | ../../src/efsw/FileWatcherInotify.cpp 156 | ../../src/efsw/FileWatcherImpl.cpp 157 | ../../src/efsw/FileWatcherGeneric.cpp 158 | ../../src/efsw/FileWatcher.cpp 159 | ../../src/efsw/FileSystem.cpp 160 | ../../src/efsw/FileInfo.cpp 161 | ../../src/efsw/DirWatcherGeneric.cpp 162 | ../../src/efsw/Debug.cpp 163 | ../../src/efsw/WatcherWin32.hpp 164 | ../../src/efsw/WatcherKqueue.hpp 165 | ../../src/efsw/WatcherInotify.hpp 166 | ../../src/efsw/WatcherGeneric.hpp 167 | ../../src/efsw/WatcherFSEvents.hpp 168 | ../../src/efsw/Watcher.hpp 169 | ../../src/efsw/Utf.hpp 170 | ../../src/efsw/Thread.hpp 171 | ../../src/efsw/System.hpp 172 | ../../src/efsw/String.hpp 173 | ../../src/efsw/sophist.h 174 | ../../src/efsw/Mutex.hpp 175 | ../../src/efsw/FileWatcherWin32.hpp 176 | ../../src/efsw/FileWatcherKqueue.hpp 177 | ../../src/efsw/FileWatcherInotify.hpp 178 | ../../src/efsw/FileWatcherImpl.hpp 179 | ../../src/efsw/FileWatcherGeneric.hpp 180 | ../../src/efsw/FileWatcherFSEvents.hpp 181 | ../../src/efsw/FileSystem.hpp 182 | ../../src/efsw/FileInfo.hpp 183 | ../../src/efsw/DirWatcherGeneric.hpp 184 | ../../src/efsw/DirectorySnapshotDiff.hpp 185 | ../../src/efsw/DirectorySnapshot.hpp 186 | ../../src/efsw/Debug.hpp 187 | ../../src/efsw/base.hpp 188 | ../../src/efsw/Utf.inl 189 | ../../src/efsw/WatcherWin32.cpp 190 | ../../src/efsw/WatcherKqueue.cpp 191 | ../../src/efsw/WatcherInotify.cpp 192 | ../../src/efsw/WatcherGeneric.cpp 193 | ../../src/efsw/WatcherFSEvents.cpp 194 | ../../src/efsw/Watcher.cpp 195 | ../../src/efsw/Thread.cpp 196 | ../../src/efsw/System.cpp 197 | ../../src/efsw/String.cpp 198 | ../../src/efsw/Mutex.cpp 199 | ../../src/efsw/Log.cpp 200 | ../../src/efsw/FileWatcherWin32.cpp 201 | ../../src/efsw/FileWatcherKqueue.cpp 202 | ../../src/efsw/FileWatcherInotify.cpp 203 | ../../src/efsw/FileWatcherImpl.cpp 204 | ../../src/efsw/FileWatcherGeneric.cpp 205 | ../../src/efsw/FileWatcherFSEvents.cpp 206 | ../../src/efsw/FileWatcher.cpp 207 | ../../src/efsw/FileSystem.cpp 208 | ../../src/efsw/FileInfo.cpp 209 | ../../src/efsw/DirWatcherGeneric.cpp 210 | ../../src/efsw/DirectorySnapshotDiff.cpp 211 | ../../src/efsw/DirectorySnapshot.cpp 212 | ../../src/efsw/Debug.cpp 213 | -------------------------------------------------------------------------------- /project/qtcreator-win/efsw.includes: -------------------------------------------------------------------------------- 1 | src 2 | include -------------------------------------------------------------------------------- /src/efsw/Debug.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef EFSW_COMPILER_MSVC 4 | #include 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace efsw { 13 | 14 | #ifdef DEBUG 15 | 16 | void efREPORT_ASSERT( const char * File, int Line, const char * Exp ) 17 | { 18 | #ifdef EFSW_COMPILER_MSVC 19 | _CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp); 20 | 21 | DebugBreak(); 22 | #else 23 | std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl; 24 | 25 | #if defined(EFSW_COMPILER_GCC) && defined(EFSW_32BIT) && !defined(EFSW_ARM) 26 | asm("int3"); 27 | #else 28 | assert( false ); 29 | #endif 30 | #endif 31 | } 32 | 33 | void efPRINT( const char * format, ... ) 34 | { 35 | char buf[2048]; 36 | va_list args; 37 | 38 | va_start( args, format ); 39 | 40 | #ifdef EFSW_COMPILER_MSVC 41 | _vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0]), format, args ); 42 | #else 43 | vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args ); 44 | #endif 45 | 46 | va_end( args ); 47 | 48 | #ifdef EFSW_COMPILER_MSVC 49 | OutputDebugStringA( buf ); 50 | #else 51 | std::cout << buf; 52 | #endif 53 | } 54 | 55 | void efPRINTC( unsigned int cond, const char * format, ...) 56 | { 57 | if ( 0 == cond ) 58 | return; 59 | 60 | char buf[2048]; 61 | va_list args; 62 | 63 | va_start( args, format ); 64 | 65 | #ifdef EFSW_COMPILER_MSVC 66 | _vsnprintf_s( buf, eeARRAY_SIZE( buf ), eeARRAY_SIZE( buf ), format, args ); 67 | #else 68 | vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args ); 69 | #endif 70 | 71 | va_end( args ); 72 | 73 | #ifdef EFSW_COMPILER_MSVC 74 | OutputDebugStringA( buf ); 75 | #else 76 | std::cout << buf; 77 | #endif 78 | } 79 | 80 | #endif 81 | 82 | } 83 | 84 | -------------------------------------------------------------------------------- /src/efsw/Debug.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_DEBUG_HPP 2 | #define EFSW_DEBUG_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | #ifdef DEBUG 9 | 10 | void efREPORT_ASSERT( const char * File, const int Line, const char * Exp ); 11 | 12 | #define efASSERT( expr ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #expr ); } 13 | #define efASSERTM( expr, msg ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #msg ); } 14 | 15 | void efPRINT ( const char * format, ... ); 16 | void efPRINTC ( unsigned int cond, const char * format, ... ); 17 | 18 | #else 19 | 20 | #define efASSERT( expr ) 21 | #define efASSERTM( expr, msg ) 22 | 23 | #define efPRINT( format, args... ) {} 24 | #define efPRINTC( cond, format, args... ) {} 25 | 26 | #endif 27 | 28 | #ifdef EFSW_VERBOSE 29 | #define efDEBUG efPRINT 30 | #define efDEBUGC efPRINTC 31 | #else 32 | #define efDEBUG( format, args... ) {} 33 | #define efDEBUGC( cond, format, args... ) {} 34 | #endif 35 | 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/efsw/DirWatcherGeneric.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace efsw { 7 | 8 | DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive ) : 9 | Parent( parent ), 10 | Watch( ws ), 11 | Recursive( recursive ), 12 | Deleted( false ) 13 | { 14 | resetDirectory( directory ); 15 | 16 | DirSnap.scan(); 17 | } 18 | 19 | DirWatcherGeneric::~DirWatcherGeneric() 20 | { 21 | /// If the directory was deleted mark the files as deleted 22 | if ( Deleted ) 23 | { 24 | DirectorySnapshotDiff Diff = DirSnap.scan(); 25 | 26 | if ( !DirSnap.exists() ) 27 | { 28 | FileInfoList::iterator it; 29 | 30 | DiffIterator( FilesDeleted ) 31 | { 32 | handleAction( (*it).Filepath, Actions::Delete ); 33 | } 34 | 35 | DiffIterator( DirsDeleted ) 36 | { 37 | handleAction( (*it).Filepath, Actions::Delete ); 38 | } 39 | } 40 | } 41 | 42 | DirWatchMap::iterator it = Directories.begin(); 43 | 44 | for ( ; it != Directories.end(); it++ ) 45 | { 46 | if ( Deleted ) 47 | { 48 | /// If the directory was deleted, mark the flag for file deletion 49 | it->second->Deleted = true; 50 | } 51 | 52 | efSAFE_DELETE( it->second ); 53 | } 54 | } 55 | 56 | void DirWatcherGeneric::resetDirectory( std::string directory ) 57 | { 58 | std::string dir( directory ); 59 | 60 | /// Is this a recursive watch? 61 | if ( Watch->Directory != directory ) 62 | { 63 | if ( !( directory.size() && ( directory.at(0) == FileSystem::getOSSlash() || directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) ) 64 | { 65 | /// Get the real directory 66 | if ( NULL != Parent ) 67 | { 68 | dir = Parent->DirSnap.DirectoryInfo.Filepath + directory; 69 | } 70 | else 71 | { 72 | efDEBUG( "resetDirectory(): Parent is NULL. Fatal error." ); 73 | } 74 | } 75 | } 76 | 77 | DirSnap.setDirectoryInfo( dir ); 78 | } 79 | 80 | void DirWatcherGeneric::handleAction( const std::string &filename, unsigned long action, std::string oldFilename) 81 | { 82 | Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath, FileSystem::fileNameFromPath( filename ), (Action)action, oldFilename ); 83 | } 84 | 85 | void DirWatcherGeneric::addChilds() 86 | { 87 | if ( Recursive ) 88 | { 89 | /// Create the subdirectories watchers 90 | std::string dir; 91 | 92 | for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ ) 93 | { 94 | if ( it->second.isDirectory() && it->second.isReadable() ) 95 | { 96 | /// Check if the directory is a symbolic link 97 | std::string curPath; 98 | std::string link( FileSystem::getLinkRealPath( it->second.Filepath, curPath ) ); 99 | 100 | dir = it->first; 101 | 102 | if ( "" != link ) 103 | { 104 | /// Avoid adding symlinks directories if it's now enabled 105 | if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) 106 | { 107 | continue; 108 | } 109 | 110 | /// If it's a symlink check if the realpath exists as a watcher, or 111 | /// if the path is outside the current dir 112 | if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) ) 113 | { 114 | continue; 115 | } 116 | else 117 | { 118 | dir = link; 119 | } 120 | } 121 | else 122 | { 123 | if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) 124 | { 125 | continue; 126 | } 127 | } 128 | 129 | Directories[ dir ] = new DirWatcherGeneric( this, Watch, dir, Recursive ); 130 | 131 | Directories[ dir ]->addChilds(); 132 | } 133 | } 134 | } 135 | } 136 | 137 | void DirWatcherGeneric::watch( bool reportOwnChange ) 138 | { 139 | DirectorySnapshotDiff Diff = DirSnap.scan(); 140 | 141 | if ( reportOwnChange && Diff.DirChanged && NULL != Parent ) 142 | { 143 | Watch->Listener->handleFileAction( Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ), FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified ); 144 | } 145 | 146 | if ( Diff.changed() ) 147 | { 148 | FileInfoList::iterator it; 149 | MovedList::iterator mit; 150 | 151 | /// Files 152 | DiffIterator( FilesCreated ) 153 | { 154 | handleAction( (*it).Filepath, Actions::Add ); 155 | } 156 | 157 | DiffIterator( FilesModified ) 158 | { 159 | handleAction( (*it).Filepath, Actions::Modified ); 160 | } 161 | 162 | DiffIterator( FilesDeleted ) 163 | { 164 | handleAction( (*it).Filepath, Actions::Delete ); 165 | } 166 | 167 | DiffMovedIterator( FilesMoved ) 168 | { 169 | handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first ); 170 | } 171 | 172 | /// Directories 173 | DiffIterator( DirsCreated ) 174 | { 175 | handleAction( (*it).Filepath, Actions::Add ); 176 | createDirectory( (*it).Filepath ); 177 | } 178 | 179 | DiffIterator( DirsModified ) 180 | { 181 | handleAction( (*it).Filepath, Actions::Modified ); 182 | } 183 | 184 | DiffIterator( DirsDeleted ) 185 | { 186 | handleAction( (*it).Filepath, Actions::Delete ); 187 | removeDirectory( (*it).Filepath ); 188 | } 189 | 190 | DiffMovedIterator( DirsMoved ) 191 | { 192 | handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first ); 193 | moveDirectory( (*mit).first, (*mit).second.Filepath ); 194 | } 195 | } 196 | 197 | /// Process the subdirectories looking for changes 198 | for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); dit++ ) 199 | { 200 | /// Just watch 201 | dit->second->watch(); 202 | } 203 | } 204 | 205 | void DirWatcherGeneric::watchDir( std::string &dir ) 206 | { 207 | DirWatcherGeneric * watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks() ? 208 | findDirWatcher( dir ) : 209 | findDirWatcherFast( dir ); 210 | 211 | if ( NULL != watcher ) 212 | { 213 | watcher->watch( true ); 214 | } 215 | } 216 | 217 | DirWatcherGeneric * DirWatcherGeneric::findDirWatcherFast( std::string dir ) 218 | { 219 | // remove the common base ( dir should always start with the same base as the watcher ) 220 | efASSERT( !dir.empty() ); 221 | efASSERT( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ); 222 | efASSERT( DirSnap.DirectoryInfo.Filepath == dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) ); 223 | 224 | if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ) 225 | { 226 | dir = dir.substr( DirSnap.DirectoryInfo.Filepath.size() - 1 ); 227 | } 228 | 229 | if ( dir.size() == 1 ) 230 | { 231 | efASSERT( dir[0] == FileSystem::getOSSlash() ); 232 | return this; 233 | } 234 | 235 | size_t level = 0; 236 | std::vector dirv = String::split( dir, FileSystem::getOSSlash(), false ); 237 | 238 | DirWatcherGeneric * watcher = this; 239 | 240 | while ( level < dirv.size() ) 241 | { 242 | // search the dir level in the current watcher 243 | DirWatchMap::iterator it = watcher->Directories.find( dirv[ level ] ); 244 | 245 | // found? continue with the next level 246 | if ( it != watcher->Directories.end() ) 247 | { 248 | watcher = it->second; 249 | 250 | level++; 251 | } 252 | else 253 | { 254 | // couldn't found the folder level? 255 | // directory not watched 256 | return NULL; 257 | } 258 | } 259 | 260 | return watcher; 261 | } 262 | 263 | DirWatcherGeneric * DirWatcherGeneric::findDirWatcher( std::string dir ) 264 | { 265 | if ( DirSnap.DirectoryInfo.Filepath == dir ) 266 | { 267 | return this; 268 | } 269 | else 270 | { 271 | DirWatcherGeneric * watcher = NULL; 272 | 273 | for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); it++ ) 274 | { 275 | watcher = it->second->findDirWatcher( dir ); 276 | 277 | if ( NULL != watcher ) 278 | { 279 | return watcher; 280 | } 281 | } 282 | } 283 | 284 | return NULL; 285 | } 286 | 287 | DirWatcherGeneric * DirWatcherGeneric::createDirectory( std::string newdir ) 288 | { 289 | FileSystem::dirRemoveSlashAtEnd( newdir ); 290 | newdir = FileSystem::fileNameFromPath( newdir ); 291 | 292 | DirWatcherGeneric * dw = NULL; 293 | 294 | /// Check if the directory is a symbolic link 295 | std::string dir( DirSnap.DirectoryInfo.Filepath + newdir ); 296 | 297 | FileSystem::dirAddSlashAtEnd( dir ); 298 | 299 | FileInfo fi( dir ); 300 | 301 | if ( !fi.isDirectory() || !fi.isReadable() ) 302 | { 303 | return NULL; 304 | } 305 | 306 | std::string curPath; 307 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); 308 | bool skip = false; 309 | 310 | if ( "" != link ) 311 | { 312 | /// Avoid adding symlinks directories if it's now enabled 313 | if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) 314 | { 315 | skip = true; 316 | } 317 | 318 | /// If it's a symlink check if the realpath exists as a watcher, or 319 | /// if the path is outside the current dir 320 | if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) ) 321 | { 322 | skip = true; 323 | } 324 | else 325 | { 326 | dir = link; 327 | } 328 | } 329 | else 330 | { 331 | if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) 332 | { 333 | skip = true; 334 | } 335 | } 336 | 337 | if ( !skip ) 338 | { 339 | /// Creates the new directory watcher of the subfolder and check for new files 340 | dw = new DirWatcherGeneric( this, Watch, dir, Recursive ); 341 | dw->watch(); 342 | 343 | /// Add it to the list of directories 344 | Directories[ newdir ] = dw; 345 | } 346 | 347 | return dw; 348 | } 349 | 350 | void DirWatcherGeneric::removeDirectory( std::string dir ) 351 | { 352 | FileSystem::dirRemoveSlashAtEnd( dir ); 353 | dir = FileSystem::fileNameFromPath( dir ); 354 | 355 | DirWatcherGeneric * dw = NULL; 356 | DirWatchMap::iterator dit; 357 | 358 | /// Folder deleted 359 | 360 | /// Search the folder, it should exists 361 | dit = Directories.find( dir ); 362 | 363 | if ( dit != Directories.end() ) 364 | { 365 | dw = dit->second; 366 | 367 | /// Flag it as deleted so it fire the event for every file inside deleted 368 | dw->Deleted = true; 369 | 370 | /// Delete the DirWatcherGeneric 371 | efSAFE_DELETE( dw ); 372 | 373 | /// Remove the directory from the map 374 | Directories.erase( dit->first ); 375 | } 376 | } 377 | 378 | void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir ) 379 | { 380 | FileSystem::dirRemoveSlashAtEnd( oldDir ); 381 | oldDir = FileSystem::fileNameFromPath( oldDir ); 382 | 383 | FileSystem::dirRemoveSlashAtEnd( newDir ); 384 | newDir = FileSystem::fileNameFromPath( newDir ); 385 | 386 | DirWatcherGeneric * dw = NULL; 387 | DirWatchMap::iterator dit; 388 | 389 | /// Directory existed? 390 | dit = Directories.find( oldDir ); 391 | 392 | if ( dit != Directories.end() ) 393 | { 394 | dw = dit->second; 395 | 396 | /// Remove the directory from the map 397 | Directories.erase( dit->first ); 398 | 399 | Directories[ newDir ] = dw; 400 | 401 | dw->resetDirectory( newDir ); 402 | } 403 | } 404 | 405 | bool DirWatcherGeneric::pathInWatches( std::string path ) 406 | { 407 | if ( DirSnap.DirectoryInfo.Filepath == path ) 408 | { 409 | return true; 410 | } 411 | 412 | for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); it++ ) 413 | { 414 | if ( it->second->pathInWatches( path ) ) 415 | { 416 | return true; 417 | } 418 | } 419 | 420 | return false; 421 | } 422 | 423 | } 424 | -------------------------------------------------------------------------------- /src/efsw/DirWatcherGeneric.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_DIRWATCHERGENERIC_HPP 2 | #define EFSW_DIRWATCHERGENERIC_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace efsw { 10 | 11 | class DirWatcherGeneric 12 | { 13 | public: 14 | typedef std::map DirWatchMap; 15 | 16 | DirWatcherGeneric * Parent; 17 | WatcherGeneric * Watch; 18 | DirectorySnapshot DirSnap; 19 | DirWatchMap Directories; 20 | bool Recursive; 21 | 22 | DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive ); 23 | 24 | ~DirWatcherGeneric(); 25 | 26 | void watch( bool reportOwnChange = false ); 27 | 28 | void watchDir( std::string& dir ); 29 | 30 | static bool isDir( const std::string& directory ); 31 | 32 | bool pathInWatches( std::string path ); 33 | 34 | void addChilds(); 35 | 36 | DirWatcherGeneric * findDirWatcher( std::string dir ); 37 | 38 | DirWatcherGeneric * findDirWatcherFast( std::string dir ); 39 | protected: 40 | bool Deleted; 41 | 42 | DirWatcherGeneric * createDirectory( std::string newdir ); 43 | 44 | void removeDirectory( std::string dir ); 45 | 46 | void moveDirectory( std::string oldDir, std::string newDir ); 47 | 48 | void resetDirectory( std::string directory ); 49 | 50 | void handleAction( const std::string& filename, unsigned long action, std::string oldFilename = ""); 51 | }; 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/efsw/DirectorySnapshot.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace efsw { 5 | 6 | DirectorySnapshot::DirectorySnapshot() 7 | { 8 | } 9 | 10 | DirectorySnapshot::DirectorySnapshot( std::string directory ) 11 | { 12 | init( directory ); 13 | } 14 | 15 | DirectorySnapshot::~DirectorySnapshot() 16 | { 17 | } 18 | 19 | void DirectorySnapshot::init( std::string directory ) 20 | { 21 | setDirectoryInfo( directory ); 22 | initFiles(); 23 | } 24 | 25 | bool DirectorySnapshot::exists() 26 | { 27 | return DirectoryInfo.exists(); 28 | } 29 | 30 | void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff ) 31 | { 32 | FileInfo fi; 33 | 34 | for ( FileInfoMap::iterator it = Files.begin(); it != Files.end(); it++ ) 35 | { 36 | fi = it->second; 37 | 38 | if ( fi.isDirectory() ) 39 | { 40 | Diff.DirsDeleted.push_back( fi ); 41 | } 42 | else 43 | { 44 | Diff.FilesDeleted.push_back( fi ); 45 | } 46 | } 47 | } 48 | 49 | void DirectorySnapshot::setDirectoryInfo( std::string directory ) 50 | { 51 | DirectoryInfo = FileInfo( directory ); 52 | } 53 | 54 | void DirectorySnapshot::initFiles() 55 | { 56 | Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); 57 | 58 | FileInfoMap::iterator it = Files.begin(); 59 | std::list eraseFiles; 60 | 61 | /// Remove all non regular files and non directories 62 | for ( ; it != Files.end(); it++ ) 63 | { 64 | if ( !it->second.isRegularFile() && !it->second.isDirectory() ) 65 | { 66 | eraseFiles.push_back( it->first ); 67 | } 68 | } 69 | 70 | for ( std::list::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); eit++ ) 71 | { 72 | Files.erase( *eit ); 73 | } 74 | } 75 | 76 | DirectorySnapshotDiff DirectorySnapshot::scan() 77 | { 78 | DirectorySnapshotDiff Diff; 79 | 80 | Diff.clear(); 81 | 82 | FileInfo curFI( DirectoryInfo.Filepath ); 83 | 84 | Diff.DirChanged = DirectoryInfo != curFI; 85 | 86 | if ( Diff.DirChanged ) 87 | { 88 | DirectoryInfo = curFI; 89 | } 90 | 91 | /// If the directory was erased, create the events for files and directories deletion 92 | if ( !curFI.exists() ) 93 | { 94 | deleteAll( Diff ); 95 | 96 | return Diff; 97 | } 98 | 99 | FileInfoMap files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); 100 | 101 | if ( files.empty() && Files.empty() ) 102 | { 103 | return Diff; 104 | } 105 | 106 | FileInfo fi; 107 | FileInfoMap FilesCpy; 108 | FileInfoMap::iterator it; 109 | FileInfoMap::iterator fiIt; 110 | 111 | if ( Diff.DirChanged ) 112 | { 113 | FilesCpy = Files; 114 | } 115 | 116 | for ( it = files.begin(); it != files.end(); it++ ) 117 | { 118 | fi = it->second; 119 | 120 | /// File existed before? 121 | fiIt = Files.find( it->first ); 122 | 123 | if ( fiIt != Files.end() ) 124 | { 125 | /// Erase from the file list copy 126 | FilesCpy.erase( it->first ); 127 | 128 | /// File changed? 129 | if ( (*fiIt).second != fi ) 130 | { 131 | /// Update the new file info 132 | Files[ it->first ] = fi; 133 | 134 | /// handle modified event 135 | if ( fi.isDirectory() ) 136 | { 137 | Diff.DirsModified.push_back( fi ); 138 | } 139 | else 140 | { 141 | Diff.FilesModified.push_back( fi ); 142 | } 143 | } 144 | } 145 | /// Only add regular files or directories 146 | else if ( fi.isRegularFile() || fi.isDirectory() ) 147 | { 148 | /// New file found 149 | Files[ it->first ] = fi; 150 | 151 | FileInfoMap::iterator fit; 152 | std::string oldFile = ""; 153 | 154 | /// Check if the same inode already existed 155 | if ( ( fit = nodeInFiles( fi ) ) != Files.end() ) 156 | { 157 | oldFile = fit->first; 158 | 159 | /// Avoid firing a Delete event 160 | FilesCpy.erase( fit->first ); 161 | 162 | /// Delete the old file name 163 | Files.erase( fit->first ); 164 | 165 | if ( fi.isDirectory() ) 166 | { 167 | Diff.DirsMoved.push_back( std::make_pair( oldFile, fi ) ); 168 | } 169 | else 170 | { 171 | Diff.FilesMoved.push_back( std::make_pair( oldFile, fi ) ); 172 | } 173 | } 174 | else 175 | { 176 | if ( fi.isDirectory() ) 177 | { 178 | Diff.DirsCreated.push_back( fi ); 179 | } 180 | else 181 | { 182 | Diff.FilesCreated.push_back( fi ); 183 | } 184 | } 185 | } 186 | } 187 | 188 | if ( !Diff.DirChanged ) 189 | { 190 | return Diff; 191 | } 192 | 193 | /// The files or directories that remains were deleted 194 | for ( it = FilesCpy.begin(); it != FilesCpy.end(); it++ ) 195 | { 196 | fi = it->second; 197 | 198 | if ( fi.isDirectory() ) 199 | { 200 | Diff.DirsDeleted.push_back( fi ); 201 | } 202 | else 203 | { 204 | Diff.FilesDeleted.push_back( fi ); 205 | } 206 | 207 | /// Remove the file or directory from the list of files 208 | Files.erase( it->first ); 209 | } 210 | 211 | return Diff; 212 | } 213 | 214 | FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi ) 215 | { 216 | FileInfoMap::iterator it; 217 | 218 | if ( FileInfo::inodeSupported() ) 219 | { 220 | for ( it = Files.begin(); it != Files.end(); it++ ) 221 | { 222 | if ( it->second.sameInode( fi ) && it->second.Filepath != fi.Filepath ) 223 | { 224 | return it; 225 | } 226 | } 227 | } 228 | 229 | return Files.end(); 230 | } 231 | 232 | void DirectorySnapshot::addFile( std::string path ) 233 | { 234 | std::string name( FileSystem::fileNameFromPath( path ) ); 235 | Files[ name ] = FileInfo( path ); 236 | } 237 | 238 | void DirectorySnapshot::removeFile( std::string path ) 239 | { 240 | std::string name( FileSystem::fileNameFromPath( path ) ); 241 | 242 | FileInfoMap::iterator it = Files.find( name ); 243 | 244 | if ( Files.end() != it ) 245 | { 246 | Files.erase( it ); 247 | } 248 | } 249 | 250 | void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath ) 251 | { 252 | removeFile( oldPath ); 253 | addFile( newPath ); 254 | } 255 | 256 | void DirectorySnapshot::updateFile(std::string path) 257 | { 258 | addFile( path ); 259 | } 260 | 261 | } 262 | -------------------------------------------------------------------------------- /src/efsw/DirectorySnapshot.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_DIRECTORYSNAPSHOT_HPP 2 | #define EFSW_DIRECTORYSNAPSHOT_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | class DirectorySnapshot 9 | { 10 | public: 11 | FileInfo DirectoryInfo; 12 | FileInfoMap Files; 13 | 14 | void setDirectoryInfo( std::string directory ); 15 | 16 | DirectorySnapshot(); 17 | 18 | DirectorySnapshot( std::string directory ); 19 | 20 | ~DirectorySnapshot(); 21 | 22 | void init( std::string directory ); 23 | 24 | bool exists(); 25 | 26 | DirectorySnapshotDiff scan(); 27 | 28 | FileInfoMap::iterator nodeInFiles( FileInfo& fi ); 29 | 30 | void addFile( std::string path ); 31 | 32 | void removeFile( std::string path ); 33 | 34 | void moveFile( std::string oldPath, std::string newPath ); 35 | 36 | void updateFile( std::string path ); 37 | protected: 38 | void initFiles(); 39 | 40 | void deleteAll( DirectorySnapshotDiff &Diff ); 41 | }; 42 | 43 | } 44 | 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /src/efsw/DirectorySnapshotDiff.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace efsw { 4 | 5 | void DirectorySnapshotDiff::clear() 6 | { 7 | FilesCreated.clear(); 8 | FilesModified.clear(); 9 | FilesMoved.clear(); 10 | FilesDeleted.clear(); 11 | DirsCreated.clear(); 12 | DirsModified.clear(); 13 | DirsMoved.clear(); 14 | DirsDeleted.clear(); 15 | } 16 | 17 | bool DirectorySnapshotDiff::changed() 18 | { 19 | return !FilesCreated.empty() || 20 | !FilesModified.empty() || 21 | !FilesMoved.empty() || 22 | !FilesDeleted.empty() || 23 | !DirsCreated.empty() || 24 | !DirsModified.empty() || 25 | !DirsMoved.empty() || 26 | !DirsDeleted.empty(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/efsw/DirectorySnapshotDiff.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_DIRECTORYSNAPSHOTDIFF_HPP 2 | #define EFSW_DIRECTORYSNAPSHOTDIFF_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | class DirectorySnapshotDiff 9 | { 10 | public: 11 | FileInfoList FilesDeleted; 12 | FileInfoList FilesCreated; 13 | FileInfoList FilesModified; 14 | MovedList FilesMoved; 15 | FileInfoList DirsDeleted; 16 | FileInfoList DirsCreated; 17 | FileInfoList DirsModified; 18 | MovedList DirsMoved; 19 | bool DirChanged; 20 | 21 | void clear(); 22 | 23 | bool changed(); 24 | }; 25 | 26 | #define DiffIterator( FileInfoListName ) it = Diff.FileInfoListName.begin(); \ 27 | for ( ; it != Diff.FileInfoListName.end(); it++ ) 28 | 29 | #define DiffMovedIterator( MovedListName ) mit = Diff.MovedListName.begin(); \ 30 | for ( ; mit != Diff.MovedListName.end(); mit++ ) 31 | 32 | } 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /src/efsw/FileInfo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace efsw { 9 | 10 | bool FileInfo::exists( const std::string& filePath ) 11 | { 12 | FileInfo fi( filePath ); 13 | return fi.exists(); 14 | } 15 | 16 | bool FileInfo::isLink( const std::string& filePath ) 17 | { 18 | FileInfo fi( filePath, true ); 19 | return fi.isLink(); 20 | } 21 | 22 | bool FileInfo::inodeSupported() 23 | { 24 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 25 | return true; 26 | #else 27 | return false; 28 | #endif 29 | } 30 | 31 | FileInfo::FileInfo() : 32 | ModificationTime(0), 33 | OwnerId(0), 34 | GroupId(0), 35 | Permissions(0), 36 | Inode(0) 37 | {} 38 | 39 | FileInfo::FileInfo( const std::string& filepath ) : 40 | Filepath( filepath ), 41 | ModificationTime(0), 42 | OwnerId(0), 43 | GroupId(0), 44 | Permissions(0), 45 | Inode(0) 46 | { 47 | getInfo(); 48 | } 49 | 50 | FileInfo::FileInfo( const std::string& filepath, bool linkInfo ) : 51 | Filepath( filepath ), 52 | ModificationTime(0), 53 | OwnerId(0), 54 | GroupId(0), 55 | Permissions(0), 56 | Inode(0) 57 | { 58 | if ( linkInfo ) 59 | { 60 | getRealInfo(); 61 | } 62 | else 63 | { 64 | getInfo(); 65 | } 66 | } 67 | 68 | void FileInfo::getInfo() 69 | { 70 | /// Why i'm doing this? stat in mingw32 doesn't work for directories if the dir path ends with a path slash 71 | bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); 72 | 73 | if ( slashAtEnd ) 74 | { 75 | FileSystem::dirRemoveSlashAtEnd( Filepath ); 76 | } 77 | 78 | struct stat st; 79 | int res = stat( Filepath.c_str(), &st ); 80 | 81 | if ( 0 == res ) 82 | { 83 | ModificationTime = st.st_mtime; 84 | OwnerId = st.st_uid; 85 | GroupId = st.st_gid; 86 | Permissions = st.st_mode; 87 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 88 | Inode = st.st_ino; 89 | #endif 90 | } 91 | 92 | if ( slashAtEnd ) 93 | { 94 | FileSystem::dirAddSlashAtEnd( Filepath ); 95 | } 96 | } 97 | 98 | void FileInfo::getRealInfo() 99 | { 100 | bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); 101 | 102 | if ( slashAtEnd ) 103 | { 104 | FileSystem::dirRemoveSlashAtEnd( Filepath ); 105 | } 106 | 107 | struct stat st; 108 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 109 | int res = lstat( Filepath.c_str(), &st ); 110 | #else 111 | int res = stat( Filepath.c_str(), &st ); 112 | #endif 113 | 114 | if ( 0 == res ) 115 | { 116 | ModificationTime = st.st_mtime; 117 | OwnerId = st.st_uid; 118 | GroupId = st.st_gid; 119 | Permissions = st.st_mode; 120 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 121 | Inode = st.st_ino; 122 | #endif 123 | } 124 | 125 | if ( slashAtEnd ) 126 | { 127 | FileSystem::dirAddSlashAtEnd( Filepath ); 128 | } 129 | } 130 | 131 | bool FileInfo::operator==( const FileInfo& Other ) const 132 | { 133 | return ( ModificationTime == Other.ModificationTime && 134 | OwnerId == Other.OwnerId && 135 | GroupId == Other.GroupId && 136 | Permissions == Other.Permissions && 137 | Inode == Other.Inode 138 | ); 139 | } 140 | 141 | bool FileInfo::isDirectory() 142 | { 143 | return S_ISDIR(Permissions); 144 | } 145 | 146 | bool FileInfo::isRegularFile() 147 | { 148 | return S_ISREG(Permissions); 149 | } 150 | 151 | bool FileInfo::isReadable() 152 | { 153 | return Permissions & S_IRUSR; 154 | } 155 | 156 | bool FileInfo::isLink() 157 | { 158 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 159 | return S_ISLNK(Permissions); 160 | #else 161 | return false; 162 | #endif 163 | } 164 | 165 | std::string FileInfo::linksTo() 166 | { 167 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 168 | if ( isLink() ) 169 | { 170 | char * ch = realpath( Filepath.c_str(), NULL); 171 | 172 | std::string tstr( ch ); 173 | 174 | free( ch ); 175 | 176 | return tstr; 177 | } 178 | #endif 179 | return std::string(""); 180 | } 181 | 182 | bool FileInfo::exists() 183 | { 184 | struct stat st; 185 | return stat( Filepath.c_str(), &st ) == 0; 186 | } 187 | 188 | FileInfo& FileInfo::operator=( const FileInfo& Other ) 189 | { 190 | this->Filepath = Other.Filepath; 191 | this->ModificationTime = Other.ModificationTime; 192 | this->GroupId = Other.GroupId; 193 | this->OwnerId = Other.OwnerId; 194 | this->Permissions = Other.Permissions; 195 | this->Inode = Other.Inode; 196 | return *this; 197 | } 198 | 199 | bool FileInfo::sameInode( const FileInfo& Other ) const 200 | { 201 | return inodeSupported() && Inode == Other.Inode; 202 | } 203 | 204 | bool FileInfo::operator!=( const FileInfo& Other ) const 205 | { 206 | return !(*this == Other); 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /src/efsw/FileInfo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEINFO_HPP 2 | #define EFSW_FILEINFO_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace efsw { 10 | 11 | class FileInfo 12 | { 13 | public: 14 | static bool exists( const std::string& filePath ); 15 | 16 | static bool isLink( const std::string& filePath ); 17 | 18 | static bool inodeSupported(); 19 | 20 | FileInfo(); 21 | 22 | FileInfo( const std::string& filepath ); 23 | 24 | FileInfo( const std::string& filepath, bool linkInfo ); 25 | 26 | bool operator==( const FileInfo& Other ) const; 27 | 28 | bool operator!=( const FileInfo& Other ) const; 29 | 30 | FileInfo& operator=( const FileInfo& Other ); 31 | 32 | bool isDirectory(); 33 | 34 | bool isRegularFile(); 35 | 36 | bool isReadable(); 37 | 38 | bool sameInode( const FileInfo& Other ) const; 39 | 40 | bool isLink(); 41 | 42 | std::string linksTo(); 43 | 44 | bool exists(); 45 | 46 | void getInfo(); 47 | 48 | void getRealInfo(); 49 | 50 | std::string Filepath; 51 | Uint64 ModificationTime; 52 | Uint32 OwnerId; 53 | Uint32 GroupId; 54 | Uint32 Permissions; 55 | Uint64 Inode; 56 | }; 57 | 58 | typedef std::map FileInfoMap; 59 | typedef std::list FileInfoList; 60 | typedef std::list< std::pair< std::string, FileInfo> > MovedList; 61 | 62 | } 63 | 64 | #endif 65 | 66 | -------------------------------------------------------------------------------- /src/efsw/FileSystem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | bool FileSystem::isDirectory( const std::string& path ) 9 | { 10 | return Platform::FileSystem::isDirectory( path ); 11 | } 12 | 13 | FileInfoMap FileSystem::filesInfoFromPath( std::string path ) { 14 | dirAddSlashAtEnd( path ); 15 | 16 | return Platform::FileSystem::filesInfoFromPath( path ); 17 | } 18 | 19 | char FileSystem::getOSSlash() 20 | { 21 | return Platform::FileSystem::getOSSlash(); 22 | } 23 | 24 | bool FileSystem::slashAtEnd( std::string &dir ) 25 | { 26 | return ( dir.size() && dir[ dir.size() - 1 ] == getOSSlash() ); 27 | } 28 | 29 | void FileSystem::dirAddSlashAtEnd( std::string& dir ) 30 | { 31 | if ( dir.size() && dir[ dir.size() - 1 ] != getOSSlash() ) 32 | { 33 | dir.push_back( getOSSlash() ); 34 | } 35 | } 36 | 37 | void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) 38 | { 39 | if ( dir.size() && dir[ dir.size() - 1 ] == getOSSlash() ) 40 | { 41 | dir.erase( dir.size() - 1 ); 42 | } 43 | } 44 | 45 | std::string FileSystem::fileNameFromPath( std::string filepath ) 46 | { 47 | dirRemoveSlashAtEnd( filepath ); 48 | 49 | size_t pos = filepath.find_last_of( getOSSlash() ); 50 | 51 | if ( pos != std::string::npos ) 52 | { 53 | return filepath.substr( pos + 1 ); 54 | } 55 | 56 | return filepath; 57 | } 58 | 59 | std::string FileSystem::pathRemoveFileName( std::string filepath ) 60 | { 61 | dirRemoveSlashAtEnd( filepath ); 62 | 63 | size_t pos = filepath.find_last_of( getOSSlash() ); 64 | 65 | if ( pos != std::string::npos ) 66 | { 67 | return filepath.substr( 0, pos + 1 ); 68 | } 69 | 70 | return filepath; 71 | } 72 | 73 | std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath ) 74 | { 75 | FileSystem::dirRemoveSlashAtEnd( dir ); 76 | FileInfo fi( dir, true ); 77 | 78 | /// Check with lstat and see if it's a link 79 | if ( fi.isLink() ) 80 | { 81 | /// get the real path of the link 82 | std::string link( fi.linksTo() ); 83 | 84 | /// get the current path of the directory without the link dir path 85 | curPath = FileSystem::pathRemoveFileName( dir ); 86 | 87 | /// ensure that ends with the os directory slash 88 | FileSystem::dirAddSlashAtEnd( link ); 89 | 90 | return link; 91 | } 92 | 93 | /// if it's not a link return nothing 94 | return ""; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/efsw/FileSystem.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILESYSTEM_HPP 2 | #define EFSW_FILESYSTEM_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace efsw { 9 | 10 | class FileSystem 11 | { 12 | public: 13 | static bool isDirectory( const std::string& path ); 14 | 15 | static FileInfoMap filesInfoFromPath( std::string path ); 16 | 17 | static char getOSSlash(); 18 | 19 | static bool slashAtEnd( std::string& dir ); 20 | 21 | static void dirAddSlashAtEnd( std::string& dir ); 22 | 23 | static void dirRemoveSlashAtEnd( std::string& dir ); 24 | 25 | static std::string fileNameFromPath( std::string filepath ); 26 | 27 | static std::string pathRemoveFileName( std::string filepath ); 28 | 29 | static void realPath( std::string curdir, std::string& path ); 30 | 31 | static std::string getLinkRealPath( std::string dir, std::string& curPath ); 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/efsw/FileWatcher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 6 | # include 7 | # define FILEWATCHER_IMPL FileWatcherWin32 8 | # define BACKEND_NAME "Win32" 9 | #elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY 10 | # include 11 | # define FILEWATCHER_IMPL FileWatcherInotify 12 | # define BACKEND_NAME "Inotify" 13 | #elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE 14 | # include 15 | # define FILEWATCHER_IMPL FileWatcherKqueue 16 | # define BACKEND_NAME "Kqueue" 17 | #elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 18 | # include 19 | # define FILEWATCHER_IMPL FileWatcherFSEvents 20 | # define BACKEND_NAME "FSEvents" 21 | #else 22 | # define FILEWATCHER_IMPL FileWatcherGeneric 23 | # define BACKEND_NAME "Generic" 24 | #endif 25 | 26 | #include 27 | 28 | namespace efsw { 29 | 30 | FileWatcher::FileWatcher() : 31 | mFollowSymlinks(false), 32 | mOutOfScopeLinks(false) 33 | { 34 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); 35 | 36 | mImpl = new FILEWATCHER_IMPL( this ); 37 | 38 | if ( !mImpl->initOK() ) 39 | { 40 | efSAFE_DELETE( mImpl ); 41 | 42 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); 43 | 44 | mImpl = new FileWatcherGeneric( this ); 45 | } 46 | } 47 | 48 | FileWatcher::FileWatcher( bool useGenericFileWatcher ) : 49 | mFollowSymlinks(false), 50 | mOutOfScopeLinks(false) 51 | { 52 | if ( useGenericFileWatcher ) 53 | { 54 | efDEBUG( "Using backend: Generic\n" ); 55 | 56 | mImpl = new FileWatcherGeneric( this ); 57 | } 58 | else 59 | { 60 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); 61 | 62 | mImpl = new FILEWATCHER_IMPL( this ); 63 | 64 | if ( !mImpl->initOK() ) 65 | { 66 | efSAFE_DELETE( mImpl ); 67 | 68 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); 69 | 70 | mImpl = new FileWatcherGeneric( this ); 71 | } 72 | } 73 | } 74 | 75 | FileWatcher::~FileWatcher() 76 | { 77 | efSAFE_DELETE( mImpl ); 78 | } 79 | 80 | WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher) 81 | { 82 | return mImpl->addWatch(directory, watcher, false); 83 | } 84 | 85 | WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) 86 | { 87 | return mImpl->addWatch(directory, watcher, recursive); 88 | } 89 | 90 | void FileWatcher::removeWatch(const std::string& directory) 91 | { 92 | mImpl->removeWatch(directory); 93 | } 94 | 95 | void FileWatcher::removeWatch(WatchID watchid) 96 | { 97 | mImpl->removeWatch(watchid); 98 | } 99 | 100 | void FileWatcher::watch() 101 | { 102 | mImpl->watch(); 103 | } 104 | 105 | void FileWatcher::followSymlinks( bool follow ) 106 | { 107 | mFollowSymlinks = follow; 108 | } 109 | 110 | const bool& FileWatcher::followSymlinks() const 111 | { 112 | return mFollowSymlinks; 113 | } 114 | 115 | void FileWatcher::allowOutOfScopeLinks( bool allow ) 116 | { 117 | mOutOfScopeLinks = allow; 118 | } 119 | 120 | const bool& FileWatcher::allowOutOfScopeLinks() const 121 | { 122 | return mOutOfScopeLinks; 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherFSEvents.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 8 | 9 | #include 10 | 11 | namespace efsw 12 | { 13 | 14 | int getOSXReleaseNumber() 15 | { 16 | static int osxR = -1; 17 | 18 | if ( -1 == osxR ) 19 | { 20 | struct utsname os; 21 | 22 | if ( -1 != uname( &os ) ) { 23 | std::string release( os.release ); 24 | 25 | size_t pos = release.find_first_of( '.' ); 26 | 27 | if ( pos != std::string::npos ) 28 | { 29 | release = release.substr( 0, pos ); 30 | } 31 | 32 | int rel = 0; 33 | 34 | if ( String::fromString( rel, release ) ) 35 | { 36 | osxR = rel; 37 | } 38 | } 39 | } 40 | 41 | return osxR; 42 | } 43 | 44 | bool FileWatcherFSEvents::isGranular() 45 | { 46 | return getOSXReleaseNumber() >= 11; 47 | } 48 | 49 | void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef, 50 | void *userData, 51 | size_t numEvents, 52 | void *eventPaths, 53 | const FSEventStreamEventFlags eventFlags[], 54 | const FSEventStreamEventId eventIds[] ) 55 | { 56 | WatcherFSEvents * watcher = static_cast( userData ); 57 | 58 | for ( size_t i = 0; i < numEvents; i++ ) 59 | { 60 | watcher->handleAction( std::string( ((char**)eventPaths)[i] ), (long)eventFlags[i] ); 61 | } 62 | 63 | watcher->process(); 64 | } 65 | 66 | FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher * parent ) : 67 | FileWatcherImpl( parent ), 68 | mRunLoopRef( NULL ), 69 | mLastWatchID(0), 70 | mThread( NULL ) 71 | { 72 | mInitOK = true; 73 | 74 | watch(); 75 | } 76 | 77 | FileWatcherFSEvents::~FileWatcherFSEvents() 78 | { 79 | WatchMap::iterator iter = mWatches.begin(); 80 | 81 | for( ; iter != mWatches.end(); ++iter ) 82 | { 83 | WatcherFSEvents * watch = iter->second; 84 | 85 | efSAFE_DELETE( watch ); 86 | } 87 | 88 | mWatches.clear(); 89 | 90 | mInitOK = false; 91 | 92 | if ( NULL != mRunLoopRef ) 93 | { 94 | CFRunLoopStop( mRunLoopRef ); 95 | } 96 | 97 | mThread->wait(); 98 | 99 | efSAFE_DELETE( mThread ); 100 | } 101 | 102 | WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ) 103 | { 104 | /// Wait to the RunLoopRef to be ready 105 | while ( NULL == mRunLoopRef ) 106 | { 107 | System::sleep( 1 ); 108 | } 109 | 110 | std::string dir( directory ); 111 | 112 | FileSystem::dirAddSlashAtEnd( dir ); 113 | 114 | if ( pathInWatches( dir ) ) 115 | { 116 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); 117 | } 118 | 119 | /// Check if the directory is a symbolic link 120 | std::string curPath; 121 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); 122 | 123 | if ( "" != link ) 124 | { 125 | /// If it's a symlink check if the realpath exists as a watcher, or 126 | /// if the path is outside the current dir 127 | if ( pathInWatches( link ) ) 128 | { 129 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); 130 | } 131 | else if ( !linkAllowed( curPath, link ) ) 132 | { 133 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); 134 | } 135 | else 136 | { 137 | dir = link; 138 | } 139 | } 140 | 141 | mLastWatchID++; 142 | 143 | WatcherFSEvents * pWatch = new WatcherFSEvents(); 144 | pWatch->Listener = watcher; 145 | pWatch->ID = mLastWatchID; 146 | pWatch->Directory = dir; 147 | pWatch->Recursive = recursive; 148 | pWatch->FWatcher = this; 149 | 150 | pWatch->init(); 151 | 152 | mWatchesLock.lock(); 153 | mWatches.insert(std::make_pair(mLastWatchID, pWatch)); 154 | mWatchesLock.unlock(); 155 | 156 | return pWatch->ID; 157 | } 158 | 159 | void FileWatcherFSEvents::removeWatch(const std::string& directory) 160 | { 161 | mWatchesLock.lock(); 162 | 163 | WatchMap::iterator iter = mWatches.begin(); 164 | 165 | for(; iter != mWatches.end(); ++iter) 166 | { 167 | if( directory == iter->second->Directory ) 168 | { 169 | removeWatch( iter->second->ID ); 170 | return; 171 | } 172 | } 173 | 174 | mWatchesLock.unlock(); 175 | } 176 | 177 | void FileWatcherFSEvents::removeWatch(WatchID watchid) 178 | { 179 | mWatchesLock.lock(); 180 | 181 | WatchMap::iterator iter = mWatches.find( watchid ); 182 | 183 | if( iter == mWatches.end() ) 184 | return; 185 | 186 | WatcherFSEvents * watch = iter->second; 187 | 188 | mWatches.erase( iter ); 189 | 190 | efDEBUG( "Removed watch %s\n", watch->Directory.c_str() ); 191 | 192 | efSAFE_DELETE( watch ); 193 | 194 | mWatchesLock.unlock(); 195 | } 196 | 197 | void FileWatcherFSEvents::watch() 198 | { 199 | if ( NULL == mThread ) 200 | { 201 | mThread = new Thread( &FileWatcherFSEvents::run, this ); 202 | mThread->launch(); 203 | } 204 | } 205 | 206 | void FileWatcherFSEvents::run() 207 | { 208 | mRunLoopRef = CFRunLoopGetCurrent(); 209 | 210 | while ( mInitOK ) 211 | { 212 | if ( !mNeedInit.empty() ) 213 | { 214 | for ( std::list::iterator it = mNeedInit.begin(); it != mNeedInit.end(); it++ ) 215 | { 216 | (*it)->initAsync(); 217 | } 218 | 219 | mNeedInit.clear(); 220 | } 221 | 222 | CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut ); 223 | } 224 | } 225 | 226 | void FileWatcherFSEvents::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename) 227 | { 228 | /// Not used 229 | } 230 | 231 | std::list FileWatcherFSEvents::directories() 232 | { 233 | std::list dirs; 234 | 235 | mWatchesLock.lock(); 236 | 237 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 238 | { 239 | dirs.push_back( std::string( it->second->Directory ) ); 240 | } 241 | 242 | mWatchesLock.unlock(); 243 | 244 | return dirs; 245 | } 246 | 247 | bool FileWatcherFSEvents::pathInWatches( const std::string& path ) 248 | { 249 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 250 | { 251 | if ( it->second->Directory == path ) 252 | { 253 | return true; 254 | } 255 | } 256 | 257 | return false; 258 | } 259 | 260 | } 261 | 262 | #endif 263 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherFSEvents.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERFSEVENTS_HPP 2 | #define EFSW_FILEWATCHERFSEVENTS_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace efsw 15 | { 16 | 17 | /* OSX < 10.7 has no file events */ 18 | /* So i declare the events constants */ 19 | enum FSEventEvents 20 | { 21 | efswFSEventStreamCreateFlagFileEvents = 0x00000010, 22 | efswFSEventStreamEventFlagItemCreated = 0x00000100, 23 | efswFSEventStreamEventFlagItemRemoved = 0x00000200, 24 | efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, 25 | efswFSEventStreamEventFlagItemRenamed = 0x00000800, 26 | efswFSEventStreamEventFlagItemModified = 0x00001000, 27 | efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, 28 | efswFSEventStreamEventFlagItemChangeOwner = 0x00004000, 29 | efswFSEventStreamEventFlagItemXattrMod = 0x00008000, 30 | efswFSEventStreamEventFlagItemIsFile = 0x00010000, 31 | efswFSEventStreamEventFlagItemIsDir = 0x00020000, 32 | efswFSEventStreamEventFlagItemIsSymlink = 0x00040000, 33 | efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod | 34 | efswFSEventStreamEventFlagItemModified | 35 | efswFSEventStreamEventFlagItemInodeMetaMod | 36 | efswFSEventStreamEventFlagItemChangeOwner | 37 | efswFSEventStreamEventFlagItemXattrMod 38 | }; 39 | 40 | 41 | /// Implementation for Win32 based on ReadDirectoryChangesW. 42 | /// @class FileWatcherFSEvents 43 | class FileWatcherFSEvents : public FileWatcherImpl 44 | { 45 | friend class WatcherFSEvents; 46 | public: 47 | /// @return If FSEvents supports file-level notifications ( true if OS X >= 10.7 ) 48 | static bool isGranular(); 49 | 50 | /// type for a map from WatchID to WatcherWin32 pointer 51 | typedef std::map WatchMap; 52 | 53 | FileWatcherFSEvents( FileWatcher * parent ); 54 | 55 | virtual ~FileWatcherFSEvents(); 56 | 57 | /// Add a directory watch 58 | /// On error returns WatchID with Error type. 59 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 60 | 61 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 62 | void removeWatch(const std::string& directory); 63 | 64 | /// Remove a directory watch. This is a map lookup O(logn). 65 | void removeWatch(WatchID watchid); 66 | 67 | /// Updates the watcher. Must be called often. 68 | void watch(); 69 | 70 | /// Handles the action 71 | void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 72 | 73 | /// @return Returns a list of the directories that are being watched 74 | std::list directories(); 75 | protected: 76 | static void FSEventCallback( ConstFSEventStreamRef streamRef, 77 | void *userData, 78 | size_t numEvents, 79 | void *eventPaths, 80 | const FSEventStreamEventFlags eventFlags[], 81 | const FSEventStreamEventId eventIds[] 82 | ); 83 | 84 | CFRunLoopRef mRunLoopRef; 85 | 86 | /// Vector of WatcherWin32 pointers 87 | WatchMap mWatches; 88 | 89 | /// The last watchid 90 | WatchID mLastWatchID; 91 | 92 | Thread * mThread; 93 | 94 | Mutex mWatchesLock; 95 | 96 | bool pathInWatches( const std::string& path ); 97 | 98 | std::list mNeedInit; 99 | private: 100 | void run(); 101 | }; 102 | 103 | } 104 | 105 | #endif 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherGeneric.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace efsw 6 | { 7 | 8 | FileWatcherGeneric::FileWatcherGeneric( FileWatcher * parent ) : 9 | FileWatcherImpl( parent ), 10 | mThread( NULL ), 11 | mLastWatchID( 0 ) 12 | { 13 | mInitOK = true; 14 | } 15 | 16 | FileWatcherGeneric::~FileWatcherGeneric() 17 | { 18 | mInitOK = false; 19 | 20 | mThread->wait(); 21 | 22 | efSAFE_DELETE( mThread ); 23 | 24 | /// Delete the watches 25 | WatchList::iterator it = mWatches.begin(); 26 | 27 | for ( ; it != mWatches.end(); it++ ) 28 | { 29 | efSAFE_DELETE( (*it) ); 30 | } 31 | } 32 | 33 | WatchID FileWatcherGeneric::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) 34 | { 35 | std::string dir( directory ); 36 | 37 | FileSystem::dirAddSlashAtEnd( dir ); 38 | 39 | FileInfo fi( dir ); 40 | 41 | if ( !fi.isDirectory() ) 42 | { 43 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); 44 | } 45 | else if ( !fi.isReadable() ) 46 | { 47 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); 48 | } 49 | else if ( pathInWatches( dir ) ) 50 | { 51 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); 52 | } 53 | 54 | std::string curPath; 55 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); 56 | 57 | if ( "" != link ) 58 | { 59 | if ( pathInWatches( link ) ) 60 | { 61 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); 62 | } 63 | else if ( !linkAllowed( curPath, link ) ) 64 | { 65 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); 66 | } 67 | else 68 | { 69 | dir = link; 70 | } 71 | } 72 | 73 | mLastWatchID++; 74 | 75 | WatcherGeneric * pWatch = new WatcherGeneric( mLastWatchID, dir, watcher, this, recursive ); 76 | 77 | mWatchesLock.lock(); 78 | mWatches.push_back(pWatch); 79 | mWatchesLock.unlock(); 80 | 81 | return pWatch->ID; 82 | } 83 | 84 | void FileWatcherGeneric::removeWatch( const std::string& directory ) 85 | { 86 | WatchList::iterator it = mWatches.begin(); 87 | 88 | for ( ; it != mWatches.end(); it++ ) 89 | { 90 | if ( (*it)->Directory == directory ) 91 | { 92 | WatcherGeneric * watch = (*it); 93 | 94 | mWatchesLock.lock(); 95 | 96 | mWatches.erase( it ); 97 | 98 | efSAFE_DELETE( watch ) ; 99 | 100 | mWatchesLock.unlock(); 101 | 102 | return; 103 | } 104 | } 105 | } 106 | 107 | void FileWatcherGeneric::removeWatch(WatchID watchid) 108 | { 109 | WatchList::iterator it = mWatches.begin(); 110 | 111 | for ( ; it != mWatches.end(); it++ ) 112 | { 113 | if ( (*it)->ID == watchid ) 114 | { 115 | WatcherGeneric * watch = (*it); 116 | 117 | mWatchesLock.lock(); 118 | 119 | mWatches.erase( it ); 120 | 121 | efSAFE_DELETE( watch ) ; 122 | 123 | mWatchesLock.unlock(); 124 | 125 | return; 126 | } 127 | } 128 | } 129 | 130 | void FileWatcherGeneric::watch() 131 | { 132 | if ( NULL == mThread ) 133 | { 134 | mThread = new Thread( &FileWatcherGeneric::run, this ); 135 | mThread->launch(); 136 | } 137 | } 138 | 139 | void FileWatcherGeneric::run() 140 | { 141 | do 142 | { 143 | mWatchesLock.lock(); 144 | 145 | WatchList::iterator it = mWatches.begin(); 146 | 147 | for ( ; it != mWatches.end(); it++ ) 148 | { 149 | (*it)->watch(); 150 | } 151 | 152 | mWatchesLock.unlock(); 153 | 154 | if ( mInitOK ) System::sleep( 1000 ); 155 | } while ( mInitOK ); 156 | } 157 | 158 | void FileWatcherGeneric::handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename) 159 | { 160 | /// Not used 161 | } 162 | 163 | std::list FileWatcherGeneric::directories() 164 | { 165 | std::list dirs; 166 | 167 | mWatchesLock.lock(); 168 | 169 | WatchList::iterator it = mWatches.begin(); 170 | 171 | for ( ; it != mWatches.end(); it++ ) 172 | { 173 | dirs.push_back( (*it)->Directory ); 174 | } 175 | 176 | mWatchesLock.unlock(); 177 | 178 | return dirs; 179 | } 180 | 181 | bool FileWatcherGeneric::pathInWatches( const std::string& path ) 182 | { 183 | WatchList::iterator it = mWatches.begin(); 184 | 185 | for ( ; it != mWatches.end(); it++ ) 186 | { 187 | if ( (*it)->Directory == path || (*it)->pathInWatches( path ) ) 188 | { 189 | return true; 190 | } 191 | } 192 | 193 | return false; 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherGeneric.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERGENERIC_HPP 2 | #define EFSW_FILEWATCHERGENERIC_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace efsw 10 | { 11 | 12 | /// Implementation for Generic File Watcher. 13 | /// @class FileWatcherGeneric 14 | class FileWatcherGeneric : public FileWatcherImpl 15 | { 16 | public: 17 | typedef std::list WatchList; 18 | 19 | FileWatcherGeneric( FileWatcher * parent ); 20 | 21 | virtual ~FileWatcherGeneric(); 22 | 23 | /// Add a directory watch 24 | /// On error returns WatchID with Error type. 25 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 26 | 27 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 28 | void removeWatch(const std::string& directory); 29 | 30 | /// Remove a directory watch. This is a map lookup O(logn). 31 | void removeWatch(WatchID watchid); 32 | 33 | /// Updates the watcher. Must be called often. 34 | void watch(); 35 | 36 | /// Handles the action 37 | void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 38 | 39 | /// @return Returns a list of the directories that are being watched 40 | std::list directories(); 41 | protected: 42 | Thread * mThread; 43 | 44 | /// The last watchid 45 | WatchID mLastWatchID; 46 | 47 | /// Map of WatchID to WatchStruct pointers 48 | WatchList mWatches; 49 | 50 | Mutex mWatchesLock; 51 | 52 | bool pathInWatches( const std::string& path ); 53 | private: 54 | void run(); 55 | }; 56 | 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace efsw { 6 | 7 | FileWatcherImpl::FileWatcherImpl( FileWatcher * parent ) : 8 | mFileWatcher( parent ), 9 | mInitOK( false ) 10 | { 11 | System::maxFD(); 12 | } 13 | 14 | FileWatcherImpl::~FileWatcherImpl() 15 | { 16 | } 17 | 18 | bool FileWatcherImpl::initOK() 19 | { 20 | return mInitOK; 21 | } 22 | 23 | bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) 24 | { 25 | return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || -1 != String::strStartsWith( curPath, link ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERIMPL_HPP 2 | #define EFSW_FILEWATCHERIMPL_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace efsw { 11 | 12 | class FileWatcherImpl 13 | { 14 | public: 15 | FileWatcherImpl( FileWatcher * parent ); 16 | 17 | virtual ~FileWatcherImpl(); 18 | 19 | /// Add a directory watch 20 | /// On error returns WatchID with Error type. 21 | virtual WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) = 0; 22 | 23 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 24 | virtual void removeWatch(const std::string& directory) = 0; 25 | 26 | /// Remove a directory watch. This is a map lookup O(logn). 27 | virtual void removeWatch(WatchID watchid) = 0; 28 | 29 | /// Updates the watcher. Must be called often. 30 | virtual void watch() = 0; 31 | 32 | /// Handles the action 33 | virtual void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "") = 0; 34 | 35 | /// @return Returns a list of the directories that are being watched 36 | virtual std::list directories() = 0; 37 | 38 | /// @return true if the backend init successfully 39 | virtual bool initOK(); 40 | 41 | /// @return If the link is allowed according to the current path and the state of out scope links 42 | virtual bool linkAllowed( const std::string& curPath, const std::string& link ); 43 | 44 | /// Search if a directory already exists in the watches 45 | virtual bool pathInWatches( const std::string& path ) = 0; 46 | 47 | FileWatcher * mFileWatcher; 48 | bool mInitOK; 49 | }; 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherInotify.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024) 17 | 18 | namespace efsw 19 | { 20 | 21 | FileWatcherInotify::FileWatcherInotify( FileWatcher * parent ) : 22 | FileWatcherImpl( parent ), 23 | mFD(-1), 24 | mThread(NULL) 25 | { 26 | mFD = inotify_init(); 27 | 28 | if (mFD < 0) 29 | { 30 | efDEBUG( "Error: %s\n", strerror(errno) ); 31 | } 32 | else 33 | { 34 | mInitOK = true; 35 | } 36 | } 37 | 38 | FileWatcherInotify::~FileWatcherInotify() 39 | { 40 | WatchMap::iterator iter = mWatches.begin(); 41 | WatchMap::iterator end = mWatches.end(); 42 | 43 | for(; iter != end; ++iter) 44 | { 45 | efSAFE_DELETE( iter->second ); 46 | } 47 | 48 | mWatches.clear(); 49 | 50 | if ( mFD != -1 ) 51 | { 52 | close(mFD); 53 | mFD = -1; 54 | } 55 | 56 | if ( mThread ) 57 | { 58 | mThread->terminate(); 59 | } 60 | 61 | efSAFE_DELETE( mThread ); 62 | } 63 | 64 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ) 65 | { 66 | return addWatch( directory, watcher, recursive, NULL ); 67 | } 68 | 69 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent ) 70 | { 71 | std::string dir( directory ); 72 | 73 | FileSystem::dirAddSlashAtEnd( dir ); 74 | 75 | FileInfo fi( dir ); 76 | 77 | if ( !fi.isDirectory() ) 78 | { 79 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); 80 | } 81 | else if ( !fi.isReadable() ) 82 | { 83 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); 84 | } 85 | else if ( pathInWatches( dir ) ) 86 | { 87 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); 88 | } 89 | 90 | /// Check if the directory is a symbolic link 91 | std::string curPath; 92 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); 93 | 94 | if ( "" != link ) 95 | { 96 | /// Avoid adding symlinks directories if it's now enabled 97 | if ( NULL != parent && !mFileWatcher->followSymlinks() ) 98 | { 99 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); 100 | } 101 | 102 | /// If it's a symlink check if the realpath exists as a watcher, or 103 | /// if the path is outside the current dir 104 | if ( pathInWatches( link ) ) 105 | { 106 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); 107 | } 108 | else if ( !linkAllowed( curPath, link ) ) 109 | { 110 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); 111 | } 112 | else 113 | { 114 | dir = link; 115 | } 116 | } 117 | 118 | int wd = inotify_add_watch (mFD, dir.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE); 119 | 120 | if ( wd < 0 ) 121 | { 122 | if( errno == ENOENT ) 123 | { 124 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); 125 | } 126 | else 127 | { 128 | return Errors::Log::createLastError( Errors::Unspecified, std::string(strerror(errno)) ); 129 | } 130 | } 131 | 132 | WatcherInotify * pWatch = new WatcherInotify(); 133 | pWatch->Listener = watcher; 134 | pWatch->ID = wd; 135 | pWatch->Directory = dir; 136 | pWatch->Recursive = recursive; 137 | pWatch->Parent = parent; 138 | 139 | mWatchesLock.lock(); 140 | mWatches.insert(std::make_pair(wd, pWatch)); 141 | mWatchesLock.unlock(); 142 | 143 | if ( NULL == pWatch->Parent ) 144 | { 145 | mRealWatches[ pWatch->ID ] = pWatch; 146 | } 147 | 148 | if ( pWatch->Recursive ) 149 | { 150 | std::map files = FileSystem::filesInfoFromPath( pWatch->Directory ); 151 | std::map::iterator it = files.begin(); 152 | 153 | for ( ; it != files.end(); it++ ) 154 | { 155 | FileInfo fi = it->second; 156 | 157 | if ( fi.isDirectory() && fi.isReadable() ) 158 | { 159 | addWatch( fi.Filepath, watcher, recursive, pWatch ); 160 | } 161 | } 162 | } 163 | 164 | return wd; 165 | } 166 | 167 | void FileWatcherInotify::removeWatch(const std::string& directory) 168 | { 169 | mWatchesLock.lock(); 170 | 171 | WatchMap::iterator iter = mWatches.begin(); 172 | 173 | for(; iter != mWatches.end(); ++iter) 174 | { 175 | if( directory == iter->second->Directory ) 176 | { 177 | WatcherInotify * watch = iter->second; 178 | 179 | if ( watch->Recursive ) 180 | { 181 | WatchMap::iterator it = mWatches.begin(); 182 | std::list eraseWatches; 183 | 184 | for(; it != mWatches.end(); ++it) 185 | { 186 | if ( it->second->inParentTree( watch ) ) 187 | { 188 | eraseWatches.push_back( it->second->ID ); 189 | } 190 | } 191 | 192 | for ( std::list::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); eit++ ) 193 | { 194 | removeWatch( *eit ); 195 | } 196 | } 197 | 198 | mWatches.erase( iter ); 199 | 200 | if ( NULL == watch->Parent ) 201 | { 202 | WatchMap::iterator eraseit = mRealWatches.find( watch->ID ); 203 | 204 | if ( eraseit != mRealWatches.end() ) 205 | { 206 | mRealWatches.erase( eraseit ); 207 | } 208 | } 209 | 210 | inotify_rm_watch(mFD, watch->ID); 211 | 212 | efSAFE_DELETE( watch ); 213 | 214 | return; 215 | } 216 | } 217 | 218 | mWatchesLock.unlock(); 219 | } 220 | 221 | void FileWatcherInotify::removeWatch( WatchID watchid ) 222 | { 223 | mWatchesLock.lock(); 224 | 225 | WatchMap::iterator iter = mWatches.find( watchid ); 226 | 227 | if( iter == mWatches.end() ) 228 | return; 229 | 230 | WatcherInotify * watch = iter->second; 231 | 232 | if ( watch->Recursive ) 233 | { 234 | WatchMap::iterator it = mWatches.begin(); 235 | std::list eraseWatches; 236 | 237 | for(; it != mWatches.end(); ++it) 238 | { 239 | if ( it->second != watch && 240 | it->second->inParentTree( watch ) 241 | ) 242 | { 243 | eraseWatches.push_back( it->second->ID ); 244 | } 245 | } 246 | 247 | for ( std::list::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); eit++ ) 248 | { 249 | removeWatch( *eit ); 250 | } 251 | } 252 | 253 | mWatches.erase( iter ); 254 | 255 | if ( NULL == watch->Parent ) 256 | { 257 | WatchMap::iterator eraseit = mRealWatches.find( watch->ID ); 258 | 259 | if ( eraseit != mRealWatches.end() ) 260 | { 261 | mRealWatches.erase( eraseit ); 262 | } 263 | } 264 | 265 | efDEBUG( "Removed watch %s\n", watch->Directory.c_str() ); 266 | 267 | inotify_rm_watch(mFD, watchid); 268 | 269 | efSAFE_DELETE( watch ); 270 | 271 | mWatchesLock.unlock(); 272 | } 273 | 274 | void FileWatcherInotify::watch() 275 | { 276 | if ( NULL == mThread ) 277 | { 278 | mThread = new Thread( &FileWatcherInotify::run, this ); 279 | mThread->launch(); 280 | } 281 | } 282 | 283 | void FileWatcherInotify::run() 284 | { 285 | WatchMap::iterator wit; 286 | 287 | do 288 | { 289 | ssize_t len, i = 0; 290 | static char buff[BUFF_SIZE] = {0}; 291 | 292 | len = read (mFD, buff, BUFF_SIZE); 293 | 294 | if (len != -1) 295 | { 296 | while (i < len) 297 | { 298 | struct inotify_event *pevent = (struct inotify_event *)&buff[i]; 299 | 300 | mWatchesLock.lock(); 301 | 302 | wit = mWatches.find( pevent->wd ); 303 | 304 | if ( wit != mWatches.end() ) 305 | { 306 | handleAction(wit->second, pevent->name, pevent->mask); 307 | } 308 | 309 | mWatchesLock.unlock(); 310 | 311 | i += sizeof(struct inotify_event) + pevent->len; 312 | } 313 | } 314 | } while( mFD > 0 ); 315 | } 316 | 317 | void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename ) 318 | { 319 | if ( !watch || !watch->Listener ) 320 | { 321 | return; 322 | } 323 | 324 | std::string fpath( watch->Directory + filename ); 325 | 326 | if( IN_CLOSE_WRITE & action ) 327 | { 328 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename,Actions::Modified ); 329 | } 330 | else if( IN_MOVED_TO & action ) 331 | { 332 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Moved, watch->OldFileName ); 333 | 334 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) 335 | { 336 | /// Update the new directory path 337 | std::string opath( watch->Directory + watch->OldFileName ); 338 | FileSystem::dirAddSlashAtEnd( opath ); 339 | FileSystem::dirAddSlashAtEnd( fpath ); 340 | 341 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 342 | { 343 | if ( it->second->Directory == opath ) 344 | { 345 | it->second->Directory = fpath; 346 | 347 | break; 348 | } 349 | } 350 | } 351 | 352 | watch->OldFileName = ""; 353 | } 354 | else if( IN_CREATE & action ) 355 | { 356 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add ); 357 | 358 | /// If the watcher is recursive, checks if the new file is a folder, and creates a watcher 359 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) 360 | { 361 | bool found = false; 362 | 363 | /// First check if exists 364 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 365 | { 366 | if ( it->second->Directory == fpath ) 367 | { 368 | found = true; 369 | break; 370 | } 371 | } 372 | 373 | if ( !found ) 374 | { 375 | addWatch( fpath, watch->Listener, watch->Recursive, static_cast( watch ) ); 376 | } 377 | } 378 | } 379 | else if ( IN_MOVED_FROM & action ) 380 | { 381 | watch->OldFileName = filename; 382 | } 383 | else if( IN_DELETE & action ) 384 | { 385 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete ); 386 | 387 | /// If the file erased is a directory and recursive is enabled, removes the directory erased 388 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) 389 | { 390 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 391 | { 392 | if ( it->second->Directory == fpath ) 393 | { 394 | removeWatch( it->second->ID ); 395 | break; 396 | } 397 | } 398 | } 399 | } 400 | } 401 | 402 | std::list FileWatcherInotify::directories() 403 | { 404 | std::list dirs; 405 | 406 | mWatchesLock.lock(); 407 | 408 | WatchMap::iterator it = mRealWatches.begin(); 409 | 410 | for ( ; it != mRealWatches.end(); it++ ) 411 | { 412 | dirs.push_back( it->second->Directory ); 413 | } 414 | 415 | mWatchesLock.unlock(); 416 | 417 | return dirs; 418 | } 419 | 420 | bool FileWatcherInotify::pathInWatches( const std::string& path ) 421 | { 422 | /// Search in the real watches, since it must allow adding a watch already watched as a subdir 423 | WatchMap::iterator it = mRealWatches.begin(); 424 | 425 | for ( ; it != mRealWatches.end(); it++ ) 426 | { 427 | if ( it->second->Directory == path ) 428 | { 429 | return true; 430 | } 431 | } 432 | 433 | return false; 434 | } 435 | 436 | } 437 | 438 | #endif 439 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherInotify.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERLINUX_HPP 2 | #define EFSW_FILEWATCHERLINUX_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY 7 | 8 | #include 9 | #include 10 | 11 | namespace efsw 12 | { 13 | 14 | /// Implementation for Linux based on inotify. 15 | /// @class FileWatcherInotify 16 | class FileWatcherInotify : public FileWatcherImpl 17 | { 18 | public: 19 | /// type for a map from WatchID to WatchStruct pointer 20 | typedef std::map WatchMap; 21 | 22 | FileWatcherInotify( FileWatcher * parent ); 23 | 24 | virtual ~FileWatcherInotify(); 25 | 26 | /// Add a directory watch 27 | /// On error returns WatchID with Error type. 28 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 29 | 30 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 31 | void removeWatch(const std::string& directory); 32 | 33 | /// Remove a directory watch. This is a map lookup O(logn). 34 | void removeWatch(WatchID watchid); 35 | 36 | /// Updates the watcher. Must be called often. 37 | void watch(); 38 | 39 | /// Handles the action 40 | void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 41 | 42 | /// @return Returns a list of the directories that are being watched 43 | std::list directories(); 44 | protected: 45 | /// Map of WatchID to WatchStruct pointers 46 | WatchMap mWatches; 47 | 48 | /// User added watches 49 | WatchMap mRealWatches; 50 | 51 | /// inotify file descriptor 52 | int mFD; 53 | 54 | Thread * mThread; 55 | 56 | Mutex mWatchesLock; 57 | 58 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent = NULL ); 59 | 60 | bool pathInWatches( const std::string& path ); 61 | private: 62 | void run(); 63 | }; 64 | 65 | } 66 | 67 | #endif 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherKqueue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace efsw 20 | { 21 | 22 | FileWatcherKqueue::FileWatcherKqueue( FileWatcher * parent ) : 23 | FileWatcherImpl( parent ), 24 | mLastWatchID(0), 25 | mThread( NULL ), 26 | mFileDescriptorCount( 1 ), 27 | mAddingWatcher( false ) 28 | { 29 | mTimeOut.tv_sec = 0; 30 | mTimeOut.tv_nsec = 0; 31 | mInitOK = true; 32 | } 33 | 34 | FileWatcherKqueue::~FileWatcherKqueue() 35 | { 36 | WatchMap::iterator iter = mWatches.begin(); 37 | 38 | for(; iter != mWatches.end(); ++iter) 39 | { 40 | efSAFE_DELETE( iter->second ); 41 | } 42 | 43 | mWatches.clear(); 44 | 45 | mInitOK = false; 46 | 47 | mThread->wait(); 48 | 49 | efSAFE_DELETE( mThread ); 50 | } 51 | 52 | WatchID FileWatcherKqueue::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) 53 | { 54 | static bool s_ug = false; 55 | 56 | std::string dir( directory ); 57 | 58 | FileSystem::dirAddSlashAtEnd( dir ); 59 | 60 | FileInfo fi( dir ); 61 | 62 | if ( !fi.isDirectory() ) 63 | { 64 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); 65 | } 66 | else if ( !fi.isReadable() ) 67 | { 68 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); 69 | } 70 | else if ( pathInWatches( dir ) ) 71 | { 72 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); 73 | } 74 | 75 | std::string curPath; 76 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); 77 | 78 | if ( "" != link ) 79 | { 80 | if ( pathInWatches( link ) ) 81 | { 82 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); 83 | } 84 | else if ( !linkAllowed( curPath, link ) ) 85 | { 86 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); 87 | } 88 | else 89 | { 90 | dir = link; 91 | } 92 | } 93 | 94 | /// Check first if are enough file descriptors available to create another kqueue watcher, otherwise it creates a generic watcher 95 | if ( availablesFD() ) 96 | { 97 | mAddingWatcher = true; 98 | 99 | WatcherKqueue * watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this ); 100 | 101 | mWatchesLock.lock(); 102 | mWatches.insert(std::make_pair(mLastWatchID, watch)); 103 | mWatchesLock.unlock(); 104 | 105 | watch->addAll(); 106 | 107 | // if failed to open the directory... erase the watcher 108 | if ( !watch->initOK() ) 109 | { 110 | int le = watch->lastErrno(); 111 | 112 | mWatches.erase( watch->ID ); 113 | 114 | efSAFE_DELETE( watch ); 115 | 116 | mLastWatchID--; 117 | 118 | // Probably the folder has too many files, create a generic watcher 119 | if ( EACCES != le ) 120 | { 121 | WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); 122 | 123 | mWatchesLock.lock(); 124 | mWatches.insert(std::make_pair(mLastWatchID, watch)); 125 | mWatchesLock.unlock(); 126 | } 127 | else 128 | { 129 | return Errors::Log::createLastError( Errors::Unspecified, link ); 130 | } 131 | } 132 | 133 | mAddingWatcher = false; 134 | } 135 | else 136 | { 137 | if ( !s_ug ) 138 | { 139 | efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", mFileDescriptorCount ); 140 | s_ug = true; 141 | } 142 | 143 | WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); 144 | 145 | mWatchesLock.lock(); 146 | mWatches.insert(std::make_pair(mLastWatchID, watch)); 147 | mWatchesLock.unlock(); 148 | } 149 | 150 | return mLastWatchID; 151 | } 152 | 153 | void FileWatcherKqueue::removeWatch(const std::string& directory) 154 | { 155 | mWatchesLock.lock(); 156 | 157 | WatchMap::iterator iter = mWatches.begin(); 158 | 159 | for(; iter != mWatches.end(); ++iter) 160 | { 161 | if(directory == iter->second->Directory) 162 | { 163 | removeWatch(iter->first); 164 | return; 165 | } 166 | } 167 | 168 | mWatchesLock.unlock(); 169 | } 170 | 171 | void FileWatcherKqueue::removeWatch(WatchID watchid) 172 | { 173 | mWatchesLock.lock(); 174 | 175 | WatchMap::iterator iter = mWatches.find(watchid); 176 | 177 | if(iter == mWatches.end()) 178 | return; 179 | 180 | Watcher* watch = iter->second; 181 | 182 | mWatches.erase(iter); 183 | 184 | efSAFE_DELETE( watch ); 185 | 186 | mWatchesLock.unlock(); 187 | } 188 | 189 | bool FileWatcherKqueue::isAddingWatcher() const 190 | { 191 | return mAddingWatcher; 192 | } 193 | 194 | void FileWatcherKqueue::watch() 195 | { 196 | if ( NULL == mThread ) 197 | { 198 | mThread = new Thread( &FileWatcherKqueue::run, this ); 199 | mThread->launch(); 200 | } 201 | } 202 | 203 | void FileWatcherKqueue::run() 204 | { 205 | do 206 | { 207 | mWatchesLock.lock(); 208 | 209 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) 210 | { 211 | it->second->watch(); 212 | } 213 | 214 | mWatchesLock.unlock(); 215 | 216 | System::sleep( 500 ); 217 | } while( mInitOK ); 218 | } 219 | 220 | void FileWatcherKqueue::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename) 221 | { 222 | } 223 | 224 | std::list FileWatcherKqueue::directories() 225 | { 226 | std::list dirs; 227 | 228 | mWatchesLock.lock(); 229 | 230 | WatchMap::iterator it = mWatches.begin(); 231 | 232 | for ( ; it != mWatches.end(); it++ ) 233 | { 234 | dirs.push_back( it->second->Directory ); 235 | } 236 | 237 | mWatchesLock.unlock(); 238 | 239 | return dirs; 240 | } 241 | 242 | bool FileWatcherKqueue::pathInWatches( const std::string& path ) 243 | { 244 | WatchMap::iterator it = mWatches.begin(); 245 | 246 | for ( ; it != mWatches.end(); it++ ) 247 | { 248 | if ( it->second->Directory == path ) 249 | { 250 | return true; 251 | } 252 | } 253 | 254 | return false; 255 | } 256 | 257 | void FileWatcherKqueue::addFD() 258 | { 259 | mFileDescriptorCount++; 260 | } 261 | 262 | void FileWatcherKqueue::removeFD() 263 | { 264 | mFileDescriptorCount--; 265 | } 266 | 267 | bool FileWatcherKqueue::availablesFD() 268 | { 269 | return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500; 270 | } 271 | 272 | } 273 | 274 | #endif 275 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherKqueue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHEROSX_HPP 2 | #define EFSW_FILEWATCHEROSX_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 7 | 8 | #include 9 | 10 | namespace efsw 11 | { 12 | 13 | /// Implementation for OSX based on kqueue. 14 | /// @class FileWatcherKqueue 15 | class FileWatcherKqueue : public FileWatcherImpl 16 | { 17 | friend class WatcherKqueue; 18 | public: 19 | FileWatcherKqueue( FileWatcher * parent ); 20 | 21 | virtual ~FileWatcherKqueue(); 22 | 23 | /// Add a directory watch 24 | /// On error returns WatchID with Error type. 25 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 26 | 27 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 28 | void removeWatch(const std::string& directory); 29 | 30 | /// Remove a directory watch. This is a map lookup O(logn). 31 | void removeWatch(WatchID watchid); 32 | 33 | /// Updates the watcher. Must be called often. 34 | void watch(); 35 | 36 | /// Handles the action 37 | void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 38 | 39 | /// @return Returns a list of the directories that are being watched 40 | std::list directories(); 41 | protected: 42 | /// Map of WatchID to WatchStruct pointers 43 | WatchMap mWatches; 44 | 45 | /// time out data 46 | struct timespec mTimeOut; 47 | 48 | /// WatchID allocator 49 | int mLastWatchID; 50 | 51 | Thread * mThread; 52 | 53 | Mutex mWatchesLock; 54 | 55 | std::list mRemoveList; 56 | 57 | long mFileDescriptorCount; 58 | 59 | bool mAddingWatcher; 60 | 61 | bool isAddingWatcher() const; 62 | 63 | bool pathInWatches( const std::string& path ); 64 | 65 | void addFD(); 66 | 67 | void removeFD(); 68 | 69 | bool availablesFD(); 70 | private: 71 | void run(); 72 | }; 73 | 74 | } 75 | 76 | #endif 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherWin32.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 6 | 7 | namespace efsw 8 | { 9 | 10 | FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) : 11 | FileWatcherImpl( parent ), 12 | mLastWatchID(0), 13 | mThread( NULL ) 14 | { 15 | mInitOK = true; 16 | } 17 | 18 | FileWatcherWin32::~FileWatcherWin32() 19 | { 20 | WatchVector::iterator iter = mWatches.begin(); 21 | 22 | for(; iter != mWatches.end(); ++iter) 23 | { 24 | DestroyWatch((*iter)); 25 | } 26 | 27 | mHandles.clear(); 28 | mWatches.clear(); 29 | 30 | mInitOK = false; 31 | 32 | mThread->wait(); 33 | 34 | efSAFE_DELETE( mThread ); 35 | } 36 | 37 | WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) 38 | { 39 | std::string dir( directory ); 40 | 41 | FileInfo fi( dir ); 42 | 43 | if ( !fi.isDirectory() ) 44 | { 45 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); 46 | } 47 | else if ( !fi.isReadable() ) 48 | { 49 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); 50 | } 51 | 52 | FileSystem::dirAddSlashAtEnd( dir ); 53 | 54 | WatchID watchid = ++mLastWatchID; 55 | 56 | WatcherStructWin32 * watch = CreateWatch( dir.c_str(), recursive, FILE_NOTIFY_CHANGE_CREATION | 57 | FILE_NOTIFY_CHANGE_SIZE | 58 | FILE_NOTIFY_CHANGE_FILE_NAME | 59 | FILE_NOTIFY_CHANGE_DIR_NAME 60 | ); 61 | 62 | if( NULL == watch ) 63 | { 64 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); 65 | } 66 | 67 | if ( pathInWatches( dir ) ) 68 | { 69 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); 70 | } 71 | 72 | // Add the handle to the handles vector 73 | watch->Watch->ID = watchid; 74 | watch->Watch->Watch = this; 75 | watch->Watch->Listener = watcher; 76 | watch->Watch->DirName = new char[dir.length()+1]; 77 | strcpy(watch->Watch->DirName, dir.c_str()); 78 | 79 | mWatchesLock.lock(); 80 | mHandles.push_back( watch->Watch->DirHandle ); 81 | mWatches.push_back( watch ); 82 | mWatchesLock.unlock(); 83 | 84 | return watchid; 85 | } 86 | 87 | void FileWatcherWin32::removeWatch(const std::string& directory) 88 | { 89 | mWatchesLock.lock(); 90 | 91 | WatchVector::iterator iter = mWatches.begin(); 92 | 93 | for(; iter != mWatches.end(); ++iter) 94 | { 95 | if(directory == (*iter)->Watch->DirName) 96 | { 97 | removeWatch((*iter)->Watch->ID); 98 | return; 99 | } 100 | } 101 | 102 | mWatchesLock.unlock(); 103 | } 104 | 105 | void FileWatcherWin32::removeWatch(WatchID watchid) 106 | { 107 | mWatchesLock.lock(); 108 | 109 | WatchVector::iterator iter = mWatches.begin(); 110 | 111 | WatcherStructWin32* watch = NULL; 112 | 113 | for(; iter != mWatches.end(); ++iter) 114 | { 115 | // Find the watch ID 116 | if ( (*iter)->Watch->ID == watchid ) 117 | { 118 | watch = (*iter); 119 | 120 | mWatches.erase( iter ); 121 | 122 | // Remove handle from the handle vector 123 | HandleVector::iterator it = mHandles.begin(); 124 | 125 | for ( ; it != mHandles.end(); it++ ) 126 | { 127 | if ( watch->Watch->DirHandle == (*it) ) 128 | { 129 | mHandles.erase( it ); 130 | break; 131 | } 132 | } 133 | 134 | DestroyWatch(watch); 135 | 136 | break; 137 | } 138 | } 139 | 140 | mWatchesLock.unlock(); 141 | } 142 | 143 | void FileWatcherWin32::watch() 144 | { 145 | if ( NULL == mThread ) 146 | { 147 | mThread = new Thread( &FileWatcherWin32::run, this ); 148 | mThread->launch(); 149 | } 150 | } 151 | 152 | void FileWatcherWin32::run() 153 | { 154 | do 155 | { 156 | DWORD wait_result = WaitForMultipleObjectsEx( mHandles.size(), &mHandles[0], FALSE, 1000, FALSE ); 157 | 158 | switch ( wait_result ) 159 | { 160 | case WAIT_ABANDONED_0: 161 | case WAIT_ABANDONED_0 + 1: 162 | //"Wait abandoned." 163 | break; 164 | case WAIT_TIMEOUT: 165 | break; 166 | case WAIT_FAILED: 167 | //"Wait failed." 168 | break; 169 | default: 170 | { 171 | mWatchesLock.lock(); 172 | 173 | // Don't trust the result - multiple objects may be signalled during a single call. 174 | if ( wait_result >= WAIT_OBJECT_0 && wait_result < WAIT_OBJECT_0 + mWatches.size() ) 175 | { 176 | WatcherStructWin32 * watch = mWatches[ wait_result ]; 177 | 178 | // First ensure that the handle is the same, this means that the watch was not removed. 179 | if ( mHandles[ wait_result ] == watch->Watch->DirHandle && HasOverlappedIoCompleted( &watch->Overlapped ) ) 180 | { 181 | DWORD bytes; 182 | 183 | if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) ) 184 | { 185 | WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped ); 186 | } 187 | else 188 | { 189 | //"GetOverlappedResult failed." 190 | } 191 | 192 | break; 193 | } 194 | } 195 | else 196 | { 197 | //"Unknown return value from WaitForMultipleObjectsEx." 198 | } 199 | 200 | mWatchesLock.unlock(); 201 | } 202 | } 203 | } while ( mInitOK ); 204 | } 205 | 206 | void FileWatcherWin32::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename) 207 | { 208 | Action fwAction; 209 | 210 | switch(action) 211 | { 212 | case FILE_ACTION_RENAMED_OLD_NAME: 213 | watch->OldFileName = filename; 214 | break; 215 | case FILE_ACTION_ADDED: 216 | fwAction = Actions::Add; 217 | break; 218 | case FILE_ACTION_RENAMED_NEW_NAME: 219 | { 220 | fwAction = Actions::Moved; 221 | 222 | std::string fpath( watch->Directory + filename ); 223 | 224 | // Update the directory path 225 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) 226 | { 227 | // Update the new directory path 228 | std::string opath( watch->Directory + watch->OldFileName ); 229 | FileSystem::dirAddSlashAtEnd( opath ); 230 | FileSystem::dirAddSlashAtEnd( fpath ); 231 | 232 | for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 233 | { 234 | if ( (*it)->Watch->Directory == opath ) 235 | { 236 | (*it)->Watch->Directory = fpath; 237 | 238 | break; 239 | } 240 | } 241 | } 242 | 243 | watch->Listener->handleFileAction(watch->ID, static_cast( watch )->DirName, filename, fwAction, watch->OldFileName); 244 | return; 245 | } 246 | case FILE_ACTION_REMOVED: 247 | fwAction = Actions::Delete; 248 | break; 249 | case FILE_ACTION_MODIFIED: 250 | fwAction = Actions::Modified; 251 | break; 252 | }; 253 | 254 | watch->Listener->handleFileAction(watch->ID, static_cast( watch )->DirName, filename, fwAction); 255 | } 256 | 257 | std::list FileWatcherWin32::directories() 258 | { 259 | std::list dirs; 260 | 261 | mWatchesLock.lock(); 262 | 263 | for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 264 | { 265 | dirs.push_back( std::string( (*it)->Watch->DirName ) ); 266 | } 267 | 268 | mWatchesLock.unlock(); 269 | 270 | return dirs; 271 | } 272 | 273 | bool FileWatcherWin32::pathInWatches( const std::string& path ) 274 | { 275 | for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 276 | { 277 | if ( (*it)->Watch->DirName == path ) 278 | { 279 | return true; 280 | } 281 | } 282 | 283 | return false; 284 | } 285 | 286 | } 287 | 288 | #endif 289 | -------------------------------------------------------------------------------- /src/efsw/FileWatcherWin32.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERWIN32_HPP 2 | #define EFSW_FILEWATCHERWIN32_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace efsw 13 | { 14 | 15 | /// Implementation for Win32 based on ReadDirectoryChangesW. 16 | /// @class FileWatcherWin32 17 | class FileWatcherWin32 : public FileWatcherImpl 18 | { 19 | public: 20 | /// type for a map from WatchID to WatcherWin32 pointer 21 | typedef std::vector WatchVector; 22 | typedef std::vector HandleVector; 23 | 24 | FileWatcherWin32( FileWatcher * parent ); 25 | 26 | virtual ~FileWatcherWin32(); 27 | 28 | /// Add a directory watch 29 | /// On error returns WatchID with Error type. 30 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 31 | 32 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 33 | void removeWatch(const std::string& directory); 34 | 35 | /// Remove a directory watch. This is a map lookup O(logn). 36 | void removeWatch(WatchID watchid); 37 | 38 | /// Updates the watcher. Must be called often. 39 | void watch(); 40 | 41 | /// Handles the action 42 | void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 43 | 44 | /// @return Returns a list of the directories that are being watched 45 | std::list directories(); 46 | protected: 47 | /// Vector of WatcherWin32 pointers 48 | WatchVector mWatches; 49 | 50 | /// Keeps an updated handles vector 51 | HandleVector mHandles; 52 | 53 | /// The last watchid 54 | WatchID mLastWatchID; 55 | 56 | Thread * mThread; 57 | 58 | Mutex mWatchesLock; 59 | 60 | bool pathInWatches( const std::string& path ); 61 | private: 62 | void run(); 63 | }; 64 | 65 | } 66 | 67 | #endif 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/efsw/Log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace efsw { namespace Errors { 4 | 5 | static std::string LastError; 6 | 7 | std::string Log::getLastErrorLog() 8 | { 9 | return LastError; 10 | } 11 | 12 | Error Log::createLastError( Error err, std::string log ) 13 | { 14 | switch ( err ) 15 | { 16 | case FileNotFound: LastError = "File not found ( " + log + " )"; break; 17 | case FileRepeated: LastError = "File reapeated in watches ( " + log + " )"; break; 18 | case FileOutOfScope: LastError = "Symlink file out of scope ( " + log + " )"; break; 19 | case Unspecified: 20 | default: LastError = log; 21 | } 22 | 23 | return err; 24 | } 25 | 26 | }} 27 | -------------------------------------------------------------------------------- /src/efsw/Mutex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace efsw { 5 | 6 | Mutex::Mutex() : 7 | mMutexImpl( new Platform::MutexImpl() ) 8 | { 9 | } 10 | 11 | Mutex::~Mutex() 12 | { 13 | efSAFE_DELETE( mMutexImpl ); 14 | } 15 | 16 | void Mutex::lock() 17 | { 18 | mMutexImpl->lock(); 19 | } 20 | 21 | void Mutex::unlock() 22 | { 23 | mMutexImpl->unlock(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/efsw/Mutex.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_MUTEX_HPP 2 | #define EFSW_MUTEX_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | namespace Platform { class MutexImpl; } 9 | 10 | /** Simple mutex class */ 11 | class Mutex { 12 | public: 13 | Mutex(); 14 | 15 | ~Mutex(); 16 | 17 | /** Lock the mutex */ 18 | void lock(); 19 | 20 | /** Unlock the mutex */ 21 | void unlock(); 22 | private: 23 | Platform::MutexImpl * mMutexImpl; 24 | }; 25 | 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/efsw/String.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace efsw { 6 | 7 | const std::size_t String::InvalidPos = StringType::npos; 8 | 9 | std::vector < std::string > String::split ( const std::string& str, const char& splitchar, const bool& pushEmptyString ) 10 | { 11 | std::vector < std::string > tmp; 12 | std::string tmpstr; 13 | 14 | for ( size_t i = 0; i < str.size(); i++ ) 15 | { 16 | if ( str[i] == splitchar ) 17 | { 18 | if ( pushEmptyString || tmpstr.size() ) 19 | { 20 | tmp.push_back(tmpstr); 21 | tmpstr = ""; 22 | } 23 | } 24 | else 25 | { 26 | tmpstr += str[i]; 27 | } 28 | } 29 | 30 | if ( tmpstr.size() ) 31 | { 32 | tmp.push_back( tmpstr ); 33 | } 34 | 35 | return tmp; 36 | } 37 | 38 | std::vector < String > String::split ( const String& str, const Uint32& splitchar, const bool& pushEmptyString ) 39 | { 40 | std::vector < String > tmp; 41 | String tmpstr; 42 | 43 | for ( size_t i = 0; i < str.size(); i++ ) 44 | { 45 | if ( str[i] == splitchar ) 46 | { 47 | if ( pushEmptyString || tmpstr.size() ) 48 | { 49 | tmp.push_back(tmpstr); 50 | tmpstr = ""; 51 | } 52 | } 53 | else 54 | { 55 | tmpstr += str[i]; 56 | } 57 | } 58 | 59 | if ( tmpstr.size() ) 60 | { 61 | tmp.push_back( tmpstr ); 62 | } 63 | 64 | return tmp; 65 | } 66 | 67 | int String::strStartsWith( const std::string& start, const std::string& str ) 68 | { 69 | int pos = -1; 70 | size_t size = start.size(); 71 | 72 | if ( str.size() >= size ) 73 | { 74 | for ( std::size_t i = 0; i < size; i++ ) 75 | { 76 | if ( start[i] == str[i] ) 77 | { 78 | pos = (int)i; 79 | } 80 | else 81 | { 82 | pos = -1; 83 | break; 84 | } 85 | } 86 | } 87 | 88 | return pos; 89 | } 90 | 91 | int String::strStartsWith( const String& start, const String& str ) 92 | { 93 | int pos = -1; 94 | size_t size = start.size(); 95 | 96 | if ( str.size() >= size ) 97 | { 98 | for ( std::size_t i = 0; i < size; i++ ) 99 | { 100 | if ( start[i] == str[i] ) 101 | { 102 | pos = (int)i; 103 | } 104 | else 105 | { 106 | pos = -1; 107 | break; 108 | } 109 | } 110 | } 111 | 112 | return pos; 113 | } 114 | 115 | String::String() 116 | { 117 | } 118 | 119 | String::String(char ansiChar, const std::locale& locale) 120 | { 121 | mString += Utf32::DecodeAnsi(ansiChar, locale); 122 | } 123 | 124 | #ifndef EFSW_NO_WIDECHAR 125 | String::String(wchar_t wideChar) 126 | { 127 | mString += Utf32::DecodeWide(wideChar); 128 | } 129 | #endif 130 | 131 | String::String(StringBaseType utf32Char) 132 | { 133 | mString += utf32Char; 134 | } 135 | 136 | String::String( const char* uf8String ) { 137 | if (uf8String) 138 | { 139 | std::size_t length = strlen(uf8String); 140 | 141 | if (length > 0) 142 | { 143 | mString.reserve(length + 1); 144 | 145 | Utf8::ToUtf32(uf8String, uf8String + length, std::back_inserter(mString)); 146 | } 147 | } 148 | } 149 | 150 | String::String( const std::string& utf8String ) { 151 | mString.reserve( utf8String.length() + 1 ); 152 | 153 | Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( mString ) ); 154 | } 155 | 156 | String::String(const char* ansiString, const std::locale& locale) 157 | { 158 | if (ansiString) 159 | { 160 | std::size_t length = strlen(ansiString); 161 | if (length > 0) 162 | { 163 | mString.reserve(length + 1); 164 | Utf32::FromAnsi(ansiString, ansiString + length, std::back_inserter(mString), locale); 165 | } 166 | } 167 | } 168 | 169 | String::String(const std::string& ansiString, const std::locale& locale) 170 | { 171 | mString.reserve(ansiString.length() + 1); 172 | Utf32::FromAnsi(ansiString.begin(), ansiString.end(), std::back_inserter(mString), locale); 173 | } 174 | 175 | #ifndef EFSW_NO_WIDECHAR 176 | String::String(const wchar_t* wideString) 177 | { 178 | if (wideString) 179 | { 180 | std::size_t length = std::wcslen(wideString); 181 | if (length > 0) 182 | { 183 | mString.reserve(length + 1); 184 | Utf32::FromWide(wideString, wideString + length, std::back_inserter(mString)); 185 | } 186 | } 187 | } 188 | 189 | String::String(const std::wstring& wideString) 190 | { 191 | mString.reserve(wideString.length() + 1); 192 | Utf32::FromWide(wideString.begin(), wideString.end(), std::back_inserter(mString)); 193 | } 194 | #endif 195 | 196 | String::String(const StringBaseType* utf32String) 197 | { 198 | if (utf32String) 199 | mString = utf32String; 200 | } 201 | 202 | String::String(const StringType& utf32String) : 203 | mString(utf32String) 204 | { 205 | } 206 | 207 | String::String(const String& str) : 208 | mString(str.mString) 209 | { 210 | } 211 | 212 | String String::fromUtf8( const std::string& utf8String ) 213 | { 214 | String::StringType utf32; 215 | 216 | utf32.reserve( utf8String.length() + 1 ); 217 | 218 | Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( utf32 ) ); 219 | 220 | return String( utf32 ); 221 | } 222 | 223 | String::operator std::string() const 224 | { 225 | return toAnsiString(); 226 | } 227 | 228 | std::string String::toAnsiString(const std::locale& locale) const 229 | { 230 | // Prepare the output string 231 | std::string output; 232 | output.reserve(mString.length() + 1); 233 | 234 | // Convert 235 | Utf32::ToAnsi(mString.begin(), mString.end(), std::back_inserter(output), 0, locale); 236 | 237 | return output; 238 | } 239 | 240 | #ifndef EFSW_NO_WIDECHAR 241 | String String::toWideString() const 242 | { 243 | // Prepare the output string 244 | std::wstring output; 245 | output.reserve(mString.length() + 1); 246 | 247 | // Convert 248 | Utf32::ToWide(mString.begin(), mString.end(), std::back_inserter(output), 0); 249 | 250 | return output; 251 | } 252 | #endif 253 | 254 | std::string String::toUtf8() const { 255 | // Prepare the output string 256 | std::string output; 257 | output.reserve(mString.length() + 1); 258 | 259 | // Convert 260 | Utf32::toUtf8(mString.begin(), mString.end(), std::back_inserter(output) ); 261 | 262 | return output; 263 | } 264 | 265 | String& String::operator =(const String& right) 266 | { 267 | mString = right.mString; 268 | return *this; 269 | } 270 | 271 | String& String::operator =( const StringBaseType& right ) 272 | { 273 | mString = right; 274 | return *this; 275 | } 276 | 277 | String& String::operator +=(const String& right) 278 | { 279 | mString += right.mString; 280 | return *this; 281 | } 282 | 283 | String& String::operator +=( const StringBaseType& right ) 284 | { 285 | mString += right; 286 | return *this; 287 | } 288 | 289 | 290 | String::StringBaseType String::operator [](std::size_t index) const 291 | { 292 | return mString[index]; 293 | } 294 | 295 | String::StringBaseType& String::operator [](std::size_t index) 296 | { 297 | return mString[index]; 298 | } 299 | 300 | String::StringBaseType String::at( std::size_t index ) const 301 | { 302 | return mString.at( index ); 303 | } 304 | 305 | void String::push_back( StringBaseType c ) 306 | { 307 | mString.push_back( c ); 308 | } 309 | 310 | void String::swap ( String& str ) 311 | { 312 | mString.swap( str.mString ); 313 | } 314 | 315 | void String::clear() 316 | { 317 | mString.clear(); 318 | } 319 | 320 | std::size_t String::size() const 321 | { 322 | return mString.size(); 323 | } 324 | 325 | std::size_t String::length() const 326 | { 327 | return mString.length(); 328 | } 329 | 330 | bool String::empty() const 331 | { 332 | return mString.empty(); 333 | } 334 | 335 | void String::erase(std::size_t position, std::size_t count) 336 | { 337 | mString.erase(position, count); 338 | } 339 | 340 | String& String::insert(std::size_t position, const String& str) 341 | { 342 | mString.insert(position, str.mString); 343 | return *this; 344 | } 345 | 346 | String& String::insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n ) 347 | { 348 | mString.insert( pos1, str.mString, pos2, n ); 349 | return *this; 350 | } 351 | 352 | String& String::insert ( size_t pos1, const char* s, size_t n ) 353 | { 354 | String tmp( s ); 355 | 356 | mString.insert( pos1, tmp.data(), n ); 357 | 358 | return *this; 359 | } 360 | 361 | String& String::insert ( size_t pos1, size_t n, char c ) 362 | { 363 | mString.insert( pos1, n, c ); 364 | return *this; 365 | } 366 | 367 | String& String::insert ( size_t pos1, const char* s ) 368 | { 369 | String tmp( s ); 370 | 371 | mString.insert( pos1, tmp.data() ); 372 | 373 | return *this; 374 | } 375 | 376 | String::Iterator String::insert ( Iterator p, char c ) 377 | { 378 | return mString.insert( p, c ); 379 | } 380 | 381 | void String::insert ( Iterator p, size_t n, char c ) 382 | { 383 | mString.insert( p, n, c ); 384 | } 385 | 386 | const String::StringBaseType* String::c_str() const 387 | { 388 | return mString.c_str(); 389 | } 390 | 391 | const String::StringBaseType* String::data() const 392 | { 393 | return mString.data(); 394 | } 395 | 396 | String::Iterator String::begin() 397 | { 398 | return mString.begin(); 399 | } 400 | 401 | String::ConstIterator String::begin() const 402 | { 403 | return mString.begin(); 404 | } 405 | 406 | String::Iterator String::end() 407 | { 408 | return mString.end(); 409 | } 410 | 411 | String::ConstIterator String::end() const 412 | { 413 | return mString.end(); 414 | } 415 | 416 | String::ReverseIterator String::rbegin() 417 | { 418 | return mString.rbegin(); 419 | } 420 | 421 | String::ConstReverseIterator String::rbegin() const 422 | { 423 | return mString.rbegin(); 424 | } 425 | 426 | String::ReverseIterator String::rend() 427 | { 428 | return mString.rend(); 429 | } 430 | 431 | String::ConstReverseIterator String::rend() const 432 | { 433 | return mString.rend(); 434 | } 435 | 436 | void String::resize( std::size_t n, StringBaseType c ) 437 | { 438 | mString.resize( n, c ); 439 | } 440 | 441 | void String::resize( std::size_t n ) 442 | { 443 | mString.resize( n ); 444 | } 445 | 446 | std::size_t String::max_size() const 447 | { 448 | return mString.max_size(); 449 | } 450 | 451 | void String::reserve( size_t res_arg ) 452 | { 453 | mString.reserve( res_arg ); 454 | } 455 | 456 | std::size_t String::capacity() const 457 | { 458 | return mString.capacity(); 459 | } 460 | 461 | String& String::assign ( const String& str ) 462 | { 463 | mString.assign( str.mString ); 464 | return *this; 465 | } 466 | 467 | String& String::assign ( const String& str, size_t pos, size_t n ) 468 | { 469 | mString.assign( str.mString, pos, n ); 470 | return *this; 471 | } 472 | 473 | String& String::assign ( const char* s, size_t n ) 474 | { 475 | String tmp( s ); 476 | 477 | mString.assign( tmp.mString ); 478 | 479 | return *this; 480 | } 481 | 482 | String& String::assign ( const char* s ) 483 | { 484 | String tmp( s ); 485 | 486 | mString.assign( tmp.mString ); 487 | 488 | return *this; 489 | } 490 | 491 | String& String::assign ( size_t n, char c ) 492 | { 493 | mString.assign( n, c ); 494 | 495 | return *this; 496 | } 497 | 498 | String& String::append ( const String& str ) 499 | { 500 | mString.append( str.mString ); 501 | 502 | return *this; 503 | } 504 | 505 | String& String::append ( const String& str, size_t pos, size_t n ) 506 | { 507 | mString.append( str.mString, pos, n ); 508 | 509 | return *this; 510 | } 511 | 512 | String& String::append ( const char* s, size_t n ) 513 | { 514 | String tmp( s ); 515 | 516 | mString.append( tmp.mString ); 517 | 518 | return *this; 519 | } 520 | 521 | String& String::append ( const char* s ) 522 | { 523 | String tmp( s ); 524 | 525 | mString.append( tmp.mString ); 526 | 527 | return *this; 528 | } 529 | 530 | String& String::append ( size_t n, char c ) 531 | { 532 | mString.append( n, c ); 533 | 534 | return *this; 535 | } 536 | 537 | String& String::append ( std::size_t n, StringBaseType c ) 538 | { 539 | mString.append( n, c ); 540 | 541 | return *this; 542 | } 543 | 544 | String& String::replace ( size_t pos1, size_t n1, const String& str ) 545 | { 546 | mString.replace( pos1, n1, str.mString ); 547 | 548 | return *this; 549 | } 550 | 551 | String& String::replace ( Iterator i1, Iterator i2, const String& str ) 552 | { 553 | mString.replace( i1, i2, str.mString ); 554 | 555 | return *this; 556 | } 557 | 558 | String& String::replace ( size_t pos1, size_t n1, const String& str, size_t pos2, size_t n2 ) 559 | { 560 | mString.replace( pos1, n1, str.mString, pos2, n2 ); 561 | 562 | return *this; 563 | } 564 | 565 | String& String::replace ( size_t pos1, size_t n1, const char* s, size_t n2 ) 566 | { 567 | String tmp( s ); 568 | 569 | mString.replace( pos1, n1, tmp.data(), n2 ); 570 | 571 | return *this; 572 | } 573 | 574 | String& String::replace ( Iterator i1, Iterator i2, const char* s, size_t n2 ) 575 | { 576 | String tmp( s ); 577 | 578 | mString.replace( i1, i2, tmp.data(), n2 ); 579 | 580 | return *this; 581 | } 582 | 583 | String& String::replace ( size_t pos1, size_t n1, const char* s ) 584 | { 585 | String tmp( s ); 586 | 587 | mString.replace( pos1, n1, tmp.mString ); 588 | 589 | return *this; 590 | } 591 | 592 | String& String::replace ( Iterator i1, Iterator i2, const char* s ) 593 | { 594 | String tmp( s ); 595 | 596 | mString.replace( i1, i2, tmp.mString ); 597 | 598 | return *this; 599 | } 600 | 601 | String& String::replace ( size_t pos1, size_t n1, size_t n2, char c ) 602 | { 603 | mString.replace( pos1, n1, n2, (StringBaseType)c ); 604 | 605 | return *this; 606 | } 607 | 608 | String& String::replace ( Iterator i1, Iterator i2, size_t n2, char c ) 609 | { 610 | mString.replace( i1, i2, n2, (StringBaseType)c ); 611 | 612 | return *this; 613 | } 614 | 615 | std::size_t String::find( const String& str, std::size_t start ) const 616 | { 617 | return mString.find( str.mString, start ); 618 | } 619 | 620 | std::size_t String::find ( const char* s, std::size_t pos, std::size_t n ) const 621 | { 622 | return find( String( s ), pos ); 623 | } 624 | 625 | std::size_t String::find ( const char* s, std::size_t pos ) const 626 | { 627 | return find( String( s ), pos ); 628 | } 629 | 630 | size_t String::find ( char c, std::size_t pos ) const 631 | { 632 | return mString.find( (StringBaseType)c, pos ); 633 | } 634 | 635 | std::size_t String::rfind ( const String& str, std::size_t pos ) const 636 | { 637 | return mString.rfind( str.mString, pos ); 638 | } 639 | 640 | std::size_t String::rfind ( const char* s, std::size_t pos, std::size_t n ) const 641 | { 642 | return rfind( String( s ), pos ); 643 | } 644 | 645 | std::size_t String::rfind ( const char* s, std::size_t pos ) const 646 | { 647 | return rfind( String( s ), pos ); 648 | } 649 | 650 | std::size_t String::rfind ( char c, std::size_t pos ) const 651 | { 652 | return mString.rfind( c, pos ); 653 | } 654 | 655 | std::size_t String::copy ( StringBaseType* s, std::size_t n, std::size_t pos ) const 656 | { 657 | return mString.copy( s, n, pos ); 658 | } 659 | 660 | String String::substr ( std::size_t pos, std::size_t n ) const 661 | { 662 | return String( mString.substr( pos, n ) ); 663 | } 664 | 665 | int String::compare ( const String& str ) const 666 | { 667 | return mString.compare( str.mString ); 668 | } 669 | 670 | int String::compare ( const char* s ) const 671 | { 672 | return compare( String( s ) ); 673 | } 674 | 675 | int String::compare ( std::size_t pos1, std::size_t n1, const String& str ) const 676 | { 677 | return mString.compare( pos1, n1, str.mString ); 678 | } 679 | 680 | int String::compare ( std::size_t pos1, std::size_t n1, const char* s) const 681 | { 682 | return compare( pos1, n1, String( s ) ); 683 | } 684 | 685 | int String::compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const 686 | { 687 | return mString.compare( pos1, n1, str.mString, pos2, n2 ); 688 | } 689 | 690 | int String::compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const 691 | { 692 | return compare( pos1, n1, String( s ), 0, n2 ); 693 | } 694 | 695 | std::size_t String::find_first_of ( const String& str, std::size_t pos ) const 696 | { 697 | return mString.find_first_of( str.mString, pos ); 698 | } 699 | 700 | std::size_t String::find_first_of ( const char* s, std::size_t pos, std::size_t n ) const 701 | { 702 | return find_first_of( String( s ), pos ); 703 | } 704 | 705 | std::size_t String::find_first_of ( const char* s, std::size_t pos ) const 706 | { 707 | return find_first_of( String( s ), pos ); 708 | } 709 | 710 | std::size_t String::find_first_of ( StringBaseType c, std::size_t pos ) const 711 | { 712 | return mString.find_first_of( c, pos ); 713 | } 714 | 715 | std::size_t String::find_last_of ( const String& str, std::size_t pos ) const 716 | { 717 | return mString.find_last_of( str.mString, pos ); 718 | } 719 | 720 | std::size_t String::find_last_of ( const char* s, std::size_t pos, std::size_t n ) const 721 | { 722 | return find_last_of( String( s ), pos ); 723 | } 724 | 725 | std::size_t String::find_last_of ( const char* s, std::size_t pos ) const 726 | { 727 | return find_last_of( String( s ), pos ); 728 | } 729 | 730 | std::size_t String::find_last_of ( StringBaseType c, std::size_t pos) const 731 | { 732 | return mString.find_last_of( c, pos ); 733 | } 734 | 735 | std::size_t String::find_first_not_of ( const String& str, std::size_t pos ) const 736 | { 737 | return mString.find_first_not_of( str.mString, pos ); 738 | } 739 | 740 | std::size_t String::find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const 741 | { 742 | return find_first_not_of( String( s ), pos ); 743 | } 744 | 745 | std::size_t String::find_first_not_of ( const char* s, std::size_t pos ) const 746 | { 747 | return find_first_not_of( String( s ), pos ); 748 | } 749 | 750 | std::size_t String::find_first_not_of ( StringBaseType c, std::size_t pos ) const 751 | { 752 | return mString.find_first_not_of( c, pos ); 753 | } 754 | 755 | std::size_t String::find_last_not_of ( const String& str, std::size_t pos ) const 756 | { 757 | return mString.find_last_not_of( str.mString, pos ); 758 | } 759 | 760 | std::size_t String::find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const 761 | { 762 | return find_last_not_of( String( s ), pos ); 763 | } 764 | 765 | std::size_t String::find_last_not_of ( const char* s, std::size_t pos ) const 766 | { 767 | return find_last_not_of( String( s ), pos ); 768 | } 769 | 770 | std::size_t String::find_last_not_of ( StringBaseType c, std::size_t pos ) const 771 | { 772 | return mString.find_last_not_of( c, pos ); 773 | } 774 | 775 | bool operator ==(const String& left, const String& right) 776 | { 777 | return left.mString == right.mString; 778 | } 779 | 780 | bool operator !=(const String& left, const String& right) 781 | { 782 | return !(left == right); 783 | } 784 | 785 | bool operator <(const String& left, const String& right) 786 | { 787 | return left.mString < right.mString; 788 | } 789 | 790 | bool operator >(const String& left, const String& right) 791 | { 792 | return right < left; 793 | } 794 | 795 | bool operator <=(const String& left, const String& right) 796 | { 797 | return !(right < left); 798 | } 799 | 800 | bool operator >=(const String& left, const String& right) 801 | { 802 | return !(left < right); 803 | } 804 | 805 | String operator +(const String& left, const String& right) 806 | { 807 | String string = left; 808 | string += right; 809 | 810 | return string; 811 | } 812 | 813 | } 814 | -------------------------------------------------------------------------------- /src/efsw/System.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace efsw { 5 | 6 | void System::sleep( const unsigned long& ms ) 7 | { 8 | Platform::System::sleep( ms ); 9 | } 10 | 11 | std::string System::getProcessPath() 12 | { 13 | return Platform::System::getProcessPath(); 14 | } 15 | 16 | void System::maxFD() 17 | { 18 | Platform::System::maxFD(); 19 | } 20 | 21 | Uint64 System::getMaxFD() 22 | { 23 | return Platform::System::getMaxFD(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/efsw/System.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_SYSTEM_HPP 2 | #define EFSW_SYSTEM_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | class System 9 | { 10 | public: 11 | /// Sleep for x milliseconds 12 | static void sleep( const unsigned long& ms ); 13 | 14 | /// @return The process binary path 15 | static std::string getProcessPath(); 16 | 17 | /// Maximize the number of file descriptors allowed per process in the current OS 18 | static void maxFD(); 19 | 20 | /// @return The number of supported file descriptors for the process 21 | static Uint64 getMaxFD(); 22 | }; 23 | 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/efsw/Thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace efsw { 5 | 6 | Thread::Thread() : 7 | mThreadImpl(NULL), 8 | mEntryPoint(NULL) 9 | { 10 | } 11 | 12 | Thread::~Thread() 13 | { 14 | wait(); 15 | 16 | efSAFE_DELETE( mEntryPoint ); 17 | } 18 | 19 | void Thread::launch() 20 | { 21 | wait(); 22 | 23 | mThreadImpl = new Platform::ThreadImpl( this ); 24 | } 25 | 26 | void Thread::wait() 27 | { 28 | if ( mThreadImpl ) 29 | { 30 | mThreadImpl->wait(); 31 | 32 | efSAFE_DELETE( mThreadImpl ); 33 | } 34 | } 35 | 36 | void Thread::terminate() 37 | { 38 | if ( mThreadImpl ) 39 | { 40 | mThreadImpl->terminate(); 41 | 42 | efSAFE_DELETE( mThreadImpl ); 43 | } 44 | } 45 | 46 | void Thread::run() 47 | { 48 | mEntryPoint->run(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/efsw/Thread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_THREAD_HPP 2 | #define EFSW_THREAD_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | namespace Platform { class ThreadImpl; } 9 | namespace Private { struct ThreadFunc; } 10 | 11 | /** @brief Thread manager class */ 12 | class Thread { 13 | public: 14 | typedef void (*FuncType)(void*); 15 | 16 | template 17 | Thread( F function ); 18 | 19 | template 20 | Thread( F function, A argument ); 21 | 22 | template 23 | Thread( void(C::*function)(), C* object ); 24 | 25 | virtual ~Thread(); 26 | 27 | /** Launch the thread */ 28 | virtual void launch(); 29 | 30 | /** Wait the thread until end */ 31 | void wait(); 32 | 33 | /** Terminate the thread */ 34 | void terminate(); 35 | protected: 36 | Thread(); 37 | private: 38 | friend class Platform::ThreadImpl; 39 | 40 | /** The virtual function to run in the thread */ 41 | virtual void run(); 42 | 43 | Platform::ThreadImpl * mThreadImpl; ///< OS-specific implementation of the thread 44 | Private::ThreadFunc * mEntryPoint; ///< Abstraction of the function to run 45 | }; 46 | 47 | //! NOTE: Taken from SFML2 threads 48 | namespace Private { 49 | 50 | // Base class for abstract thread functions 51 | struct ThreadFunc 52 | { 53 | virtual ~ThreadFunc() {} 54 | virtual void run() = 0; 55 | }; 56 | 57 | // Specialization using a functor (including free functions) with no argument 58 | template 59 | struct ThreadFunctor : ThreadFunc 60 | { 61 | ThreadFunctor(T functor) : m_functor(functor) {} 62 | virtual void run() {m_functor();} 63 | T m_functor; 64 | }; 65 | 66 | // Specialization using a functor (including free functions) with one argument 67 | template 68 | struct ThreadFunctorWithArg : ThreadFunc 69 | { 70 | ThreadFunctorWithArg(F function, A arg) : m_function(function), m_arg(arg) {} 71 | virtual void run() {m_function(m_arg);} 72 | F m_function; 73 | A m_arg; 74 | }; 75 | 76 | // Specialization using a member function 77 | template 78 | struct ThreadMemberFunc : ThreadFunc 79 | { 80 | ThreadMemberFunc(void(C::*function)(), C* object) : m_function(function), m_object(object) {} 81 | virtual void run() {(m_object->*m_function)();} 82 | void(C::*m_function)(); 83 | C* m_object; 84 | }; 85 | 86 | } 87 | 88 | template 89 | Thread::Thread(F functor) : 90 | mThreadImpl (NULL), 91 | mEntryPoint( new Private::ThreadFunctor(functor) ) 92 | { 93 | } 94 | 95 | template 96 | Thread::Thread(F function, A argument) : 97 | mThreadImpl(NULL), 98 | mEntryPoint( new Private::ThreadFunctorWithArg(function, argument) ) 99 | { 100 | } 101 | 102 | template 103 | Thread::Thread(void(C::*function)(), C* object) : 104 | mThreadImpl(NULL), 105 | mEntryPoint( new Private::ThreadMemberFunc(function, object) ) 106 | { 107 | } 108 | 109 | } 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /src/efsw/Watcher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace efsw { 4 | 5 | Watcher::Watcher() : 6 | ID(0), 7 | Directory(""), 8 | Listener(NULL), 9 | Recursive(false) 10 | { 11 | } 12 | 13 | Watcher::Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ) : 14 | ID( id ), 15 | Directory( directory ), 16 | Listener( listener ), 17 | Recursive( recursive ) 18 | { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/efsw/Watcher.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERIMPL_HPP 2 | #define EFSW_WATCHERIMPL_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace efsw { 8 | 9 | /** @brief Base Watcher class */ 10 | class Watcher 11 | { 12 | public: 13 | Watcher(); 14 | 15 | Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ); 16 | 17 | virtual ~Watcher() {} 18 | 19 | virtual void watch() {} 20 | 21 | WatchID ID; 22 | std::string Directory; 23 | FileWatchListener * Listener; 24 | bool Recursive; 25 | std::string OldFileName; 26 | }; 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/efsw/WatcherFSEvents.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 7 | 8 | namespace efsw { 9 | 10 | WatcherFSEvents::WatcherFSEvents() : 11 | Watcher(), 12 | FWatcher( NULL ), 13 | FSStream( NULL ), 14 | WatcherGen( NULL ), 15 | initializedAsync( false ) 16 | { 17 | } 18 | 19 | WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent ) : 20 | Watcher( id, directory, listener, recursive ), 21 | FWatcher( NULL ), 22 | FSStream( NULL ), 23 | WatcherGen( NULL ), 24 | initializedAsync( false ) 25 | { 26 | } 27 | 28 | WatcherFSEvents::~WatcherFSEvents() 29 | { 30 | if ( initializedAsync ) 31 | { 32 | FSEventStreamStop( FSStream ); 33 | FSEventStreamInvalidate( FSStream ); 34 | } 35 | 36 | if ( NULL != FSStream ) 37 | { 38 | FSEventStreamRelease( FSStream ); 39 | } 40 | 41 | efSAFE_DELETE( WatcherGen ); 42 | } 43 | 44 | void WatcherFSEvents::init() 45 | { 46 | CFStringRef CFDirectory = CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 ); 47 | CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void **)&CFDirectory, 1, NULL ); 48 | 49 | Uint32 streamFlags = kFSEventStreamCreateFlagNone; 50 | 51 | if ( FileWatcherFSEvents::isGranular() ) 52 | { 53 | streamFlags = efswFSEventStreamCreateFlagFileEvents; 54 | } 55 | else 56 | { 57 | WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher, Recursive ); 58 | } 59 | 60 | FSEventStreamContext ctx; 61 | /* Initialize context */ 62 | ctx.version = 0; 63 | ctx.info = this; 64 | ctx.retain = NULL; 65 | ctx.release = NULL; 66 | ctx.copyDescription = NULL; 67 | 68 | FSStream = FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags ); 69 | 70 | FWatcher->mNeedInit.push_back( this ); 71 | 72 | CFRelease( CFDirectoryArray ); 73 | CFRelease( CFDirectory ); 74 | } 75 | 76 | void WatcherFSEvents::initAsync() 77 | { 78 | FSEventStreamScheduleWithRunLoop( FSStream, FWatcher->mRunLoopRef, kCFRunLoopDefaultMode ); 79 | FSEventStreamStart( FSStream ); 80 | initializedAsync = true; 81 | } 82 | 83 | void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, std::string& filePath ) 84 | { 85 | if ( flags & efswFSEventStreamEventFlagItemCreated ) 86 | { 87 | Listener->handleFileAction( ID, dirPath, filePath, Actions::Add ); 88 | } 89 | 90 | if ( flags & efswFSEventsModified ) 91 | { 92 | Listener->handleFileAction( ID, dirPath, filePath, Actions::Modified ); 93 | } 94 | 95 | if ( flags & efswFSEventStreamEventFlagItemRemoved ) 96 | { 97 | Listener->handleFileAction( ID, dirPath, filePath, Actions::Delete ); 98 | 99 | // Since i don't know the order, at least i try to keep the data consistent with the real state 100 | if ( FileInfo::exists( path ) ) 101 | { 102 | Listener->handleFileAction( ID, dirPath, filePath, Actions::Add ); 103 | } 104 | } 105 | } 106 | 107 | void WatcherFSEvents::handleAction( const std::string& path, const Uint32& flags ) 108 | { 109 | static std::string lastRenamed = ""; 110 | static bool lastWasAdd = false; 111 | 112 | if ( flags & ( kFSEventStreamEventFlagUserDropped | 113 | kFSEventStreamEventFlagKernelDropped | 114 | kFSEventStreamEventFlagEventIdsWrapped | 115 | kFSEventStreamEventFlagHistoryDone | 116 | kFSEventStreamEventFlagMount | 117 | kFSEventStreamEventFlagUnmount | 118 | kFSEventStreamEventFlagRootChanged) ) 119 | { 120 | return; 121 | } 122 | 123 | if ( !Recursive ) 124 | { 125 | /** In case that is not recursive the watcher, ignore the events from subfolders */ 126 | if ( path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 ) 127 | { 128 | return; 129 | } 130 | } 131 | 132 | std::string dirPath( FileSystem::pathRemoveFileName( path ) ); 133 | std::string filePath( FileSystem::fileNameFromPath( path ) ); 134 | 135 | if ( FileWatcherFSEvents::isGranular() ) 136 | { 137 | if ( flags & ( efswFSEventStreamEventFlagItemCreated | 138 | efswFSEventStreamEventFlagItemRemoved | 139 | efswFSEventStreamEventFlagItemRenamed ) 140 | ) 141 | { 142 | std::string dpath( FileSystem::pathRemoveFileName( path ) ); 143 | 144 | if ( dpath != Directory ) 145 | { 146 | DirsChanged.insert( dpath ); 147 | } 148 | } 149 | 150 | // 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 ) 151 | // 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. 152 | // I don't know what they were thinking by doing this... 153 | efDEBUG( "Event in: %s - flags: %ld\n", path.c_str(), flags ); 154 | 155 | if ( !( flags & efswFSEventStreamEventFlagItemRenamed ) ) 156 | { 157 | handleAddModDel( flags, path, dirPath, filePath ); 158 | } 159 | else 160 | { 161 | if ( lastRenamed.empty() ) 162 | { 163 | efDEBUG( "New lastRenamed: %s\n", filePath.c_str() ); 164 | 165 | lastRenamed = path; 166 | lastWasAdd = FileInfo::exists( path ); 167 | 168 | handleAddModDel( flags, path, dirPath, filePath ); 169 | } 170 | else 171 | { 172 | std::string oldDir( FileSystem::pathRemoveFileName( lastRenamed ) ); 173 | std::string newDir( FileSystem::pathRemoveFileName( path ) ); 174 | std::string oldFilepath( FileSystem::fileNameFromPath( lastRenamed ) ); 175 | 176 | if ( lastRenamed != path ) 177 | { 178 | if ( oldDir == newDir ) 179 | { 180 | if ( !lastWasAdd ) 181 | { 182 | Listener->handleFileAction( ID, dirPath, filePath, Actions::Moved, oldFilepath ); 183 | } 184 | else 185 | { 186 | Listener->handleFileAction( ID, dirPath, oldFilepath, Actions::Moved, filePath ); 187 | } 188 | } 189 | else 190 | { 191 | Listener->handleFileAction( ID, oldDir, oldFilepath, Actions::Delete ); 192 | Listener->handleFileAction( ID, dirPath, filePath, Actions::Add ); 193 | 194 | if ( flags & efswFSEventsModified ) 195 | { 196 | Listener->handleFileAction( ID, dirPath, filePath, Actions::Modified ); 197 | } 198 | } 199 | } 200 | else 201 | { 202 | handleAddModDel( flags, path, dirPath, filePath ); 203 | } 204 | 205 | lastRenamed.clear(); 206 | } 207 | } 208 | } 209 | else 210 | { 211 | efDEBUG( "Directory: %s changed\n", path.c_str() ); 212 | DirsChanged.insert( path ); 213 | } 214 | } 215 | 216 | void WatcherFSEvents::process() 217 | { 218 | 219 | std::set::iterator it = DirsChanged.begin(); 220 | 221 | for ( ; it != DirsChanged.end(); it++ ) 222 | { 223 | if ( !FileWatcherFSEvents::isGranular() ) 224 | { 225 | WatcherGen->watchDir( (*it) ); 226 | } 227 | else 228 | { 229 | Listener->handleFileAction( ID, FileSystem::pathRemoveFileName( (*it) ), FileSystem::fileNameFromPath( (*it) ), Actions::Modified ); 230 | } 231 | } 232 | 233 | DirsChanged.clear(); 234 | } 235 | 236 | } 237 | 238 | #endif 239 | -------------------------------------------------------------------------------- /src/efsw/WatcherFSEvents.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERINOTIFY_HPP 2 | #define EFSW_WATCHERINOTIFY_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace efsw { 14 | 15 | class FileWatcherFSEvents; 16 | 17 | class WatcherFSEvents : public Watcher 18 | { 19 | public: 20 | WatcherFSEvents(); 21 | 22 | WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent = NULL ); 23 | 24 | ~WatcherFSEvents(); 25 | 26 | void init(); 27 | 28 | void initAsync(); 29 | 30 | void handleAction( const std::string& path, const Uint32& flags ); 31 | 32 | void process(); 33 | 34 | FileWatcherFSEvents * FWatcher; 35 | 36 | FSEventStreamRef FSStream; 37 | protected: 38 | void handleAddModDel( const Uint32 &flags, const std::string &path, std::string &dirPath, std::string &filePath ); 39 | 40 | WatcherGeneric * WatcherGen; 41 | 42 | bool initializedAsync; 43 | 44 | std::set DirsChanged; 45 | }; 46 | 47 | } 48 | 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/efsw/WatcherGeneric.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace efsw 6 | { 7 | 8 | WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ) : 9 | Watcher( id, directory, fwl, recursive ), 10 | WatcherImpl( fw ), 11 | DirWatch( NULL ) 12 | { 13 | FileSystem::dirAddSlashAtEnd( Directory ); 14 | 15 | DirWatch = new DirWatcherGeneric( NULL, this, directory, recursive ); 16 | 17 | DirWatch->addChilds(); 18 | } 19 | 20 | WatcherGeneric::~WatcherGeneric() 21 | { 22 | efSAFE_DELETE( DirWatch ); 23 | } 24 | 25 | void WatcherGeneric::watch() 26 | { 27 | DirWatch->watch(); 28 | } 29 | 30 | void WatcherGeneric::watchDir( std::string dir ) 31 | { 32 | DirWatch->watchDir( dir ); 33 | } 34 | 35 | bool WatcherGeneric::pathInWatches( std::string path ) 36 | { 37 | return DirWatch->pathInWatches( path ); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/efsw/WatcherGeneric.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERGENERIC_HPP 2 | #define EFSW_WATCHERGENERIC_HPP 3 | 4 | #include 5 | 6 | namespace efsw 7 | { 8 | 9 | class DirWatcherGeneric; 10 | 11 | class WatcherGeneric : public Watcher 12 | { 13 | public: 14 | FileWatcherImpl * WatcherImpl; 15 | DirWatcherGeneric * DirWatch; 16 | 17 | WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ); 18 | 19 | ~WatcherGeneric(); 20 | 21 | void watch(); 22 | 23 | void watchDir( std::string dir ); 24 | 25 | bool pathInWatches( std::string path ); 26 | }; 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/efsw/WatcherInotify.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace efsw { 4 | 5 | WatcherInotify::WatcherInotify() : 6 | Watcher(), 7 | Parent( NULL ) 8 | { 9 | } 10 | 11 | WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent ) : 12 | Watcher( id, directory, listener, recursive ), 13 | Parent( parent ) 14 | { 15 | } 16 | 17 | bool WatcherInotify::inParentTree( WatcherInotify * parent ) 18 | { 19 | WatcherInotify * tNext = Parent; 20 | 21 | while ( NULL != tNext ) 22 | { 23 | if ( tNext == parent ) 24 | { 25 | return true; 26 | } 27 | 28 | tNext = tNext->Parent; 29 | } 30 | 31 | return false; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/efsw/WatcherInotify.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERINOTIFY_HPP 2 | #define EFSW_WATCHERINOTIFY_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | class WatcherInotify : public Watcher 9 | { 10 | public: 11 | WatcherInotify(); 12 | 13 | WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent = NULL ); 14 | 15 | WatcherInotify * Parent; 16 | 17 | bool inParentTree( WatcherInotify * parent ); 18 | }; 19 | 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/efsw/WatcherKqueue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define KEVENT_RESERVE_VALUE (10) 21 | 22 | #ifndef O_EVTONLY 23 | #define O_EVTONLY (O_RDONLY | O_NONBLOCK) 24 | #endif 25 | 26 | namespace efsw { 27 | 28 | int comparator(const void* ke1, const void* ke2) 29 | { 30 | const KEvent * kev1 = reinterpret_cast( ke1 ); 31 | const KEvent * kev2 = reinterpret_cast( ke2 ); 32 | 33 | if ( NULL != kev2->udata ) 34 | { 35 | FileInfo * fi1 = reinterpret_cast( kev1->udata ); 36 | FileInfo * fi2 = reinterpret_cast( kev2->udata ); 37 | 38 | return strcmp( fi1->Filepath.c_str(), fi2->Filepath.c_str() ); 39 | } 40 | 41 | return 1; 42 | } 43 | 44 | WatcherKqueue::WatcherKqueue(WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent ) : 45 | Watcher( watchid, dirname, listener, recursive ), 46 | mLastWatchID(0), 47 | mChangeListCount( 0 ), 48 | mKqueue( kqueue() ), 49 | mWatcher( watcher ), 50 | mParent( parent ), 51 | mInitOK( true ), 52 | mErrno(0) 53 | { 54 | if ( -1 == mKqueue ) 55 | { 56 | efDEBUG( "kqueue() returned invalid descriptor for directory %s. File descriptors count: %ld\n", Directory.c_str(), mWatcher->mFileDescriptorCount ); 57 | 58 | mInitOK = false; 59 | mErrno = errno; 60 | } 61 | else 62 | { 63 | mWatcher->addFD(); 64 | } 65 | } 66 | 67 | WatcherKqueue::~WatcherKqueue() 68 | { 69 | // Remove the childs watchers ( sub-folders watches ) 70 | removeAll(); 71 | 72 | for ( size_t i = 0; i < mChangeListCount; i++ ) 73 | { 74 | if ( NULL != mChangeList[i].udata ) 75 | { 76 | FileInfo * fi = reinterpret_cast( mChangeList[i].udata ); 77 | 78 | efSAFE_DELETE( fi ); 79 | } 80 | } 81 | 82 | close( mKqueue ); 83 | 84 | mWatcher->removeFD(); 85 | } 86 | 87 | void WatcherKqueue::addAll() 88 | { 89 | if ( -1 == mKqueue ) 90 | { 91 | return; 92 | } 93 | 94 | // scan directory and call addFile(name, false) on each file 95 | FileSystem::dirAddSlashAtEnd( Directory ); 96 | 97 | efDEBUG( "addAll(): Added folder: %s\n", Directory.c_str()); 98 | 99 | // add base dir 100 | int fd = open( Directory.c_str(), O_EVTONLY ); 101 | 102 | if ( -1 == fd ) 103 | { 104 | efDEBUG( "addAll(): Couldn't open folder: %s\n", Directory.c_str() ); 105 | 106 | if ( EACCES != errno ) 107 | { 108 | mInitOK = false; 109 | } 110 | 111 | mErrno = errno; 112 | 113 | return; 114 | } 115 | 116 | mDirSnap.setDirectoryInfo( Directory ); 117 | mDirSnap.scan(); 118 | 119 | mChangeList.resize( KEVENT_RESERVE_VALUE ); 120 | 121 | // Creates the kevent for the folder 122 | EV_SET( 123 | &mChangeList[0], 124 | fd, 125 | EVFILT_VNODE, 126 | EV_ADD | EV_ENABLE | EV_ONESHOT, 127 | NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, 128 | 0, 129 | 0 130 | ); 131 | 132 | mWatcher->addFD(); 133 | 134 | // Get the files and directories from the directory 135 | FileInfoMap files = FileSystem::filesInfoFromPath( Directory ); 136 | 137 | for ( FileInfoMap::iterator it = files.begin(); it != files.end(); it++ ) 138 | { 139 | FileInfo& fi = it->second; 140 | 141 | if ( fi.isRegularFile() ) 142 | { 143 | // Add the regular files kevent 144 | addFile( fi.Filepath , false ); 145 | } 146 | else if ( Recursive && fi.isDirectory() && fi.isReadable() ) 147 | { 148 | // Create another watcher for the subfolders ( if recursive ) 149 | WatchID id = addWatch( fi.Filepath, Listener, Recursive, this ); 150 | 151 | // If the watcher is not adding the watcher means that the directory was created 152 | if ( id > 0 && !mWatcher->isAddingWatcher() ) 153 | { 154 | handleFolderAction( fi.Filepath, Actions::Add ); 155 | } 156 | } 157 | } 158 | } 159 | 160 | void WatcherKqueue::removeAll() 161 | { 162 | efDEBUG( "removeAll(): Removing all child watchers\n" ); 163 | 164 | std::list erase; 165 | 166 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) 167 | { 168 | efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); 169 | 170 | erase.push_back( it->second->ID ); 171 | } 172 | 173 | for ( std::list::iterator eit = erase.begin(); eit != erase.end(); eit++ ) 174 | { 175 | removeWatch( *eit ); 176 | } 177 | } 178 | 179 | void WatcherKqueue::addFile(const std::string& name, bool emitEvents) 180 | { 181 | efDEBUG( "addFile(): Added: %s\n", name.c_str() ); 182 | 183 | // Open the file to get the file descriptor 184 | int fd = open( name.c_str(), O_EVTONLY ); 185 | 186 | if( fd == -1 ) 187 | { 188 | efDEBUG( "addFile(): Could open file descriptor for %s. File descriptor count: %ld\n", name.c_str(), mWatcher->mFileDescriptorCount ); 189 | 190 | Errors::Log::createLastError( Errors::FileNotReadable, name ); 191 | 192 | if ( EACCES != errno ) 193 | { 194 | mInitOK = false; 195 | } 196 | 197 | mErrno = errno; 198 | 199 | return; 200 | } 201 | 202 | mWatcher->addFD(); 203 | 204 | // increase the file kevent file count 205 | mChangeListCount++; 206 | 207 | if ( mChangeListCount + KEVENT_RESERVE_VALUE > mChangeList.size() && 208 | mChangeListCount % KEVENT_RESERVE_VALUE == 0 ) 209 | { 210 | size_t reserve_size = mChangeList.size() + KEVENT_RESERVE_VALUE; 211 | mChangeList.resize( reserve_size ); 212 | efDEBUG( "addFile(): Reserverd more KEvents space for %s, space reserved %ld, list actual size %ld.\n", Directory.c_str(), reserve_size, mChangeListCount ); 213 | } 214 | 215 | // create entry 216 | FileInfo * entry = new FileInfo( name ); 217 | 218 | // set the event data at the end of the list 219 | EV_SET( 220 | &mChangeList[mChangeListCount], 221 | fd, 222 | EVFILT_VNODE, 223 | EV_ADD | EV_ENABLE | EV_ONESHOT, 224 | NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, 225 | 0, 226 | (void*)entry 227 | ); 228 | 229 | // qsort sort the list by name 230 | qsort(&mChangeList[1], mChangeListCount, sizeof(KEvent), comparator); 231 | 232 | // handle action 233 | if( emitEvents ) 234 | { 235 | handleAction(name, Actions::Add); 236 | } 237 | } 238 | 239 | void WatcherKqueue::removeFile( const std::string& name, bool emitEvents ) 240 | { 241 | efDEBUG( "removeFile(): Trying to remove file: %s\n", name.c_str() ); 242 | 243 | // bsearch 244 | KEvent target; 245 | 246 | // Create a temporary file info to search the kevent ( searching the directory ) 247 | FileInfo tempEntry( name ); 248 | 249 | target.udata = &tempEntry; 250 | 251 | // Search the kevent 252 | KEvent * ke = (KEvent*)bsearch(&target, &mChangeList[0], mChangeListCount + 1, sizeof(KEvent), comparator); 253 | 254 | // Trying to remove a non-existing file? 255 | if( !ke ) 256 | { 257 | Errors::Log::createLastError( Errors::FileNotFound, name ); 258 | efDEBUG( "File not removed\n" ); 259 | return; 260 | } 261 | 262 | efDEBUG( "File removed\n" ); 263 | 264 | // handle action 265 | if ( emitEvents ) 266 | { 267 | handleAction( name, Actions::Delete ); 268 | } 269 | 270 | // Delete the user data ( FileInfo ) from the kevent closed 271 | FileInfo * del = reinterpret_cast( ke->udata ); 272 | 273 | efSAFE_DELETE( del ); 274 | 275 | // close the file descriptor from the kevent 276 | close( ke->ident ); 277 | 278 | mWatcher->removeFD(); 279 | 280 | memset(ke, 0, sizeof(KEvent)); 281 | 282 | // move end to current 283 | memcpy(ke, &mChangeList[mChangeListCount], sizeof(KEvent)); 284 | memset(&mChangeList[mChangeListCount], 0, sizeof(KEvent)); 285 | --mChangeListCount; 286 | } 287 | 288 | void WatcherKqueue::rescan() 289 | { 290 | efDEBUG( "rescan(): Rescanning: %s\n", Directory.c_str() ); 291 | 292 | DirectorySnapshotDiff Diff = mDirSnap.scan(); 293 | 294 | if ( Diff.DirChanged ) 295 | { 296 | sendDirChanged(); 297 | } 298 | 299 | if ( Diff.changed() ) 300 | { 301 | FileInfoList::iterator it; 302 | MovedList::iterator mit; 303 | 304 | /// Files 305 | DiffIterator( FilesCreated ) 306 | { 307 | addFile( (*it).Filepath ); 308 | } 309 | 310 | DiffIterator( FilesModified ) 311 | { 312 | handleAction( (*it).Filepath, Actions::Modified ); 313 | } 314 | 315 | DiffIterator( FilesDeleted ) 316 | { 317 | removeFile( (*it).Filepath ); 318 | } 319 | 320 | DiffMovedIterator( FilesMoved ) 321 | { 322 | handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first ); 323 | removeFile( Directory + (*mit).first, false ); 324 | addFile( (*mit).second.Filepath, false ); 325 | } 326 | 327 | /// Directories 328 | DiffIterator( DirsCreated ) 329 | { 330 | handleFolderAction( (*it).Filepath, Actions::Add ); 331 | addWatch( (*it).Filepath, Listener, Recursive, this ); 332 | } 333 | 334 | DiffIterator( DirsModified ) 335 | { 336 | handleFolderAction( (*it).Filepath, Actions::Modified ); 337 | } 338 | 339 | DiffIterator( DirsDeleted ) 340 | { 341 | handleFolderAction( (*it).Filepath, Actions::Delete ); 342 | 343 | Watcher * watch = findWatcher( (*it).Filepath ); 344 | 345 | if ( NULL != watch ) 346 | { 347 | removeWatch( watch->ID ); 348 | 349 | } 350 | } 351 | 352 | DiffMovedIterator( DirsMoved ) 353 | { 354 | moveDirectory( Directory + (*mit).first, (*mit).second.Filepath ); 355 | } 356 | } 357 | } 358 | 359 | WatchID WatcherKqueue::watchingDirectory( std::string dir ) 360 | { 361 | Watcher * watch = findWatcher( dir ); 362 | 363 | if ( NULL != watch ) 364 | { 365 | return watch->ID; 366 | } 367 | 368 | return Errors::FileNotFound; 369 | } 370 | 371 | void WatcherKqueue::handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename ) 372 | { 373 | Listener->handleFileAction( ID, Directory, FileSystem::fileNameFromPath( filename ), action, FileSystem::fileNameFromPath( oldFilename ) ); 374 | } 375 | 376 | void WatcherKqueue::handleFolderAction( std::string filename, efsw::Action action , const std::string &oldFilename ) 377 | { 378 | FileSystem::dirRemoveSlashAtEnd( filename ); 379 | 380 | handleAction( filename, action, oldFilename ); 381 | } 382 | 383 | void WatcherKqueue::sendDirChanged() 384 | { 385 | if ( NULL != mParent ) 386 | { 387 | Listener->handleFileAction( mParent->ID, mParent->Directory, FileSystem::fileNameFromPath( Directory ), Actions::Modified ); 388 | } 389 | } 390 | 391 | void WatcherKqueue::watch() 392 | { 393 | if ( -1 == mKqueue ) 394 | { 395 | return; 396 | } 397 | 398 | int nev = 0; 399 | KEvent event; 400 | 401 | // First iterate the childs, to get the events from the deepest folder, to the watcher childs 402 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) 403 | { 404 | it->second->watch(); 405 | } 406 | 407 | bool needScan = false; 408 | 409 | // Then we get the the events of the current folder 410 | while( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, &mWatcher->mTimeOut ) ) != 0 ) 411 | { 412 | // An error ocurred? 413 | if( nev == -1 ) 414 | { 415 | efDEBUG( "watch(): Error on directory %s\n", Directory.c_str() ); 416 | perror("kevent"); 417 | break; 418 | } 419 | else 420 | { 421 | FileInfo * entry = NULL; 422 | 423 | // If udate == NULL means that it is the fisrt element of the change list, the folder. 424 | // otherwise it is an event of some file inside the folder 425 | if( ( entry = reinterpret_cast ( event.udata ) ) != NULL ) 426 | { 427 | efDEBUG( "watch(): File: %s ", entry->Filepath.c_str() ); 428 | 429 | // If the event flag is delete... the file was deleted 430 | if ( event.fflags & NOTE_DELETE ) 431 | { 432 | efDEBUG( "deleted\n" ); 433 | 434 | mDirSnap.removeFile( entry->Filepath ); 435 | 436 | removeFile( entry->Filepath ); 437 | } 438 | else if ( event.fflags & NOTE_EXTEND || 439 | event.fflags & NOTE_WRITE || 440 | event.fflags & NOTE_ATTRIB 441 | ) 442 | { 443 | // The file was modified 444 | efDEBUG( "modified\n" ); 445 | 446 | FileInfo fi( entry->Filepath ); 447 | 448 | if ( fi != *entry ) 449 | { 450 | *entry = fi; 451 | 452 | mDirSnap.updateFile( entry->Filepath ); 453 | 454 | handleAction( entry->Filepath, efsw::Actions::Modified ); 455 | } 456 | } 457 | else if ( event.fflags & NOTE_RENAME ) 458 | { 459 | efDEBUG( "moved\n" ); 460 | 461 | needScan = true; 462 | } 463 | } 464 | else 465 | { 466 | needScan = true; 467 | } 468 | } 469 | } 470 | 471 | if ( needScan ) 472 | { 473 | rescan(); 474 | } 475 | } 476 | 477 | Watcher * WatcherKqueue::findWatcher( const std::string path ) 478 | { 479 | WatchMap::iterator it = mWatches.begin(); 480 | 481 | for ( ; it != mWatches.end(); it++ ) 482 | { 483 | if ( it->second->Directory == path ) 484 | { 485 | return it->second; 486 | } 487 | } 488 | 489 | return NULL; 490 | } 491 | 492 | void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, bool emitEvents ) 493 | { 494 | // Update the directory path if it's a watcher 495 | std::string opath2( oldPath ); 496 | FileSystem::dirAddSlashAtEnd( opath2 ); 497 | 498 | Watcher * watch = findWatcher( opath2 ); 499 | 500 | if ( NULL != watch ) 501 | { 502 | watch->Directory = opath2; 503 | } 504 | 505 | if ( emitEvents ) 506 | { 507 | handleFolderAction( newPath, efsw::Actions::Moved, oldPath ); 508 | } 509 | } 510 | 511 | WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive , WatcherKqueue *parent) 512 | { 513 | static long s_fc = 0; 514 | static bool s_ug = false; 515 | 516 | std::string dir( directory ); 517 | 518 | FileSystem::dirAddSlashAtEnd( dir ); 519 | 520 | // This should never happen here 521 | if( !FileSystem::isDirectory( dir ) ) 522 | { 523 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); 524 | } 525 | else if ( pathInWatches( dir ) || pathInParent( dir ) ) 526 | { 527 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); 528 | } 529 | 530 | std::string curPath; 531 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); 532 | 533 | if ( "" != link ) 534 | { 535 | /// Avoid adding symlinks directories if it's now enabled 536 | if ( NULL != parent && !mWatcher->mFileWatcher->followSymlinks() ) 537 | { 538 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); 539 | } 540 | 541 | if ( pathInWatches( link ) || pathInParent( link ) ) 542 | { 543 | return Errors::Log::createLastError( Errors::FileRepeated, link ); 544 | } 545 | else if ( !mWatcher->linkAllowed( curPath, link ) ) 546 | { 547 | return Errors::Log::createLastError( Errors::FileOutOfScope, link ); 548 | } 549 | else 550 | { 551 | dir = link; 552 | } 553 | } 554 | 555 | if ( mWatcher->availablesFD() ) 556 | { 557 | WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, mWatcher, parent ); 558 | 559 | mWatches.insert(std::make_pair(mLastWatchID, watch)); 560 | 561 | watch->addAll(); 562 | 563 | s_fc++; 564 | 565 | // if failed to open the directory... erase the watcher 566 | if ( !watch->initOK() ) 567 | { 568 | int le = watch->lastErrno(); 569 | 570 | mWatches.erase( watch->ID ); 571 | 572 | efSAFE_DELETE( watch ); 573 | 574 | mLastWatchID--; 575 | 576 | // Probably the folder has too many files, create a generic watcher 577 | if ( EACCES != le ) 578 | { 579 | WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive ); 580 | 581 | mWatches.insert(std::make_pair(mLastWatchID, watch)); 582 | } 583 | else 584 | { 585 | return Errors::Log::createLastError( Errors::Unspecified, link ); 586 | } 587 | } 588 | } 589 | else 590 | { 591 | if ( !s_ug ) 592 | { 593 | efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders added: %ld\n", mWatcher->mFileDescriptorCount, s_fc ); 594 | s_ug = true; 595 | } 596 | 597 | WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive ); 598 | 599 | mWatches.insert(std::make_pair(mLastWatchID, watch)); 600 | } 601 | 602 | return mLastWatchID; 603 | } 604 | 605 | bool WatcherKqueue::initOK() 606 | { 607 | return mInitOK; 608 | } 609 | 610 | void WatcherKqueue::removeWatch( WatchID watchid ) 611 | { 612 | WatchMap::iterator iter = mWatches.find(watchid); 613 | 614 | if(iter == mWatches.end()) 615 | return; 616 | 617 | Watcher * watch = iter->second; 618 | 619 | mWatches.erase(iter); 620 | 621 | efSAFE_DELETE( watch ); 622 | } 623 | 624 | bool WatcherKqueue::pathInWatches( const std::string& path ) 625 | { 626 | return NULL != findWatcher( path ); 627 | } 628 | 629 | bool WatcherKqueue::pathInParent( const std::string &path ) 630 | { 631 | WatcherKqueue * pNext = mParent; 632 | 633 | while ( NULL != pNext ) 634 | { 635 | if ( pNext->pathInWatches( path ) ) 636 | { 637 | return true; 638 | } 639 | 640 | pNext = pNext->mParent; 641 | } 642 | 643 | if ( mWatcher->pathInWatches( path ) ) 644 | { 645 | return true; 646 | } 647 | 648 | if ( path == Directory ) 649 | { 650 | return true; 651 | } 652 | 653 | return false; 654 | } 655 | 656 | int WatcherKqueue::lastErrno() 657 | { 658 | return mErrno; 659 | } 660 | 661 | } 662 | 663 | #endif 664 | -------------------------------------------------------------------------------- /src/efsw/WatcherKqueue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHEROSX_HPP 2 | #define EFSW_WATCHEROSX_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace efsw 15 | { 16 | 17 | class FileWatcherKqueue; 18 | class WatcherKqueue; 19 | 20 | typedef struct kevent KEvent; 21 | 22 | /// type for a map from WatchID to WatcherKqueue pointer 23 | typedef std::map WatchMap; 24 | 25 | class WatcherKqueue : public Watcher 26 | { 27 | public: 28 | WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent = NULL ); 29 | 30 | virtual ~WatcherKqueue(); 31 | 32 | void addFile( const std::string& name, bool emitEvents = true ); 33 | 34 | void removeFile( const std::string& name, bool emitEvents = true ); 35 | 36 | // called when the directory is actually changed 37 | // means a file has been added or removed 38 | // rescans the watched directory adding/removing files and sending notices 39 | void rescan(); 40 | 41 | void handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename = "" ); 42 | 43 | void handleFolderAction( std::string filename, efsw::Action action, const std::string& oldFilename = "" ); 44 | 45 | void addAll(); 46 | 47 | void removeAll(); 48 | 49 | WatchID watchingDirectory( std::string dir ); 50 | 51 | void watch(); 52 | 53 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherKqueue * parent); 54 | 55 | void removeWatch (WatchID watchid ); 56 | 57 | bool initOK(); 58 | 59 | int lastErrno(); 60 | protected: 61 | WatchMap mWatches; 62 | int mLastWatchID; 63 | 64 | // index 0 is always the directory 65 | std::vector mChangeList; 66 | size_t mChangeListCount; 67 | DirectorySnapshot mDirSnap; 68 | 69 | /// The descriptor for the kqueue 70 | int mKqueue; 71 | 72 | FileWatcherKqueue * mWatcher; 73 | 74 | WatcherKqueue * mParent; 75 | 76 | bool mInitOK; 77 | int mErrno; 78 | 79 | bool pathInWatches( const std::string& path ); 80 | 81 | bool pathInParent( const std::string& path ); 82 | 83 | Watcher * findWatcher( const std::string path ); 84 | 85 | void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true ); 86 | 87 | void sendDirChanged(); 88 | }; 89 | 90 | } 91 | 92 | #endif 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /src/efsw/WatcherWin32.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 4 | 5 | namespace efsw 6 | { 7 | 8 | /// Unpacks events and passes them to a user defined callback. 9 | void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) 10 | { 11 | TCHAR szFile[MAX_PATH]; 12 | PFILE_NOTIFY_INFORMATION pNotify; 13 | WatcherStructWin32 * tWatch = (WatcherStructWin32*) lpOverlapped; 14 | WatcherWin32 * pWatch = tWatch->Watch; 15 | size_t offset = 0; 16 | 17 | if(dwNumberOfBytesTransfered == 0) 18 | return; 19 | 20 | if (dwErrorCode == ERROR_SUCCESS) 21 | { 22 | do 23 | { 24 | pNotify = (PFILE_NOTIFY_INFORMATION) &pWatch->mBuffer[offset]; 25 | offset += pNotify->NextEntryOffset; 26 | 27 | # if defined(UNICODE) 28 | { 29 | lstrcpynW(szFile, pNotify->FileName, 30 | min(MAX_PATH, pNotify->FileNameLength / sizeof(WCHAR) + 1)); 31 | } 32 | # else 33 | { 34 | int count = WideCharToMultiByte(CP_ACP, 0, pNotify->FileName, 35 | pNotify->FileNameLength / sizeof(WCHAR), 36 | szFile, MAX_PATH - 1, NULL, NULL); 37 | szFile[count] = TEXT('\0'); 38 | } 39 | # endif 40 | 41 | pWatch->Watch->handleAction(pWatch, szFile, pNotify->Action); 42 | 43 | } while (pNotify->NextEntryOffset != 0); 44 | } 45 | 46 | if (!pWatch->StopNow) 47 | { 48 | RefreshWatch(tWatch); 49 | } 50 | } 51 | 52 | /// Refreshes the directory monitoring. 53 | bool RefreshWatch(WatcherStructWin32* pWatch, bool _clear) 54 | { 55 | return ReadDirectoryChangesW( 56 | pWatch->Watch->DirHandle, 57 | pWatch->Watch->mBuffer, 58 | sizeof(pWatch->Watch->mBuffer), 59 | pWatch->Watch->Recursive, 60 | pWatch->Watch->NotifyFilter, 61 | NULL, 62 | &pWatch->Overlapped, 63 | _clear ? 0 : WatchCallback 64 | ) != 0; 65 | } 66 | 67 | /// Stops monitoring a directory. 68 | void DestroyWatch(WatcherStructWin32* pWatch) 69 | { 70 | if (pWatch) 71 | { 72 | WatcherWin32 * tWatch = pWatch->Watch; 73 | 74 | tWatch->StopNow = TRUE; 75 | 76 | CancelIo(tWatch->DirHandle); 77 | 78 | RefreshWatch(pWatch, true); 79 | 80 | if (!HasOverlappedIoCompleted(&pWatch->Overlapped)) 81 | { 82 | SleepEx(5, TRUE); 83 | } 84 | 85 | CloseHandle(pWatch->Overlapped.hEvent); 86 | CloseHandle(pWatch->Watch->DirHandle); 87 | efSAFE_DELETE( pWatch->Watch->DirName ); 88 | efSAFE_DELETE( pWatch->Watch ); 89 | HeapFree(GetProcessHeap(), 0, pWatch); 90 | } 91 | } 92 | 93 | /// Starts monitoring a directory. 94 | WatcherStructWin32* CreateWatch(LPCTSTR szDirectory, bool recursive, DWORD NotifyFilter) 95 | { 96 | WatcherStructWin32 * tWatch; 97 | size_t ptrsize = sizeof(*tWatch); 98 | tWatch = static_cast(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize)); 99 | 100 | WatcherWin32 * pWatch = new WatcherWin32(); 101 | tWatch->Watch = pWatch; 102 | 103 | pWatch->DirHandle = CreateFile( 104 | szDirectory, 105 | GENERIC_READ, 106 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 107 | NULL, 108 | OPEN_EXISTING, 109 | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 110 | NULL 111 | ); 112 | 113 | if (pWatch->DirHandle != INVALID_HANDLE_VALUE) 114 | { 115 | tWatch->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 116 | pWatch->NotifyFilter = NotifyFilter; 117 | pWatch->Recursive = recursive; 118 | 119 | if (RefreshWatch(tWatch)) 120 | { 121 | return tWatch; 122 | } 123 | else 124 | { 125 | CloseHandle(tWatch->Overlapped.hEvent); 126 | CloseHandle(pWatch->DirHandle); 127 | } 128 | } 129 | 130 | HeapFree(GetProcessHeap(), 0, tWatch); 131 | return NULL; 132 | } 133 | 134 | } 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /src/efsw/WatcherWin32.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERWIN32_HPP 2 | #define EFSW_WATCHERWIN32_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | #define _WIN32_WINNT 0x0550 9 | #include 10 | 11 | #ifdef EFSW_COMPILER_MSVC 12 | #pragma comment(lib, "comctl32.lib") 13 | #pragma comment(lib, "user32.lib") 14 | #pragma comment(lib, "ole32.lib") 15 | 16 | // disable secure warnings 17 | #pragma warning (disable: 4996) 18 | #endif 19 | 20 | namespace efsw 21 | { 22 | 23 | class WatcherWin32; 24 | 25 | /// Internal watch data 26 | struct WatcherStructWin32 27 | { 28 | OVERLAPPED Overlapped; 29 | WatcherWin32 * Watch; 30 | }; 31 | 32 | bool RefreshWatch(WatcherStructWin32* pWatch, bool _clear = false); 33 | 34 | void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped); 35 | 36 | void DestroyWatch(WatcherStructWin32* pWatch); 37 | 38 | WatcherStructWin32* CreateWatch(LPCTSTR szDirectory, bool recursive, DWORD NotifyFilter); 39 | 40 | class WatcherWin32 : public Watcher 41 | { 42 | public: 43 | WatcherStructWin32 * Struct; 44 | HANDLE DirHandle; 45 | BYTE mBuffer[32 * 1024]; 46 | LPARAM lParam; 47 | DWORD NotifyFilter; 48 | bool StopNow; 49 | FileWatcherImpl* Watch; 50 | char* DirName; 51 | }; 52 | 53 | } 54 | 55 | #endif 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/efsw/base.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_BASE 2 | #define EFSW_BASE 3 | 4 | #include 5 | #include 6 | 7 | namespace efsw { 8 | 9 | typedef SOPHIST_int8 Int8; 10 | typedef SOPHIST_uint8 Uint8; 11 | typedef SOPHIST_int16 Int16; 12 | typedef SOPHIST_uint16 Uint16; 13 | typedef SOPHIST_int32 Int32; 14 | typedef SOPHIST_uint32 Uint32; 15 | typedef SOPHIST_int64 Int64; 16 | typedef SOPHIST_uint64 Uint64; 17 | 18 | #define EFSW_OS_WIN 1 19 | #define EFSW_OS_LINUX 2 20 | #define EFSW_OS_MACOSX 3 21 | #define EFSW_OS_BSD 4 22 | #define EFSW_OS_SOLARIS 5 23 | #define EFSW_OS_HAIKU 6 24 | #define EFSW_OS_ANDROID 7 25 | #define EFSW_OS_IOS 8 26 | 27 | #define EFSW_PLATFORM_WIN32 1 28 | #define EFSW_PLATFORM_INOTIFY 2 29 | #define EFSW_PLATFORM_KQUEUE 3 30 | #define EFSW_PLATFORM_FSEVENTS 4 31 | #define EFSW_PLATFORM_GENERIC 5 32 | 33 | #if defined(_WIN32) 34 | /// Any Windows platform 35 | #define EFSW_OS EFSW_OS_WIN 36 | #define EFSW_PLATFORM EFSW_PLATFORM_WIN32 37 | 38 | #if ( defined( _MSCVER ) || defined( _MSC_VER ) ) 39 | #define EFSW_COMPILER_MSVC 40 | #endif 41 | 42 | #elif defined( __FreeBSD__ ) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined( __DragonFly__ ) 43 | #define EFSW_OS EFSW_OS_BSD 44 | #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE 45 | 46 | #elif defined( __APPLE_CC__ ) || defined ( __APPLE__ ) 47 | #include 48 | 49 | #if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR ) 50 | #define EFSW_OS EFSW_OS_IOS 51 | #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE 52 | #else 53 | #define EFSW_OS EFSW_OS_MACOSX 54 | 55 | #if defined(EFSW_FSEVENTS_NOT_SUPPORTED) 56 | #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE 57 | #else 58 | #define EFSW_PLATFORM EFSW_PLATFORM_FSEVENTS 59 | #endif 60 | #endif 61 | 62 | #elif defined(__linux__) 63 | /// This includes Linux and Android 64 | #ifndef EFSW_KQUEUE 65 | #define EFSW_PLATFORM EFSW_PLATFORM_INOTIFY 66 | #else 67 | /// This is for testing libkqueue, sadly it doesnt work 68 | #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE 69 | #endif 70 | 71 | #if defined( __ANDROID__ ) || defined( ANDROID ) 72 | #define EFSW_OS EFSW_OS_ANDROID 73 | #else 74 | #define EFSW_OS EFSW_OS_LINUX 75 | #endif 76 | 77 | #else 78 | #if defined( __SVR4 ) 79 | #define EFSW_OS EFSW_OS_SOLARIS 80 | #elif defined( __HAIKU__ ) || defined( __BEOS__ ) 81 | #define EFSW_OS EFSW_OS_HAIKU 82 | #endif 83 | 84 | /// Everything else 85 | #define EFSW_PLATFORM EFSW_PLATFORM_GENERIC 86 | #endif 87 | 88 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 89 | #define EFSW_PLATFORM_POSIX 90 | #endif 91 | 92 | #if 1 == SOPHIST_pointer64 93 | #define EFSW_64BIT 94 | #else 95 | #define EFSW_32BIT 96 | #endif 97 | 98 | #if defined(arm) || defined(__arm__) 99 | #define EFSW_ARM 100 | #endif 101 | 102 | #define efCOMMA , 103 | 104 | #define efSAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } 105 | #define efSAFE_DELETE_ARRAY(p) { if(p) { delete [] (p); (p)=NULL; } } 106 | 107 | } 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /src/efsw/platform/platformimpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_PLATFORMIMPL_HPP 2 | #define EFSW_PLATFORMIMPL_HPP 3 | 4 | #include 5 | 6 | #if defined( EFSW_PLATFORM_POSIX ) 7 | #include 8 | #include 9 | #include 10 | #include 11 | #elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32 12 | #include 13 | #include 14 | #include 15 | #include 16 | #else 17 | #error Thread, Mutex, and System not implemented for this platform. 18 | #endif 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/efsw/platform/posix/FileSystemImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined( EFSW_PLATFORM_POSIX ) 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace efsw { namespace Platform { 13 | 14 | FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) 15 | { 16 | FileInfoMap files; 17 | 18 | DIR *dp; 19 | struct dirent *dirp; 20 | 21 | if( ( dp = opendir( path.c_str() ) ) == NULL) 22 | return files; 23 | 24 | while ( ( dirp = readdir(dp) ) != NULL) 25 | { 26 | if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 ) 27 | { 28 | std::string name( dirp->d_name ); 29 | std::string fpath( path + name ); 30 | 31 | files[ name ] = FileInfo( fpath ); 32 | } 33 | } 34 | 35 | closedir(dp); 36 | 37 | return files; 38 | } 39 | 40 | char FileSystem::getOSSlash() 41 | { 42 | return '/'; 43 | } 44 | 45 | bool FileSystem::isDirectory( const std::string& path ) 46 | { 47 | struct stat st; 48 | int res = stat( path.c_str(), &st ); 49 | 50 | if ( 0 == res ) 51 | { 52 | return static_cast( S_ISDIR(st.st_mode) ); 53 | } 54 | 55 | return false; 56 | } 57 | 58 | }} 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/efsw/platform/posix/FileSystemImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP 2 | #define EFSW_FILESYSTEMIMPLPOSIX_HPP 3 | 4 | #include 5 | #include 6 | 7 | #if defined( EFSW_PLATFORM_POSIX ) 8 | 9 | namespace efsw { namespace Platform { 10 | 11 | class FileSystem 12 | { 13 | public: 14 | static FileInfoMap filesInfoFromPath( const std::string& path ); 15 | 16 | static char getOSSlash(); 17 | 18 | static bool isDirectory( const std::string& path ); 19 | }; 20 | 21 | }} 22 | 23 | #endif 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/efsw/platform/posix/MutexImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined( EFSW_PLATFORM_POSIX ) 4 | 5 | namespace efsw { namespace Platform { 6 | 7 | MutexImpl::MutexImpl() 8 | { 9 | pthread_mutexattr_t attributes; 10 | pthread_mutexattr_init(&attributes); 11 | pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); 12 | pthread_mutex_init(&mMutex, &attributes); 13 | } 14 | 15 | MutexImpl::~MutexImpl() 16 | { 17 | pthread_mutex_destroy(&mMutex); 18 | } 19 | 20 | void MutexImpl::lock() 21 | { 22 | pthread_mutex_lock(&mMutex); 23 | } 24 | 25 | void MutexImpl::unlock() 26 | { 27 | pthread_mutex_unlock(&mMutex); 28 | } 29 | 30 | }} 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/efsw/platform/posix/MutexImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_MUTEXIMPLPOSIX_HPP 2 | #define EFSW_MUTEXIMPLPOSIX_HPP 3 | 4 | #include 5 | 6 | #if defined( EFSW_PLATFORM_POSIX ) 7 | 8 | #include 9 | 10 | namespace efsw { namespace Platform { 11 | 12 | class MutexImpl 13 | { 14 | public: 15 | MutexImpl(); 16 | 17 | ~MutexImpl(); 18 | 19 | void lock(); 20 | 21 | void unlock(); 22 | private: 23 | pthread_mutex_t mMutex; 24 | }; 25 | 26 | }} 27 | 28 | #endif 29 | 30 | #endif 31 | 32 | -------------------------------------------------------------------------------- /src/efsw/platform/posix/SystemImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined( EFSW_PLATFORM_POSIX ) 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #if EFSW_OS == EFSW_OS_MACOSX 14 | #include 15 | #elif EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_ANDROID 16 | #include 17 | #include 18 | #elif EFSW_OS == EFSW_OS_HAIKU 19 | #include 20 | #include 21 | #elif EFSW_OS == EFSW_OS_SOLARIS 22 | #include 23 | #elif EFSW_OS == EFSW_OS_BSD 24 | #include 25 | #endif 26 | 27 | namespace efsw { namespace Platform { 28 | 29 | void System::sleep( const unsigned long& ms ) 30 | { 31 | // usleep( static_cast( ms * 1000 ) ); 32 | 33 | // usleep is not reliable enough (it might block the 34 | // whole process instead of just the current thread) 35 | // so we must use pthread_cond_timedwait instead 36 | 37 | // this implementation is inspired from Qt 38 | // and taken from SFML 39 | 40 | unsigned long long usecs = ms * 1000; 41 | 42 | // get the current time 43 | timeval tv; 44 | gettimeofday(&tv, NULL); 45 | 46 | // construct the time limit (current time + time to wait) 47 | timespec ti; 48 | ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000; 49 | ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000); 50 | ti.tv_nsec %= 1000000000; 51 | 52 | // create a mutex and thread condition 53 | pthread_mutex_t mutex; 54 | pthread_mutex_init(&mutex, 0); 55 | pthread_cond_t condition; 56 | pthread_cond_init(&condition, 0); 57 | 58 | // wait... 59 | pthread_mutex_lock(&mutex); 60 | pthread_cond_timedwait(&condition, &mutex, &ti); 61 | pthread_mutex_unlock(&mutex); 62 | 63 | // destroy the mutex and condition 64 | pthread_cond_destroy(&condition); 65 | } 66 | 67 | std::string System::getProcessPath() 68 | { 69 | #if EFSW_OS == EFSW_OS_MACOSX 70 | char exe_file[PATH_MAX + 1]; 71 | 72 | CFBundleRef mainBundle = CFBundleGetMainBundle(); 73 | 74 | if (mainBundle) 75 | { 76 | CFURLRef mainURL = CFBundleCopyBundleURL(mainBundle); 77 | 78 | if (mainURL) 79 | { 80 | int ok = CFURLGetFileSystemRepresentation ( mainURL, (Boolean) true, (UInt8*)exe_file, PATH_MAX ); 81 | 82 | if (ok) 83 | { 84 | return std::string(exe_file) + "/"; 85 | } 86 | } 87 | } 88 | 89 | return "./"; 90 | #elif EFSW_OS == EFSW_OS_LINUX 91 | char exe_file[PATH_MAX + 1]; 92 | 93 | int size; 94 | 95 | size = readlink("/proc/self/exe", exe_file, PATH_MAX); 96 | 97 | if (size < 0) 98 | { 99 | return std::string( "./" ); 100 | } 101 | else 102 | { 103 | exe_file[size] = '\0'; 104 | return std::string( dirname( exe_file ) ) + "/"; 105 | } 106 | 107 | #elif EFSW_OS == EFSW_OS_BSD 108 | int mib[4]; 109 | mib[0] = CTL_KERN; 110 | mib[1] = KERN_PROC; 111 | mib[2] = KERN_PROC_PATHNAME; 112 | mib[3] = -1; 113 | char buf[1024]; 114 | size_t cb = sizeof(buf); 115 | sysctl(mib, 4, buf, &cb, NULL, 0); 116 | 117 | return FileSystem::pathRemoveFileName( std::string( buf ) ); 118 | 119 | #elif EFSW_OS == EFSW_OS_SOLARIS 120 | return FileSystem::pathRemoveFileName( std::string( getexecname() ) ); 121 | 122 | #elif EFSW_OS == EFSW_OS_HAIKU 123 | image_info info; 124 | int32 cookie = 0; 125 | 126 | while ( B_OK == get_next_image_info( 0, &cookie, &info ) ) 127 | { 128 | if ( info.type == B_APP_IMAGE ) 129 | break; 130 | } 131 | 132 | return FileSystem::pathRemoveFileName( std::string( info.name ) ); 133 | 134 | #elif EFSW_OS == EFSW_OS_ANDROID 135 | return "/sdcard/"; 136 | 137 | #else 138 | #warning getProcessPath() not implemented on this platform. ( will return "./" ) 139 | return "./"; 140 | 141 | #endif 142 | } 143 | 144 | void System::maxFD() 145 | { 146 | static bool maxed = false; 147 | 148 | if ( !maxed ) 149 | { 150 | struct rlimit limit; 151 | getrlimit( RLIMIT_NOFILE, &limit ); 152 | limit.rlim_cur = limit.rlim_max; 153 | setrlimit( RLIMIT_NOFILE, &limit ); 154 | 155 | getrlimit( RLIMIT_NOFILE, &limit ); 156 | 157 | efDEBUG( "File descriptor limit %ld\n", limit.rlim_cur ); 158 | 159 | maxed = true; 160 | } 161 | } 162 | 163 | Uint64 System::getMaxFD() 164 | { 165 | static rlim_t max_fd = 0; 166 | 167 | if ( max_fd == 0 ) 168 | { 169 | struct rlimit limit; 170 | getrlimit( RLIMIT_NOFILE, &limit ); 171 | max_fd = limit.rlim_cur; 172 | } 173 | 174 | return max_fd; 175 | } 176 | 177 | }} 178 | 179 | #endif 180 | -------------------------------------------------------------------------------- /src/efsw/platform/posix/SystemImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_SYSTEMIMPLPOSIX_HPP 2 | #define EFSW_SYSTEMIMPLPOSIX_HPP 3 | 4 | #include 5 | 6 | #if defined( EFSW_PLATFORM_POSIX ) 7 | 8 | namespace efsw { namespace Platform { 9 | 10 | class System 11 | { 12 | public: 13 | static void sleep( const unsigned long& ms ); 14 | 15 | static std::string getProcessPath(); 16 | 17 | static void maxFD(); 18 | 19 | static Uint64 getMaxFD(); 20 | }; 21 | 22 | }} 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/efsw/platform/posix/ThreadImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if defined( EFSW_PLATFORM_POSIX ) 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace efsw { namespace Platform { 11 | 12 | ThreadImpl::ThreadImpl( Thread * owner ) : 13 | mIsActive(false) 14 | { 15 | mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; 16 | 17 | if ( !mIsActive ) 18 | { 19 | efDEBUG( "Failed to create thread\n" ); 20 | } 21 | } 22 | 23 | void ThreadImpl::wait() 24 | { 25 | // Wait for the thread to finish, no timeout 26 | if ( mIsActive ) 27 | { 28 | assert( pthread_equal( pthread_self(), mThread ) == 0 ); 29 | 30 | pthread_join( mThread, NULL ); 31 | 32 | mIsActive = false; // Reset the thread state 33 | } 34 | } 35 | 36 | void ThreadImpl::terminate() 37 | { 38 | if ( mIsActive ) 39 | { 40 | #if !defined( __ANDROID__ ) && !defined( ANDROID ) 41 | pthread_cancel( mThread ); 42 | #else 43 | pthread_kill( mThread , SIGUSR1 ); 44 | #endif 45 | 46 | mIsActive = false; 47 | } 48 | } 49 | 50 | void * ThreadImpl::entryPoint( void * userData ) 51 | { 52 | // The Thread instance is stored in the user data 53 | Thread * owner = static_cast( userData ); 54 | 55 | // Tell the thread to handle cancel requests immediatly 56 | #ifdef PTHREAD_CANCEL_ASYNCHRONOUS 57 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); 58 | #endif 59 | 60 | // Forward to the owner 61 | owner->run(); 62 | 63 | return NULL; 64 | } 65 | 66 | }} 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/efsw/platform/posix/ThreadImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_THREADIMPLPOSIX_HPP 2 | #define EFSW_THREADIMPLPOSIX_HPP 3 | 4 | #include 5 | 6 | #if defined( EFSW_PLATFORM_POSIX ) 7 | 8 | #include 9 | 10 | namespace efsw { 11 | 12 | class Thread; 13 | 14 | namespace Platform { 15 | 16 | class ThreadImpl 17 | { 18 | public: 19 | ThreadImpl( Thread * owner ); 20 | 21 | void wait(); 22 | 23 | void terminate(); 24 | protected: 25 | static void * entryPoint( void* userData ); 26 | 27 | pthread_t mThread; 28 | bool mIsActive; 29 | }; 30 | 31 | }} 32 | 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/efsw/platform/win/FileSystemImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 4 | 5 | #ifndef WIN32_LEAN_AND_MEAN 6 | #define WIN32_LEAN_AND_MEAN 7 | #endif 8 | #include 9 | 10 | #ifndef EFSW_COMPILER_MSVC 11 | #include 12 | #endif 13 | 14 | namespace efsw { namespace Platform { 15 | 16 | FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) 17 | { 18 | FileInfoMap files; 19 | 20 | #ifdef EFSW_COMPILER_MSVC 21 | #ifdef UNICODE 22 | /// Unicode support just for this? MMHH... 23 | String tpath( String::fromUtf8( path ) ); 24 | 25 | if ( tpath[ tpath.size() - 1 ] == '/' || tpath[ tpath.size() - 1 ] == '\\' ) { 26 | tpath += "*"; 27 | } else { 28 | tpath += "\\*"; 29 | } 30 | 31 | WIN32_FIND_DATA findFileData; 32 | HANDLE hFind = FindFirstFile( (LPCWSTR)tpath.toWideString().c_str(), &findFileData ); 33 | 34 | if( hFind != INVALID_HANDLE_VALUE ) { 35 | String name( findFileData.cFileName ); 36 | std::string fpath( path + name.toUtf8() ); 37 | 38 | if ( name != "." && name != ".." ) 39 | { 40 | files[ name.toUtf8() ] = FileInfo( fpath ); 41 | } 42 | 43 | while( FindNextFile(hFind, &findFileData ) ) { 44 | name = String( findFileData.cFileName ); 45 | fpath = path + name.toUtf8(); 46 | 47 | if ( name != "." && name != ".." ) 48 | { 49 | files[ name.toUtf8() ] = FileInfo( fpath ); 50 | } 51 | } 52 | 53 | FindClose( hFind ); 54 | } 55 | #else 56 | std::string tpath( path ); 57 | 58 | if ( tpath[ tpath.size() - 1 ] == '/' || tpath[ tpath.size() - 1 ] == '\\' ) { 59 | tpath += "*"; 60 | } else { 61 | tpath += "\\*"; 62 | } 63 | 64 | WIN32_FIND_DATA findFileData; 65 | HANDLE hFind = FindFirstFile( (LPCTSTR) tpath.c_str(), &findFileData ); 66 | 67 | if( hFind != INVALID_HANDLE_VALUE ) { 68 | std::string name( findFileData.cFileName ); 69 | std::string fpath( path + name ); 70 | 71 | if ( name != "." && name != ".." ) 72 | { 73 | files[ name ] = FileInfo( fpath ); 74 | } 75 | 76 | while( FindNextFile(hFind, &findFileData ) ) { 77 | name = std::string( findFileData.cFileName ); 78 | fpath = path + name; 79 | 80 | if ( name != "." && name != ".." ) 81 | { 82 | files[ name ] = FileInfo( fpath ); 83 | } 84 | } 85 | 86 | FindClose( hFind ); 87 | } 88 | #endif 89 | 90 | return files; 91 | #else 92 | DIR *dp; 93 | struct dirent *dirp; 94 | 95 | if( ( dp = opendir( path.c_str() ) ) == NULL) 96 | return files; 97 | 98 | while ( ( dirp = readdir(dp) ) != NULL) 99 | { 100 | if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 ) 101 | { 102 | std::string name( dirp->d_name ); 103 | std::string fpath( path + name ); 104 | 105 | files[ name ] = FileInfo( fpath ); 106 | } 107 | } 108 | 109 | closedir(dp); 110 | 111 | return files; 112 | #endif 113 | } 114 | 115 | char FileSystem::getOSSlash() 116 | { 117 | return '\\'; 118 | } 119 | 120 | bool FileSystem::isDirectory( const std::string& path ) 121 | { 122 | return GetFileAttributes( (LPCTSTR) path.c_str() ) == FILE_ATTRIBUTE_DIRECTORY; 123 | } 124 | 125 | 126 | }} 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /src/efsw/platform/win/FileSystemImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILESYSTEMIMPLWIN_HPP 2 | #define EFSW_FILESYSTEMIMPLWIN_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 9 | 10 | namespace efsw { namespace Platform { 11 | 12 | class FileSystem 13 | { 14 | public: 15 | static FileInfoMap filesInfoFromPath( const std::string& path ); 16 | 17 | static char getOSSlash(); 18 | 19 | static bool isDirectory( const std::string& path ); 20 | }; 21 | 22 | }} 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/efsw/platform/win/MutexImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 4 | 5 | namespace efsw { namespace Platform { 6 | 7 | MutexImpl::MutexImpl() 8 | { 9 | InitializeCriticalSection(&mMutex); 10 | } 11 | 12 | MutexImpl::~MutexImpl() 13 | { 14 | DeleteCriticalSection(&mMutex); 15 | } 16 | 17 | void MutexImpl::lock() 18 | { 19 | EnterCriticalSection(&mMutex); 20 | } 21 | 22 | void MutexImpl::unlock() 23 | { 24 | LeaveCriticalSection(&mMutex); 25 | } 26 | 27 | }} 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/efsw/platform/win/MutexImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_MUTEXIMPLWIN_HPP 2 | #define EFSW_MUTEXIMPLWIN_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | #ifndef WIN32_LEAN_AND_MEAN 9 | #define WIN32_LEAN_AND_MEAN 10 | #endif 11 | #include 12 | 13 | namespace efsw { namespace Platform { 14 | 15 | class MutexImpl 16 | { 17 | public: 18 | MutexImpl(); 19 | 20 | ~MutexImpl(); 21 | 22 | void lock(); 23 | 24 | void unlock(); 25 | private: 26 | CRITICAL_SECTION mMutex; 27 | }; 28 | 29 | }} 30 | 31 | #endif 32 | 33 | #endif 34 | 35 | -------------------------------------------------------------------------------- /src/efsw/platform/win/SystemImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 4 | 5 | #ifndef WIN32_LEAN_AND_MEAN 6 | #define WIN32_LEAN_AND_MEAN 7 | #endif 8 | #include 9 | #include 10 | 11 | namespace efsw { namespace Platform { 12 | 13 | void System::sleep( const unsigned long& ms ) 14 | { 15 | ::Sleep( ms ); 16 | } 17 | 18 | std::string System::getProcessPath() { 19 | #ifdef UNICODE 20 | // Get path to executable: 21 | char szDrive[_MAX_DRIVE]; 22 | char szDir[_MAX_DIR]; 23 | char szFilename[_MAX_DIR]; 24 | char szExt[_MAX_DIR]; 25 | std::wstring dllName( _MAX_DIR, 0 ); 26 | 27 | GetModuleFileName(0, &dllName[0], _MAX_PATH); 28 | 29 | std::string dllstrName( String( dllName ).ToUtf8() ); 30 | 31 | #ifdef EE_COMPILER_MSVC 32 | _splitpath_s( dllstrName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, szExt, _MAX_DIR ); 33 | #else 34 | _splitpath(szDllName, szDrive, szDir, szFilename, szExt); 35 | #endif 36 | 37 | return std::string( szDrive ) + std::string( szDir ); 38 | #else 39 | // Get path to executable: 40 | TCHAR szDllName[_MAX_PATH]; 41 | TCHAR szDrive[_MAX_DRIVE]; 42 | TCHAR szDir[_MAX_DIR]; 43 | TCHAR szFilename[_MAX_DIR]; 44 | TCHAR szExt[_MAX_DIR]; 45 | GetModuleFileName(0, szDllName, _MAX_PATH); 46 | 47 | #ifdef EFSW_COMPILER_MSVC 48 | _splitpath_s(szDllName, szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, szExt, _MAX_DIR ); 49 | #else 50 | _splitpath(szDllName, szDrive, szDir, szFilename, szExt); 51 | #endif 52 | 53 | return std::string( szDrive ) + std::string( szDir ); 54 | #endif 55 | } 56 | 57 | void System::maxFD() 58 | { 59 | } 60 | 61 | Uint64 System::getMaxFD() 62 | { // Number of ReadDirectory per thread 63 | return 60; 64 | } 65 | 66 | }} 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/efsw/platform/win/SystemImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_SYSTEMIMPLWIN_HPP 2 | #define EFSW_SYSTEMIMPLWIN_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | namespace efsw { namespace Platform { 9 | 10 | class System 11 | { 12 | public: 13 | static void sleep( const unsigned long& ms ); 14 | 15 | static std::string getProcessPath(); 16 | 17 | static void maxFD(); 18 | 19 | static Uint64 getMaxFD(); 20 | }; 21 | 22 | }} 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/efsw/platform/win/ThreadImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 6 | 7 | #include 8 | 9 | namespace efsw { namespace Platform { 10 | 11 | ThreadImpl::ThreadImpl( Thread *owner ) 12 | { 13 | mThread = reinterpret_cast( _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); 14 | 15 | if ( !mThread ) 16 | { 17 | efDEBUG( "Failed to create thread\n" ); 18 | } 19 | } 20 | 21 | void ThreadImpl::wait() 22 | { 23 | // Wait for the thread to finish, no timeout 24 | if ( mThread ) 25 | { 26 | assert( mThreadId != GetCurrentThreadId() ); // A thread cannot wait for itself! 27 | 28 | WaitForSingleObject( mThread, INFINITE ); 29 | } 30 | } 31 | 32 | void ThreadImpl::terminate() 33 | { 34 | if ( mThread ) 35 | { 36 | TerminateThread( mThread, 0 ); 37 | } 38 | } 39 | 40 | unsigned int __stdcall ThreadImpl::entryPoint( void * userData ) 41 | { 42 | // The Thread instance is stored in the user data 43 | Thread * owner = static_cast( userData ); 44 | 45 | // Forward to the owner 46 | owner->run(); 47 | 48 | // Optional, but it is cleaner 49 | _endthreadex(0); 50 | 51 | return 0; 52 | } 53 | 54 | }} 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/efsw/platform/win/ThreadImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_THREADIMPLWIN_HPP 2 | #define EFSW_THREADIMPLWIN_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | #ifndef WIN32_LEAN_AND_MEAN 9 | #define WIN32_LEAN_AND_MEAN 10 | #endif 11 | #include 12 | #include 13 | 14 | namespace efsw { 15 | 16 | class Thread; 17 | 18 | namespace Platform { 19 | 20 | class ThreadImpl 21 | { 22 | public: 23 | ThreadImpl( Thread * owner ); 24 | 25 | void wait(); 26 | 27 | void terminate(); 28 | protected: 29 | static unsigned int __stdcall entryPoint(void* userData); 30 | 31 | HANDLE mThread; 32 | unsigned int mThreadId; 33 | }; 34 | 35 | }} 36 | 37 | #endif 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/efsw/sophist.h: -------------------------------------------------------------------------------- 1 | /* sophist.h - 0.3 - public domain - Sean Barrett 2010 2 | ** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net 3 | ** Sophist provides portable types; you typedef/#define them to your own names 4 | ** 5 | ** defines: 6 | ** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian 7 | ** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined 8 | ** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit 9 | ** 10 | ** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer 11 | ** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 12 | ** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 13 | ** - SOPHIST_int64_constant(number) - macros for creating 64-bit 14 | ** - SOPHIST_uint64_constant(number) integer constants 15 | ** - SOPHIST_printf_format64 - string for printf format for int64 16 | */ 17 | 18 | #ifndef __INCLUDE_SOPHIST_H__ 19 | #define __INCLUDE_SOPHIST_H__ 20 | 21 | #define SOPHIST_compiletime_assert(name,val) \ 22 | typedef int SOPHIST__assert##name[(val) ? 1 : -1] 23 | 24 | /* define a couple synthetic rules to make code more readable */ 25 | #if (defined(__sparc__) || defined(__sparc)) && \ 26 | (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) 27 | #define SOPHIST_sparc64 28 | #endif 29 | 30 | #if (defined(linux) || defined(__linux__)) && \ 31 | (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) 32 | #define SOPHIST_linux64 33 | #endif 34 | 35 | /* basic types */ 36 | typedef signed char SOPHIST_int8; 37 | typedef unsigned char SOPHIST_uint8; 38 | 39 | typedef signed short SOPHIST_int16; 40 | typedef unsigned short SOPHIST_uint16; 41 | 42 | #ifdef __palmos__ 43 | typedef signed long SOPHIST_int32; 44 | typedef unsigned long SOPHIST_uint32; 45 | #else 46 | typedef signed int SOPHIST_int32; 47 | typedef unsigned int SOPHIST_uint32; 48 | #endif 49 | 50 | #ifndef SOPHIST_NO_64 51 | #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ 52 | || (defined(__alpha) && defined(__DECC)) 53 | 54 | typedef signed __int64 SOPHIST_int64; 55 | typedef unsigned __int64 SOPHIST_uint64; 56 | #define SOPHIST_has_64 1 57 | #define SOPHIST_int64_constant(x) (x##i64) 58 | #define SOPHIST_uint64_constant(x) (x##ui64) 59 | #define SOPHIST_printf_format64 "I64" 60 | 61 | #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) 62 | 63 | typedef signed long SOPHIST_int64; 64 | typedef unsigned long SOPHIST_uint64; 65 | 66 | #define SOPHIST_has_64 1 67 | #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) 68 | #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) 69 | #define SOPHIST_printf_format64 "l" 70 | 71 | #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ 72 | || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ 73 | || defined(sgi) || defined (__sgi) || defined(__sgi__) \ 74 | || defined(_CRAYC) 75 | 76 | typedef signed long long SOPHIST_int64; 77 | typedef unsigned long long SOPHIST_uint64; 78 | 79 | #define SOPHIST_has_64 1 80 | #define SOPHIST_int64_constant(x) (x##LL) 81 | #define SOPHIST_uint64_constant(x) (x##ULL) 82 | #define SOPHIST_printf_format64 "ll" 83 | #endif 84 | #endif 85 | 86 | #ifndef SOPHIST_has_64 87 | #define SOPHIST_has_64 0 88 | #endif 89 | 90 | SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); 91 | SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); 92 | SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); 93 | SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); 94 | 95 | #if SOPHIST_has_64 96 | SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); 97 | SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); 98 | #endif 99 | 100 | /* determine whether pointers are 64-bit */ 101 | 102 | #if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ 103 | || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ 104 | || defined(__64BIT__) \ 105 | || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ 106 | || defined(_ADDR64) || defined(_CRAYC) \ 107 | 108 | #define SOPHIST_pointer64 1 109 | 110 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); 111 | 112 | typedef SOPHIST_int64 SOPHIST_intptr; 113 | typedef SOPHIST_uint64 SOPHIST_uintptr; 114 | #else 115 | 116 | #define SOPHIST_pointer64 0 117 | 118 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); 119 | 120 | /* do we care about pointers that are only 16-bit? */ 121 | typedef SOPHIST_int32 SOPHIST_intptr; 122 | typedef SOPHIST_uint32 SOPHIST_uintptr; 123 | 124 | #endif 125 | 126 | SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); 127 | 128 | /* enumerate known little endian cases; fallback to big-endian */ 129 | 130 | #define SOPHIST_little_endian 1 131 | #define SOPHIST_big_endian 2 132 | 133 | #if defined(__386__) || defined(i386) || defined(__i386__) \ 134 | || defined(__X86) || defined(_M_IX86) \ 135 | || defined(_M_X64) || defined(__x86_64__) \ 136 | || defined(alpha) || defined(__alpha) || defined(__alpha__) \ 137 | || defined(_M_ALPHA) \ 138 | || defined(ARM) || defined(_ARM) || defined(__arm__) \ 139 | || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ 140 | || defined(_WIN32_WCE) || defined(__NT__) \ 141 | || defined(__MIPSEL__) 142 | #define SOPHIST_endian SOPHIST_little_endian 143 | #else 144 | #define SOPHIST_endian SOPHIST_big_endian 145 | #endif 146 | 147 | #endif /* __INCLUDE_SOPHIST_H__ */ 148 | -------------------------------------------------------------------------------- /src/test/efsw-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool STOP = false; 7 | 8 | void sigend(int signal) 9 | { 10 | std::cout << std::endl << "Bye bye" << std::endl; 11 | STOP = true; 12 | } 13 | 14 | /// Processes a file action 15 | class UpdateListener : public efsw::FileWatchListener 16 | { 17 | public: 18 | UpdateListener() {} 19 | 20 | std::string getActionName( efsw::Action action ) 21 | { 22 | switch ( action ) 23 | { 24 | case efsw::Actions::Add: return "Add"; 25 | case efsw::Actions::Modified: return "Modified"; 26 | case efsw::Actions::Delete: return "Delete"; 27 | case efsw::Actions::Moved: return "Moved"; 28 | default: return "Bad Action"; 29 | } 30 | } 31 | 32 | void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" ) 33 | { 34 | std::cout << "DIR (" << dir + ") FILE (" + ( oldFilename.empty() ? "" : "from file " + oldFilename + " to " ) + filename + ") has event " << getActionName( action ) << std::endl; 35 | } 36 | }; 37 | 38 | efsw::WatchID handleWathID( efsw::WatchID watchid ) 39 | { 40 | switch ( watchid ) 41 | { 42 | case efsw::Errors::FileNotFound: 43 | case efsw::Errors::FileRepeated: 44 | case efsw::Errors::FileOutOfScope: 45 | case efsw::Errors::Unspecified: 46 | { 47 | std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl; 48 | break; 49 | } 50 | default: 51 | { 52 | std::cout << "Added WatchID: " << watchid << std::endl; 53 | } 54 | } 55 | 56 | return watchid; 57 | } 58 | 59 | int main(int argc, char **argv) 60 | { 61 | signal( SIGABRT , sigend ); 62 | signal( SIGINT , sigend ); 63 | signal( SIGTERM , sigend ); 64 | 65 | std::cout << "Press ^C to exit demo" << std::endl; 66 | 67 | bool commonTest = true; 68 | bool useGeneric = false; 69 | std::string path; 70 | 71 | if ( argc >= 2 ) 72 | { 73 | path = std::string( argv[1] ); 74 | 75 | if ( efsw::FileSystem::isDirectory( path ) ) 76 | { 77 | commonTest = false; 78 | } 79 | 80 | if ( argc >= 3 ) 81 | { 82 | if ( std::string( argv[2] ) == "true" ) 83 | { 84 | useGeneric = true; 85 | } 86 | } 87 | } 88 | 89 | UpdateListener * ul = new UpdateListener(); 90 | 91 | /// create the file watcher object 92 | efsw::FileWatcher fileWatcher( useGeneric ); 93 | 94 | fileWatcher.followSymlinks( false ); 95 | fileWatcher.allowOutOfScopeLinks( false ); 96 | 97 | if ( commonTest ) 98 | { 99 | std::string CurPath( efsw::System::getProcessPath() ); 100 | 101 | std::cout << "CurPath: " << CurPath.c_str() << std::endl; 102 | 103 | /// add a watch to the system 104 | handleWathID( fileWatcher.addWatch( CurPath + "test" + efsw::FileSystem::getOSSlash(), ul, true ) ); 105 | 106 | /// starts watching 107 | fileWatcher.watch(); 108 | 109 | /// adds another watch after started watching... 110 | efsw::System::sleep( 100 ); 111 | 112 | efsw::WatchID watchID = handleWathID( fileWatcher.addWatch( CurPath + "test2", ul, true ) ); 113 | 114 | /// delete the watch 115 | if ( watchID > 0 ) 116 | { 117 | efsw::System::sleep( 1000 ); 118 | fileWatcher.removeWatch( watchID ); 119 | } 120 | } 121 | else 122 | { 123 | efsw::WatchID err; 124 | 125 | if ( ( err = fileWatcher.addWatch( path, ul, true ) ) > 0 ) 126 | { 127 | fileWatcher.watch(); 128 | 129 | std::cout << "Watching directory: " << path.c_str() << std::endl; 130 | 131 | if ( useGeneric ) 132 | { 133 | std::cout << "Using generic backend watcher" << std::endl; 134 | } 135 | } 136 | else 137 | { 138 | std::cout << "Error trying to watch directory: " << path.c_str() << std::endl; 139 | std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl; 140 | } 141 | } 142 | 143 | while( !STOP ) 144 | { 145 | efsw::System::sleep( 100 ); 146 | } 147 | 148 | return 0; 149 | } 150 | --------------------------------------------------------------------------------