From dadfb914c4b685a9ea93aae512d37f0e1f659c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Mar=C3=A9chal?= Date: Tue, 28 Jul 2020 17:03:03 -0400 Subject: [PATCH] linux: support simple ignore patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a first pass at implementing some mechanism to filter paths. Linux only. Some pattern examples: - `/absolute/path[/][*]` - `./path/parts[/][*]` - `**/path/parts[/][*]` - `*path/parts[/][*]` - `path/parts[/][*]` The general idea is to do simple string matching and convert patterns into path parts that can then be matched against a real path. For example, `**/foo` gets converted to `/foo/` and we will try to find this subtring in the following paths: - `/a/b/foo/c/` matches. - `/a/b/foobar/c/` does not match. In order for the pattern to match `/a/b/foobar/c/` we need to write `**/foo*` which will be converted to `/foo`. We now have: - `/a/b/foo/c` matches. - `/a/b/foobar/c` matches. This is because we are not required to find `/` right after `/foo`. Depending on if we use a `/` character or not, we can match path parts strictly or not. The rules for converting patterns are as follow: - If a pattern starts with `**/` we replace this prefix by `/` and will match the string anywhere. - If a pattern starts with `*` we do not prefix it with `/` and will match the string anywhere. - If a pattern starts with `./` we replace this prefix by the directory being watched by the current watcher and will match the string from root. - If a pattern starts with `/` we will match the string from root. - If a pattern starts with none of the above, we prefix with `/` and match the string anywhere. Then we apply trailing conversion logic: - If a pattern contains a `*` we remove this character plus everything that follows. - If a pattern ends with `/` we ensure there's only one trailing `/`. - If a pattern does not finish by either `*` or `/` we append `/`. The final filters are triaged between two vectors: `mRootFilters` and `mFilters` in order to match starting from the root or to match anywhere, respectively. Signed-off-by: Paul Maréchal --- binding.gyp | 5 +- docs/README.md | 1 + includes/NSFW.h | 2 + includes/NativeInterface.h | 4 +- includes/PathFilter.h | 23 +++++++++ includes/Queue.h | 3 ++ includes/linux/InotifyService.h | 3 +- includes/linux/InotifyTree.h | 8 ++- includes/osx/FSEventsService.h | 3 +- includes/win32/Controller.h | 3 +- index.d.ts | 2 + js/spec/index-spec.js | 72 ++++++++++++++++++++++++++ js/src/index.js | 8 ++- src/NSFW.cpp | 23 ++++++++- src/NativeInterface.cpp | 4 +- src/PathFilter.cpp | 91 +++++++++++++++++++++++++++++++++ src/Queue.cpp | 25 +++++++++ src/linux/InotifyService.cpp | 4 +- src/linux/InotifyTree.cpp | 14 ++++- src/osx/FSEventsService.cpp | 2 +- src/win32/Controller.cpp | 2 +- 21 files changed, 283 insertions(+), 19 deletions(-) create mode 100644 includes/PathFilter.h create mode 100644 src/PathFilter.cpp diff --git a/binding.gyp b/binding.gyp index 33eedc3d..eeb8bde8 100644 --- a/binding.gyp +++ b/binding.gyp @@ -5,7 +5,8 @@ "sources": [ "src/NSFW.cpp", "src/Queue.cpp", - "src/NativeInterface.cpp" + "src/NativeInterface.cpp", + "src/PathFilter.cpp" ], "include_dirs": [ "includes", @@ -102,7 +103,7 @@ ], "libraries": [ "-L/usr/local/lib", - "-linotify" + "-linotify" ] }], ] diff --git a/docs/README.md b/docs/README.md index 19736dea..093ba5de 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,6 +10,7 @@ const nsfw = require('nsfw'); - **options** - **debounceMS**: time in milliseconds to debounce the event callback - **errorCallback**: callback to fire in the case of errors + - **ignoreGlobs**: glob-like patterns to ignore paths while watching Returns a Promise that resolves to the created NSFW Object. diff --git a/includes/NSFW.h b/includes/NSFW.h index 5cd7d373..60f2b32f 100644 --- a/includes/NSFW.h +++ b/includes/NSFW.h @@ -10,6 +10,7 @@ #include "./Queue.h" #include "./NativeInterface.h" +#include "./PathFilter.h" class NSFW : public Napi::ObjectWrap { private: @@ -23,6 +24,7 @@ class NSFW : public Napi::ObjectWrap { std::unique_ptr mInterface; std::mutex mInterfaceLock; std::shared_ptr mQueue; + std::shared_ptr mPathFilter; std::string mPath; std::thread mPollThread; std::atomic mRunning; diff --git a/includes/NativeInterface.h b/includes/NativeInterface.h index 35d64ada..2940515e 100644 --- a/includes/NativeInterface.h +++ b/includes/NativeInterface.h @@ -13,11 +13,12 @@ using NativeImplementation = InotifyService; #endif #include "Queue.h" +#include "PathFilter.h" #include class NativeInterface { public: - NativeInterface(const std::string &path, std::shared_ptr queue); + NativeInterface(const std::string &path, std::shared_ptr queue, std::shared_ptr pathFilter); ~NativeInterface(); std::string getError(); @@ -26,6 +27,7 @@ class NativeInterface { private: std::unique_ptr mNativeInterface; + std::shared_ptr mPathFilter; }; #endif diff --git a/includes/PathFilter.h b/includes/PathFilter.h new file mode 100644 index 00000000..ea555390 --- /dev/null +++ b/includes/PathFilter.h @@ -0,0 +1,23 @@ +#ifndef FILTER_H +#define FILTER_H + +#include +#include + +class PathFilter { + private: + std::string mRoot; + std::vector mRootFilters; + std::vector mFilters; + + public: + PathFilter(const std::string &root); + ~PathFilter(); + + /** register a glob filter */ + void addIgnoreGlob(const std::string &glob); + /** return true if path should be ignored, false otherwise */ + bool isIgnored(const std::string &path); +}; + +#endif diff --git a/includes/Queue.h b/includes/Queue.h index 8693559a..02a7f291 100644 --- a/includes/Queue.h +++ b/includes/Queue.h @@ -1,6 +1,8 @@ #ifndef NSFW_QUEUE_H #define NSFW_QUEUE_H +#include "./PathFilter.h" + #include #include #include @@ -40,6 +42,7 @@ class EventQueue { std::size_t count(); std::unique_ptr dequeue(); std::unique_ptr>> dequeueAll(); + std::unique_ptr>> dequeueAll(const std::shared_ptr &pathFilter); void enqueue( const EventType type, const std::string &fromDirectory, diff --git a/includes/linux/InotifyService.h b/includes/linux/InotifyService.h index e226a787..7faa7f73 100644 --- a/includes/linux/InotifyService.h +++ b/includes/linux/InotifyService.h @@ -4,6 +4,7 @@ #include "InotifyEventLoop.h" #include "InotifyTree.h" #include "../Queue.h" +#include "../PathFilter.h" #include #include @@ -12,7 +13,7 @@ class InotifyTree; class InotifyService { public: - InotifyService(std::shared_ptr queue, std::string path); + InotifyService(std::shared_ptr queue, std::string path, std::shared_ptr pathFilter); std::string getError(); bool hasErrored(); diff --git a/includes/linux/InotifyTree.h b/includes/linux/InotifyTree.h index ef23d3cc..b6518b5e 100644 --- a/includes/linux/InotifyTree.h +++ b/includes/linux/InotifyTree.h @@ -9,11 +9,14 @@ #include #include #include +#include #include +#include "../PathFilter.h" + class InotifyTree { public: - InotifyTree(int inotifyInstance, std::string path); + InotifyTree(int inotifyInstance, std::string path, std::shared_ptr pathFilter); void addDirectory(int wd, std::string name); std::string getError(); @@ -31,6 +34,7 @@ class InotifyTree { InotifyNode( InotifyTree *tree, int inotifyInstance, + std::shared_ptr pathFilter, InotifyNode *parent, std::string directory, std::string name, @@ -68,6 +72,7 @@ class InotifyTree { std::string mFullPath; ino_t mInodeNumber; const int mInotifyInstance; + std::shared_ptr mPathFilter; std::string mName; InotifyNode *mParent; InotifyTree *mTree; @@ -83,6 +88,7 @@ class InotifyTree { std::string mError; const int mInotifyInstance; + std::shared_ptr mPathFilter; std::map *mInotifyNodeByWatchDescriptor; std::unordered_set inodes; InotifyNode *mRoot; diff --git a/includes/osx/FSEventsService.h b/includes/osx/FSEventsService.h index f2008b87..10069912 100644 --- a/includes/osx/FSEventsService.h +++ b/includes/osx/FSEventsService.h @@ -3,6 +3,7 @@ #include "RunLoop.h" #include "../Queue.h" +#include "../PathFilter.h" #include #include @@ -24,7 +25,7 @@ class RunLoop; class FSEventsService { public: - FSEventsService(std::shared_ptr queue, std::string path); + FSEventsService(std::shared_ptr queue, std::string path, std::shared_ptr pathFilter); friend void FSEventsServiceCallback( ConstFSEventStreamRef streamRef, diff --git a/includes/win32/Controller.h b/includes/win32/Controller.h index 61578fef..a1062d9a 100644 --- a/includes/win32/Controller.h +++ b/includes/win32/Controller.h @@ -4,12 +4,13 @@ #include #include #include "Watcher.h" +#include "../PathFilter.h" class EventQueue; class Controller { public: - Controller(std::shared_ptr queue, const std::string &path); + Controller(std::shared_ptr queue, const std::string &path, std::shared_ptr pathFilter); std::string getError(); bool hasErrored(); diff --git a/index.d.ts b/index.d.ts index da412a30..9930ffa2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -62,5 +62,7 @@ declare module 'nsfw' { debounceMS?: number; /** callback to fire in the case of errors */ errorCallback: (err: any) => void + /** glob-like patterns to ignore paths while watching */ + ignoreGlobs: string[]; } } diff --git a/js/spec/index-spec.js b/js/spec/index-spec.js index 6db83b53..126a2e36 100644 --- a/js/spec/index-spec.js +++ b/js/spec/index-spec.js @@ -534,6 +534,78 @@ describe('Node Sentinel File Watcher', function() { watch = null; } }); + + if (process.platform === 'linux') { + it('can cut part of the watch tree (linux)', async function () { + // Creates `${name}/test.file` + async function mkdir(name) { + const folder = path.resolve(workDir, name); + await fse.mkdir(folder, { recursive: true }); + await fse.writeFile(path.resolve(folder, 'test.file'), name); + } + // `workDir/aaa` + const aaa = path.resolve(workDir, 'aaa'); // ignored + const aaab = path.resolve(workDir, 'aaab'); // not ignored + // `workDir/bb*` + const baa = path.resolve(workDir, 'baa'); // not ignored + const bbb = path.resolve(workDir, 'bbb'); // ignored + const bbc = path.resolve(workDir, 'bbc'); // ignored + // `*zz` + const czz = path.resolve(workDir, 'czz'); // ignored + const dzza = path.resolve(workDir, 'dzza'); // not ignored + // `**/eee` + const eee = path.resolve(workDir, 'eee'); // ignored + const feee = path.resolve(workDir, 'feee'); // not ignored + // `**/gaa///` + const gaa = path.resolve(workDir, 'gaa'); // ignored + const gaab = path.resolve(workDir, 'gaab'); // not ignored + const folders = [aaa, aaab, baa, bbb, bbc, czz, dzza, eee, feee, gaa, gaab]; + await Promise.all(folders.map(mkdir)); + const expectIgnored = new Set([bbb, bbc, czz, eee, gaa]); + const expectNotIgnored = new Set([aaab, baa, dzza, feee, gaab]); + const expectWorkDirEvents = new Set(Array.from(expectNotIgnored, folder => path.basename(folder))); + const actualIgnored = new Set(); // should be empty + const actualNotIgnored = new Set(); // should be == expectNotIgnored + const actualWorkDirEvents = new Set(); // should be == expectWorkDirEvents + function findEvent(element) { + if (element.action === nsfw.actions.DELETED) + { + if (element.directory === workDir && expectWorkDirEvents.has(element.file)) { + actualWorkDirEvents.add(element.file); // Ok. + } else if (element.file === 'test.file') { + if (expectIgnored.has(element.directory)) { + actualIgnored.add(element.directory); // This should fail the test. + } else if (expectNotIgnored.has(element.directory)) { + actualNotIgnored.add(element.directory); // Ok. + } + } + } + } + let watch = await nsfw( + workDir, + events => events.forEach(findEvent), + { debounceMS: DEBOUNCE, ignoreGlobs: [ + workDir + '/aaa', + workDir + '/bb*', + '*zz', + '**/eee', + '**/gaa///', + ] } + ); + try { + await watch.start(); + await sleep(TIMEOUT_PER_STEP); + await Promise.all(folders.map(folder => fse.remove(folder))); + await sleep(TIMEOUT_PER_STEP); + } finally { + await watch.stop(); + watch = null; + } + assert.deepStrictEqual(new Set(), actualIgnored, 'some folders were not ignored'); + assert.deepStrictEqual(expectNotIgnored, actualNotIgnored, 'some folders got ignored'); + assert.deepStrictEqual(expectWorkDirEvents, actualWorkDirEvents); + }); + } }); describe('Pausing', function () { diff --git a/js/src/index.js b/js/src/index.js index e62d7d9d..92ad4e1a 100644 --- a/js/src/index.js +++ b/js/src/index.js @@ -51,7 +51,11 @@ function NSFWFilePoller(watchPath, eventCallback, debounceMS) { } -const buildNSFW = async (watchPath, eventCallback, { debounceMS = 500, errorCallback: _errorCallback } = {}) => { +const buildNSFW = async (watchPath, eventCallback, { + debounceMS = 500, + errorCallback: _errorCallback, + ignoreGlobs +} = {}) => { if (Number.isInteger(debounceMS)) { if (debounceMS < 1) { throw new Error('Minimum debounce is 1ms.'); @@ -74,7 +78,7 @@ const buildNSFW = async (watchPath, eventCallback, { debounceMS = 500, errorCall } if (stats.isDirectory()) { - return new NSFW(watchPath, eventCallback, { debounceMS, errorCallback }); + return new NSFW(watchPath, eventCallback, { debounceMS, errorCallback, ignoreGlobs }); } else if (stats.isFile()) { return new NSFWFilePoller(watchPath, eventCallback, debounceMS); } else { diff --git a/src/NSFW.cpp b/src/NSFW.cpp index aa95f24b..7d20d892 100644 --- a/src/NSFW.cpp +++ b/src/NSFW.cpp @@ -1,4 +1,5 @@ #include "../includes/NSFW.h" +#include Napi::FunctionReference NSFW::constructor; std::size_t NSFW::instanceCount = 0; @@ -9,6 +10,7 @@ NSFW::NSFW(const Napi::CallbackInfo &info): mDebounceMS(0), mInterface(nullptr), mQueue(std::make_shared()), + mPathFilter(nullptr), mPath(""), mRunning(false) { @@ -22,6 +24,7 @@ NSFW::NSFW(const Napi::CallbackInfo &info): } mPath = info[0].ToString(); + mPathFilter = std::make_shared(mPath); if (info.Length() < 2 || !info[1].IsFunction()) { throw Napi::TypeError::New(env, "Must pass an event callback as the second parameter to NSFW."); @@ -70,6 +73,22 @@ NSFW::NSFW(const Napi::CallbackInfo &info): 0, 1 ); + + Napi::Value maybeIgnoreGlobs = options["ignoreGlobs"]; + if (options.Has("ignoreGlobs") && !maybeIgnoreGlobs.IsUndefined()) { + if (!maybeIgnoreGlobs.IsArray()) { + throw Napi::TypeError::New(env, "options.ignoreGlobs must be a string array."); + } + Napi::Array array(maybeIgnoreGlobs.As()); + uint32_t length(array.Length()); + for (uint32_t i(0); i < length; ++i) { + Napi::Value item(array.Get(i)); + if (!item.IsString()) { + throw Napi::TypeError::New(env, "options.ignoreGlobs must be a string array."); + } + mPathFilter->addIgnoreGlob(item.ToString().Utf8Value()); + } + } } } @@ -105,7 +124,7 @@ void NSFW::StartWorker::Execute() { } mNSFW->mQueue->clear(); - mNSFW->mInterface.reset(new NativeInterface(mNSFW->mPath, mNSFW->mQueue)); + mNSFW->mInterface.reset(new NativeInterface(mNSFW->mPath, mNSFW->mQueue, mNSFW->mPathFilter)); if (mNSFW->mInterface->isWatching()) { mStatus = STARTED; @@ -276,7 +295,7 @@ void NSFW::pollForEvents() { } if (mQueue->count() != 0) { - auto events = mQueue->dequeueAll(); + auto events = mQueue->dequeueAll(mPathFilter); if (events != nullptr) { sleepDuration = mDebounceMS; auto callback = [](Napi::Env env, Napi::Function jsCallback, std::vector> *eventsRaw) { diff --git a/src/NativeInterface.cpp b/src/NativeInterface.cpp index 3af66e8e..5884cb3b 100644 --- a/src/NativeInterface.cpp +++ b/src/NativeInterface.cpp @@ -1,7 +1,7 @@ #include "../includes/NativeInterface.h" -NativeInterface::NativeInterface(const std::string &path, std::shared_ptr queue) { - mNativeInterface.reset(new NativeImplementation(queue, path)); +NativeInterface::NativeInterface(const std::string &path, std::shared_ptr queue, std::shared_ptr pathFilter) { + mNativeInterface.reset(new NativeImplementation(queue, path, pathFilter)); } NativeInterface::~NativeInterface() { diff --git a/src/PathFilter.cpp b/src/PathFilter.cpp new file mode 100644 index 00000000..2b617dcb --- /dev/null +++ b/src/PathFilter.cpp @@ -0,0 +1,91 @@ +#include "../includes/PathFilter.h" + +#pragma unmanaged + +static const std::string doubleStarPrefix("**/"); + +static bool startsWith(const std::string &prefix, const std::string &str) { + return str.length() >= prefix.length() && std::equal(prefix.begin(), prefix.end(), str.begin()); +} + +static const std::string ensureTrailingSeparator(const std::string &path) { + if (path.back() == '/') { + return path; + } else { + return path + '/'; + } +} + +static const std::string normalizeTail(const std::string &path) { + int length = path.length(); + if (length == 0) { + return path; + } + // Find the first '*' and remove trailing elements + auto istar = path.find('*'); + if (istar != std::string::npos) { + return path.substr(0, istar); + } + // Path should end with exactly one '/' or none at all. + if (path[length - 1] == '/') { + if (length == 1) { + return path; + } + else { + int i = length - 2; + while (i >= 0 && path[--i] == '/'); + return path.substr(0, i + 2); + } + } + return path + '/'; +} + +static void pushUnique(std::vector &vector, const std::string &element) { + for (auto e : vector) { + if (e == element) { + return; + } + } + vector.push_back(element); +} + +PathFilter::PathFilter(const std::string &root) : mRoot(ensureTrailingSeparator(root)) {} + +PathFilter::~PathFilter() {} + +void PathFilter::addIgnoreGlob(const std::string &glob) { + // `/path/parts[/][*]` + if (startsWith("/", glob)) { + pushUnique(mRootFilters, normalizeTail(glob)); + } + // `./path/parts[/][*]` + else if (startsWith("./", glob)) { + pushUnique(mRootFilters, normalizeTail(mRoot + glob.substr(2))); + } + // `**/path/parts[/][*]` + else if (startsWith(doubleStarPrefix, glob)) { + pushUnique(mFilters, '/' + normalizeTail(glob.substr(doubleStarPrefix.length()))); + } + // `*path/parts[/][*]` + else if (startsWith("*", glob)) { + pushUnique(mFilters, normalizeTail(glob.substr(1))); + } + // `path/parts[/][*]` + else { + pushUnique(mFilters, '/' + normalizeTail(glob)); + } +} + +bool PathFilter::isIgnored(const std::string &path) { + for (std::string filter : mRootFilters) { + if (startsWith(filter, path)) { + return true; + } + } + for (std::string filter : mFilters) { + if (path.find(filter) != std::string::npos) { + return true; + } + } + return false; +} diff --git a/src/Queue.cpp b/src/Queue.cpp index 3fe62174..06ae7e5e 100644 --- a/src/Queue.cpp +++ b/src/Queue.cpp @@ -1,5 +1,6 @@ #include "../includes/Queue.h" #include +#include #pragma unmanaged @@ -43,6 +44,30 @@ std::unique_ptr>> EventQueue::dequeueAll() { return events; } +std::unique_ptr>> EventQueue::dequeueAll(const std::shared_ptr &pathFilter) { + std::lock_guard lock(mutex); + if (queue.empty()) { + return nullptr; + } + + const auto queueSize = queue.size(); + std::unique_ptr>> events(new std::vector>); + for (size_t i = 0; i < queueSize; ++i) { + auto &front = queue.front(); + if ( + pathFilter->isIgnored(front->fromDirectory + '/' + front->fromFile) || + (front->type == EventType::RENAMED && pathFilter->isIgnored(front->toDirectory + "/" + front->toFile)) + ) { + queue.pop_front(); + continue; + } + events->emplace_back(std::move(front)); + queue.pop_front(); + } + + return events; +} + void EventQueue::enqueue( const EventType type, const std::string &fromDirectory, diff --git a/src/linux/InotifyService.cpp b/src/linux/InotifyService.cpp index ff6f989f..27590c9f 100644 --- a/src/linux/InotifyService.cpp +++ b/src/linux/InotifyService.cpp @@ -1,6 +1,6 @@ #include "../../includes/linux/InotifyService.h" -InotifyService::InotifyService(std::shared_ptr queue, std::string path): +InotifyService::InotifyService(std::shared_ptr queue, std::string path, std::shared_ptr pathFilter): mEventLoop(NULL), mQueue(queue), mTree(NULL) { @@ -10,7 +10,7 @@ InotifyService::InotifyService(std::shared_ptr queue, std::string pa return; } - mTree = new InotifyTree(mInotifyInstance, path); + mTree = new InotifyTree(mInotifyInstance, path, pathFilter); if (!mTree->isRootAlive()) { delete mTree; mTree = NULL; diff --git a/src/linux/InotifyTree.cpp b/src/linux/InotifyTree.cpp index 8a940ff0..d233553e 100644 --- a/src/linux/InotifyTree.cpp +++ b/src/linux/InotifyTree.cpp @@ -2,9 +2,10 @@ /** * InotifyTree --------------------------------------------------------------------------------------------------------- */ -InotifyTree::InotifyTree(int inotifyInstance, std::string path): +InotifyTree::InotifyTree(int inotifyInstance, std::string path, std::shared_ptr pathFilter): mError(""), - mInotifyInstance(inotifyInstance) { + mInotifyInstance(inotifyInstance), + mPathFilter(pathFilter) { mInotifyNodeByWatchDescriptor = new std::map; std::string directory; @@ -28,6 +29,7 @@ InotifyTree::InotifyTree(int inotifyInstance, std::string path): mRoot = new InotifyNode( this, mInotifyInstance, + mPathFilter, NULL, directory, watchName, @@ -159,6 +161,7 @@ InotifyTree::~InotifyTree() { InotifyTree::InotifyNode::InotifyNode( InotifyTree *tree, int inotifyInstance, + std::shared_ptr pathFilter, InotifyNode *parent, std::string directory, std::string name, @@ -167,6 +170,7 @@ InotifyTree::InotifyNode::InotifyNode( mDirectory(directory), mInodeNumber(inodeNumber), mInotifyInstance(inotifyInstance), + mPathFilter(pathFilter), mName(name), mParent(parent), mTree(tree) { @@ -201,6 +205,10 @@ InotifyTree::InotifyNode::InotifyNode( std::string filePath = createFullPath(mFullPath, fileName); + if (mPathFilter->isIgnored(filePath)) { + continue; + } + struct stat file; if ( @@ -214,6 +222,7 @@ InotifyTree::InotifyNode::InotifyNode( InotifyNode *child = new InotifyNode( mTree, mInotifyInstance, + mPathFilter, this, mFullPath, fileName, @@ -256,6 +265,7 @@ void InotifyTree::InotifyNode::addChild(std::string name) { InotifyNode *child = new InotifyNode( mTree, mInotifyInstance, + mPathFilter, this, mFullPath, name, diff --git a/src/osx/FSEventsService.cpp b/src/osx/FSEventsService.cpp index ea7098e9..564590f8 100644 --- a/src/osx/FSEventsService.cpp +++ b/src/osx/FSEventsService.cpp @@ -1,7 +1,7 @@ #include "../../includes/osx/FSEventsService.h" #include -FSEventsService::FSEventsService(std::shared_ptr queue, std::string path): +FSEventsService::FSEventsService(std::shared_ptr queue, std::string path, std::shared_ptr pathFilter): mPath(path), mQueue(queue) { mRunLoop = new RunLoop(this, path); diff --git a/src/win32/Controller.cpp b/src/win32/Controller.cpp index 98e5066a..3214fc5d 100644 --- a/src/win32/Controller.cpp +++ b/src/win32/Controller.cpp @@ -54,7 +54,7 @@ HANDLE Controller::openDirectory(const std::wstring &path) { ); } -Controller::Controller(std::shared_ptr queue, const std::string &path) +Controller::Controller(std::shared_ptr queue, const std::string &path, std::shared_ptr pathFilter) : mDirectoryHandle(INVALID_HANDLE_VALUE) { auto widePath = convertMultiByteToWideChar(path);