#3425: Fixed suspend/resumeEvents pair in DirectoryWatcher

This commit is contained in:
Günter Obiltschnig
2021-11-05 15:05:01 +01:00
parent a032f771af
commit 58fd4fcd6a
3 changed files with 198 additions and 59 deletions

View File

@@ -61,7 +61,7 @@ public:
{ {
return _owner; return _owner;
} }
virtual void run() = 0; virtual void run() = 0;
virtual void stop() = 0; virtual void stop() = 0;
virtual bool supportsMoveEvents() const = 0; virtual bool supportsMoveEvents() const = 0;
@@ -73,21 +73,21 @@ protected:
size(0) size(0)
{ {
} }
ItemInfo(const ItemInfo& other): ItemInfo(const ItemInfo& other):
path(other.path), path(other.path),
size(other.size), size(other.size),
lastModified(other.lastModified) lastModified(other.lastModified)
{ {
} }
explicit ItemInfo(const File& f): explicit ItemInfo(const File& f):
path(f.path()), path(f.path()),
size(f.isFile() ? f.getSize() : 0), size(f.isFile() ? f.getSize() : 0),
lastModified(f.getLastModified()) lastModified(f.getLastModified())
{ {
} }
std::string path; std::string path;
File::FileSize size; File::FileSize size;
Timestamp lastModified; Timestamp lastModified;
@@ -104,7 +104,7 @@ protected:
++it; ++it;
} }
} }
void compare(ItemInfoMap& oldEntries, ItemInfoMap& newEntries) void compare(ItemInfoMap& oldEntries, ItemInfoMap& newEntries)
{ {
for (auto& np: newEntries) for (auto& np: newEntries)
@@ -145,7 +145,7 @@ private:
DirectoryWatcherStrategy(); DirectoryWatcherStrategy();
DirectoryWatcherStrategy(const DirectoryWatcherStrategy&); DirectoryWatcherStrategy(const DirectoryWatcherStrategy&);
DirectoryWatcherStrategy& operator = (const DirectoryWatcherStrategy&); DirectoryWatcherStrategy& operator = (const DirectoryWatcherStrategy&);
DirectoryWatcher& _owner; DirectoryWatcher& _owner;
}; };
@@ -163,21 +163,21 @@ public:
if (!_hStopped) if (!_hStopped)
throw SystemException("cannot create event"); throw SystemException("cannot create event");
} }
~WindowsDirectoryWatcherStrategy() ~WindowsDirectoryWatcherStrategy()
{ {
CloseHandle(_hStopped); CloseHandle(_hStopped);
} }
void run() void run()
{ {
ItemInfoMap entries; ItemInfoMap entries;
scan(entries); scan(entries);
DWORD filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME; DWORD filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
if (owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED) if (owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED)
filter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; filter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
std::string path(owner().directory().path()); std::string path(owner().directory().path());
std::wstring upath; std::wstring upath;
FileImpl::convertPath(path.c_str(), upath); FileImpl::convertPath(path.c_str(), upath);
@@ -195,7 +195,7 @@ public:
} }
return; return;
} }
bool stopped = false; bool stopped = false;
while (!stopped) while (!stopped)
{ {
@@ -228,21 +228,21 @@ public:
catch (Poco::Exception& exc) catch (Poco::Exception& exc)
{ {
owner().scanError(&owner(), exc); owner().scanError(&owner(), exc);
} }
} }
FindCloseChangeNotification(hChange); FindCloseChangeNotification(hChange);
} }
void stop() void stop()
{ {
SetEvent(_hStopped); SetEvent(_hStopped);
} }
bool supportsMoveEvents() const bool supportsMoveEvents() const
{ {
return false; return false;
} }
private: private:
HANDLE _hStopped; HANDLE _hStopped;
}; };
@@ -262,12 +262,12 @@ public:
_fd = inotify_init(); _fd = inotify_init();
if (_fd == -1) throw Poco::IOException("cannot initialize inotify", errno); if (_fd == -1) throw Poco::IOException("cannot initialize inotify", errno);
} }
~LinuxDirectoryWatcherStrategy() ~LinuxDirectoryWatcherStrategy()
{ {
close(_fd); close(_fd);
} }
void run() void run()
{ {
int mask = 0; int mask = 0;
@@ -293,7 +293,7 @@ public:
owner().scanError(&owner(), exc); owner().scanError(&owner(), exc);
} }
} }
Poco::Buffer<char> buffer(4096); Poco::Buffer<char> buffer(4096);
while (!_stopped) while (!_stopped)
{ {
@@ -314,16 +314,16 @@ public:
while (n > 0) while (n > 0)
{ {
struct inotify_event* pEvent = reinterpret_cast<struct inotify_event*>(buffer.begin() + i); struct inotify_event* pEvent = reinterpret_cast<struct inotify_event*>(buffer.begin() + i);
if (pEvent->len > 0) if (pEvent->len > 0)
{ {
if (!owner().eventsSuspended()) if (!owner().eventsSuspended())
{ {
Poco::Path p(owner().directory().path()); Poco::Path p(owner().directory().path());
p.makeDirectory(); p.makeDirectory();
p.setFileName(pEvent->name); p.setFileName(pEvent->name);
Poco::File f(p.toString()); Poco::File f(p.toString());
if ((pEvent->mask & IN_CREATE) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_ADDED)) if ((pEvent->mask & IN_CREATE) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_ADDED))
{ {
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_ADDED); DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_ADDED);
@@ -351,7 +351,7 @@ public:
} }
} }
} }
i += sizeof(inotify_event) + pEvent->len; i += sizeof(inotify_event) + pEvent->len;
n -= sizeof(inotify_event) + pEvent->len; n -= sizeof(inotify_event) + pEvent->len;
} }
@@ -359,12 +359,12 @@ public:
} }
} }
} }
void stop() void stop()
{ {
_stopped = true; _stopped = true;
} }
bool supportsMoveEvents() const bool supportsMoveEvents() const
{ {
return true; return true;
@@ -469,11 +469,11 @@ public:
DirectoryWatcherStrategy(owner) DirectoryWatcherStrategy(owner)
{ {
} }
~PollingDirectoryWatcherStrategy() ~PollingDirectoryWatcherStrategy()
{ {
} }
void run() void run()
{ {
ItemInfoMap entries; ItemInfoMap entries;
@@ -493,7 +493,7 @@ public:
} }
} }
} }
void stop() void stop()
{ {
_stopped.set(); _stopped.set();
@@ -520,7 +520,7 @@ DirectoryWatcher::DirectoryWatcher(const std::string& path, int eventMask, int s
init(); init();
} }
DirectoryWatcher::DirectoryWatcher(const Poco::File& directory, int eventMask, int scanInterval): DirectoryWatcher::DirectoryWatcher(const Poco::File& directory, int eventMask, int scanInterval):
_directory(directory), _directory(directory),
_eventMask(eventMask), _eventMask(eventMask),
@@ -543,16 +543,16 @@ DirectoryWatcher::~DirectoryWatcher()
} }
} }
void DirectoryWatcher::suspendEvents() void DirectoryWatcher::resumeEvents()
{ {
poco_assert (_eventsSuspended > 0); poco_assert (_eventsSuspended > 0);
_eventsSuspended--; _eventsSuspended--;
} }
void DirectoryWatcher::resumeEvents() void DirectoryWatcher::suspendEvents()
{ {
_eventsSuspended++; _eventsSuspended++;
} }
@@ -562,7 +562,7 @@ void DirectoryWatcher::init()
{ {
if (!_directory.exists()) if (!_directory.exists())
throw Poco::FileNotFoundException(_directory.path()); throw Poco::FileNotFoundException(_directory.path());
if (!_directory.isDirectory()) if (!_directory.isDirectory())
throw Poco::InvalidArgumentException("not a directory", _directory.path()); throw Poco::InvalidArgumentException("not a directory", _directory.path());
@@ -578,7 +578,7 @@ void DirectoryWatcher::init()
_thread.start(*this); _thread.start(*this);
} }
void DirectoryWatcher::run() void DirectoryWatcher::run()
{ {
_pStrategy->run(); _pStrategy->run();

View File

@@ -24,7 +24,7 @@
using Poco::DirectoryWatcher; using Poco::DirectoryWatcher;
DirectoryWatcherTest::DirectoryWatcherTest(const std::string& name): DirectoryWatcherTest::DirectoryWatcherTest(const std::string& name):
CppUnit::TestCase(name), CppUnit::TestCase(name),
_error(false) _error(false)
{ {
@@ -39,23 +39,23 @@ DirectoryWatcherTest::~DirectoryWatcherTest()
void DirectoryWatcherTest::testAdded() void DirectoryWatcherTest::testAdded()
{ {
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2); DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded); dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved); dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified); dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom); dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo); dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000); Poco::Thread::sleep(1000);
Poco::Path p(path()); Poco::Path p(path());
p.setFileName("test.txt"); p.setFileName("test.txt");
Poco::FileOutputStream fos(p.toString()); Poco::FileOutputStream fos(p.toString());
fos << "Hello, world!"; fos << "Hello, world!";
fos.close(); fos.close();
Poco::Thread::sleep(2000*dw.scanInterval()); Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1); assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemAdded"); assertTrue (_events[0].callback == "onItemAdded");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt"); assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
@@ -73,20 +73,20 @@ void DirectoryWatcherTest::testRemoved()
fos.close(); fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2); DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded); dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved); dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified); dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom); dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo); dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000); Poco::Thread::sleep(1000);
Poco::File f(p.toString()); Poco::File f(p.toString());
f.remove(); f.remove();
Poco::Thread::sleep(2000*dw.scanInterval()); Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1); assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemRemoved"); assertTrue (_events[0].callback == "onItemRemoved");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt"); assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
@@ -104,21 +104,21 @@ void DirectoryWatcherTest::testModified()
fos.close(); fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2); DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded); dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved); dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified); dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom); dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo); dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000); Poco::Thread::sleep(1000);
Poco::FileOutputStream fos2(p.toString(), std::ios::app); Poco::FileOutputStream fos2(p.toString(), std::ios::app);
fos2 << "Again!"; fos2 << "Again!";
fos2.close(); fos2.close();
Poco::Thread::sleep(2000*dw.scanInterval()); Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1); assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemModified"); assertTrue (_events[0].callback == "onItemModified");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt"); assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
@@ -136,22 +136,22 @@ void DirectoryWatcherTest::testMoved()
fos.close(); fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2); DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded); dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved); dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified); dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom); dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo); dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000); Poco::Thread::sleep(1000);
Poco::Path p2(path()); Poco::Path p2(path());
p2.setFileName("test2.txt"); p2.setFileName("test2.txt");
Poco::File f(p.toString()); Poco::File f(p.toString());
f.renameTo(p2.toString()); f.renameTo(p2.toString());
Poco::Thread::sleep(2000*dw.scanInterval()); Poco::Thread::sleep(2000*dw.scanInterval());
if (dw.supportsMoveEvents()) if (dw.supportsMoveEvents())
{ {
assertTrue (_events.size() >= 2); assertTrue (_events.size() >= 2);
@@ -188,11 +188,144 @@ void DirectoryWatcherTest::testMoved()
} }
void DirectoryWatcherTest::testSuspend()
{
Poco::Path p(path());
p.setFileName("test.txt");
Poco::FileOutputStream fos(p.toString());
fos << "Hello, world!";
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
dw.suspendEvents();
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
fos2 << "Again!";
fos2.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() == 0);
assertTrue (!_error);
}
void DirectoryWatcherTest::testResume()
{
Poco::Path p(path());
p.setFileName("test.txt");
Poco::FileOutputStream fos(p.toString());
fos << "Hello, world!";
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
dw.suspendEvents();
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
fos2 << "Again!";
fos2.close();
assertTrue (_events.size() == 0);
assertTrue (!_error);
dw.resumeEvents();
Poco::FileOutputStream fos3(p.toString(), std::ios::app);
fos3 << "Now it works!";
fos3.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemModified");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
assertTrue (_events[0].type == DirectoryWatcher::DW_ITEM_MODIFIED);
assertTrue (!_error);
}
void DirectoryWatcherTest::testSuspendMultipleTimes()
{
Poco::Path p(path());
p.setFileName("test.txt");
Poco::FileOutputStream fos(p.toString());
fos << "Hello, world!";
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
dw.suspendEvents();
dw.suspendEvents();
dw.suspendEvents();
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
fos2 << "Not notified!";
fos2.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() == 0);
assertTrue (!_error);
dw.resumeEvents();
Poco::FileOutputStream fos3(p.toString(), std::ios::app);
fos3 << "Still not notified!";
fos3.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() == 0);
assertTrue (!_error);
dw.resumeEvents();
dw.resumeEvents();
Poco::FileOutputStream fos4(p.toString(), std::ios::app);
fos4 << "Now it works!";
fos4.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemModified");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
assertTrue (_events[0].type == DirectoryWatcher::DW_ITEM_MODIFIED);
assertTrue (!_error);
}
void DirectoryWatcherTest::setUp() void DirectoryWatcherTest::setUp()
{ {
_error = false; _error = false;
_events.clear(); _events.clear();
try try
{ {
Poco::File d(path().toString()); Poco::File d(path().toString());
@@ -292,6 +425,9 @@ CppUnit::Test* DirectoryWatcherTest::suite()
CppUnit_addTest(pSuite, DirectoryWatcherTest, testRemoved); CppUnit_addTest(pSuite, DirectoryWatcherTest, testRemoved);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testModified); CppUnit_addTest(pSuite, DirectoryWatcherTest, testModified);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testMoved); CppUnit_addTest(pSuite, DirectoryWatcherTest, testMoved);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testSuspend);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testResume);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testSuspendMultipleTimes);
return pSuite; return pSuite;
} }

View File

@@ -35,12 +35,15 @@ public:
void testRemoved(); void testRemoved();
void testModified(); void testModified();
void testMoved(); void testMoved();
void testSuspend();
void testResume();
void testSuspendMultipleTimes();
void setUp(); void setUp();
void tearDown(); void tearDown();
static CppUnit::Test* suite(); static CppUnit::Test* suite();
protected: protected:
void onItemAdded(const Poco::DirectoryWatcher::DirectoryEvent& ev); void onItemAdded(const Poco::DirectoryWatcher::DirectoryEvent& ev);
void onItemRemoved(const Poco::DirectoryWatcher::DirectoryEvent& ev); void onItemRemoved(const Poco::DirectoryWatcher::DirectoryEvent& ev);
@@ -48,7 +51,7 @@ protected:
void onItemMovedFrom(const Poco::DirectoryWatcher::DirectoryEvent& ev); void onItemMovedFrom(const Poco::DirectoryWatcher::DirectoryEvent& ev);
void onItemMovedTo(const Poco::DirectoryWatcher::DirectoryEvent& ev); void onItemMovedTo(const Poco::DirectoryWatcher::DirectoryEvent& ev);
void onError(const Poco::Exception& exc); void onError(const Poco::Exception& exc);
Poco::Path path() const; Poco::Path path() const;
private: private: