M .gitignore => .gitignore +2 -0
@@ 60,3 60,5 @@ update/
# often created by the visual studio code
/null.d
+
+test/test_env<
\ No newline at end of file
M Target_RT1051.cmake => Target_RT1051.cmake +1 -0
@@ 95,6 95,7 @@ set(BOARD_DIR_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/board/rt1051/newlib/include
${CMAKE_SOURCE_DIR}/module-utils/CrashDebug/CrashCatcher/include
${CMAKE_SOURCE_DIR}/module-utils/CrashDebug/CrashCatcher/Core/src
+ ${CMAKE_SOURCE_DIR}/module-vfs/include/internal
)
set(TARGET_LIBRARIES
M module-services/service-desktop/CMakeLists.txt => module-services/service-desktop/CMakeLists.txt +1 -0
@@ 60,6 60,7 @@ target_link_libraries(${PROJECT_NAME}
module-cellular
crc32
microtar
+ utils-bootconfig
)
if (${ENABLE_TESTS})
M module-services/service-fileindexer/CMakeLists.txt => module-services/service-fileindexer/CMakeLists.txt +0 -1
@@ 18,7 18,6 @@ target_link_options(${PROJECT_NAME} PUBLIC ${TARGET_LINK_OPTIONS})
target_sources( ${PROJECT_NAME}
PRIVATE
"ServiceFileIndexer.cpp"
- "messages/FileChangeMessage.cpp"
"StartupIndexer.cpp"
"notesIndexer.cpp"
)
M module-services/service-fileindexer/ServiceFileIndexer.cpp => module-services/service-fileindexer/ServiceFileIndexer.cpp +40 -14
@@ 1,13 1,23 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <log/log.hpp>
+#include <purefs/filesystem_paths.hpp>
+#include <purefs/fs/inotify.hpp>
#include "ServiceFileIndexer.hpp"
-#include "notesIndexer.hpp"
-#include "messages/FileChangeMessage.hpp"
-#include "Constants.hpp"
#include <fileref.h>
#include <tag.h>
+#include "notesIndexer.hpp"
+#include "Constants.hpp"
+#include <purefs/fs/inotify_message.hpp>
+
+namespace
+{
+ inline auto getMusicPath()
+ {
+ return purefs::createPath(purefs::dir::getUserDiskPath(), "music").string();
+ }
+} // namespace
namespace service
{
@@ 20,6 30,15 @@ namespace service
// When receive notification handler
sys::MessagePointer ServiceFileIndexer::DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp)
{
+ auto inotify = dynamic_cast<purefs::fs::message::inotify *>(msg);
+ if (inotify) {
+ LOG_ERROR("Inotify event %s %08x", inotify->name.c_str(), int(inotify->flags));
+ }
+ else {
+ LOG_ERROR("Not a inotify message");
+ }
+
+#if 0
auto fcm = dynamic_cast<msg::FileChangeMessage *>(msg);
if (fcm) {
switch (fcm->event()) {
@@ 47,6 66,7 @@ namespace service
}
return std::make_shared<sys::ResponseMessage>();
}
+#endif
return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Unresolved);
}
@@ 54,23 74,29 @@ namespace service
sys::ReturnCodes ServiceFileIndexer::InitHandler()
{
/*
- vfs.registerNotificationHandler(
- [_this = shared_from_this()](std::string_view new_path, vfs::FsEvent event, std::string_view old_path) {
- namespace fs = std::filesystem;
- const auto new_ext = fs::path(new_path).extension().string();
- auto msg = std::make_shared<msg::FileChangeMessage>(new_path, event, old_path);
- _this->bus.sendUnicast(msg, std::string(service::name::file_indexer));
- });
mStartupIndexer.start(shared_from_this(), service::name::file_indexer);
*/
+
+ mfsNotifier = purefs::fs::inotify_create(shared_from_this());
+ if (!mfsNotifier) {
+ LOG_ERROR("Unable to create inotify object");
+ return sys::ReturnCodes::Failure;
+ }
+ const int err = mfsNotifier->add_watch(getMusicPath(), purefs::fs::inotify_flags::close_write);
+ if (err) {
+ LOG_ERROR("Unable to create inotify watch errno: %i", err);
+ return sys::ReturnCodes::Failure;
+ }
return sys::ReturnCodes::Success;
}
sys::ReturnCodes ServiceFileIndexer::DeinitHandler()
{
- /*
- vfs.registerNotificationHandler(nullptr);
- */
+ const int err = mfsNotifier->rm_watch(getMusicPath());
+ if (err) {
+ LOG_ERROR("Unable to remove watch errno: %i", err);
+ return sys::ReturnCodes::Failure;
+ }
return sys::ReturnCodes::Success;
}
M module-services/service-fileindexer/ServiceFileIndexer.hpp => module-services/service-fileindexer/ServiceFileIndexer.hpp +8 -0
@@ 8,6 8,11 @@
#include "Constants.hpp"
#include "StartupIndexer.hpp"
+namespace purefs::fs
+{
+ class inotify;
+}
+
namespace service
{
@@ 28,6 33,9 @@ namespace service
auto onRenameFile(std::string_view oldPath, std::string_view newPath) -> void;
auto onAudioContentChanged(std::string_view path) -> void;
auto onTextContentChanged(std::string_view path) -> void;
+
+ private:
+ std::shared_ptr<purefs::fs::inotify> mfsNotifier;
detail::StartupIndexer mStartupIndexer;
};
M module-services/service-fileindexer/StartupIndexer.cpp => module-services/service-fileindexer/StartupIndexer.cpp +1 -3
@@ 2,10 2,8 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "StartupIndexer.hpp"
-#include "messages/FileChangeMessage.hpp"
#include <Timers/TimerFactory.hpp>
#include <filesystem>
-//#include <ff_stdio_listdir_recursive.h>
#include <purefs/filesystem_paths.hpp>
#include "Constants.hpp"
@@ 63,7 61,7 @@ namespace service::detail
mIdxTimer = sys::TimerFactory::createPeriodicTimer(
svc.get(), "file_indexing", std::chrono::milliseconds{timer_indexing_time}, [this, svc](sys::Timer &) {
if (!mMsgs.empty()) {
- svc->bus.sendUnicast(mMsgs.front(), std::string(service::name::file_indexer));
+ // svc->bus.sendUnicast(mMsgs.front(), std::string(service::name::file_indexer));
mMsgs.pop_front();
}
else {
D module-services/service-fileindexer/messages/FileChangeMessage.cpp => module-services/service-fileindexer/messages/FileChangeMessage.cpp +0 -11
@@ 1,11 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "FileChangeMessage.hpp"
-
-namespace service::msg
-{
- FileChangeMessage::FileChangeMessage(std::string_view new_path, evt_t ev, std::string_view old_path)
- : DataMessage(MessageType::FileContentModified), mNewPath(new_path), mEvent(ev), mOldPath(old_path)
- {}
-} // namespace service::msg
D module-services/service-fileindexer/messages/FileChangeMessage.hpp => module-services/service-fileindexer/messages/FileChangeMessage.hpp +0 -36
@@ 1,36 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-
-#include <Service/Message.hpp>
-#include <vfsNotifier.hpp>
-namespace service::msg
-{
- class FileChangeMessage final : public sys::DataMessage
- {
- public:
- using evt_t = vfsn::utility::vfsNotifier::FsEvent;
- FileChangeMessage(std::string_view new_path, evt_t ev, std::string_view old_path);
- virtual ~FileChangeMessage() = default;
- FileChangeMessage(FileChangeMessage &) = delete;
- FileChangeMessage &operator=(FileChangeMessage &) = delete;
- [[nodiscard]] auto newPath() const noexcept
- {
- return mNewPath;
- }
- [[nodiscard]] auto oldPath() const noexcept
- {
- return mOldPath;
- }
- [[nodiscard]] auto event() const noexcept
- {
- return mEvent;
- }
-
- private:
- const std::string mNewPath;
- const evt_t mEvent;
- const std::string mOldPath;
- };
-} // namespace service::msg
M module-vfs/CMakeLists.txt => module-vfs/CMakeLists.txt +22 -20
@@ 16,23 16,28 @@ set(FF_FAT_SOURCES
${FF_FAT_SOURCES_THIRDPARTY}
${CMAKE_CURRENT_SOURCE_DIR}/drivers/src/thirdparty/fatfs/ffsystem.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/src/thirdparty/fatfs/ff_glue.cpp
+)
+set(FF_LFS_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/drivers/src/thirdparty/littlefs/lfs_glue.cpp
)
set(SOURCES
- ${FF_FAT_SOURCES}
- src/purefs/filesystem_paths.cpp
- src/purefs/blkdev/disk_manager.cpp
- src/purefs/blkdev/disk.cpp
- src/purefs/blkdev/partition_parser.cpp
- src/purefs/blkdev/disk_handle.cpp
- src/purefs/fs/filesystem.cpp
- src/purefs/fs/filesystem_operations.cpp
- src/purefs/fs/filesystem_syscalls.cpp
- src/purefs/fs/filesystem_cwd.cpp
- src/purefs/vfs_subsystem.cpp
- drivers/src/purefs/fs/filesystem_vfat.cpp
- drivers/src/purefs/fs/filesystem_littlefs.cpp
+ ${FF_FAT_SOURCES}
+ ${FF_LFS_SOURCES}
+ src/purefs/filesystem_paths.cpp
+ src/purefs/blkdev/disk_manager.cpp
+ src/purefs/blkdev/disk.cpp
+ src/purefs/blkdev/partition_parser.cpp
+ src/purefs/blkdev/disk_handle.cpp
+ src/purefs/fs/filesystem.cpp
+ src/purefs/fs/filesystem_operations.cpp
+ src/purefs/fs/filesystem_syscalls.cpp
+ src/purefs/fs/filesystem_cwd.cpp
+ src/purefs/vfs_subsystem.cpp
+ src/purefs/fs/notifier.cpp
+ src/purefs/fs/fsnotify.cpp
+ drivers/src/purefs/fs/filesystem_vfat.cpp
+ drivers/src/purefs/fs/filesystem_littlefs.cpp
)
@@ 64,23 69,20 @@ target_compile_definitions(${PROJECT_NAME}
target_include_directories(${PROJECT_NAME}
PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/include/user/deprecated
- ${CMAKE_CURRENT_SOURCE_DIR}/include/user/
- ${CMAKE_CURRENT_SOURCE_DIR}/include/internal/
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/user
${CMAKE_CURRENT_SOURCE_DIR}/drivers/include
)
target_include_directories(${PROJECT_NAME}
PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/internal
${CMAKE_CURRENT_SOURCE_DIR}/drivers/include/thirdparty/fatfs
${CMAKE_CURRENT_SOURCE_DIR}/drivers/include/thirdparty
${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/fatfs/source
)
-target_link_libraries(${PROJECT_NAME} PUBLIC ${TARGET_LIBRARIES} module-bsp module-utils)
-target_link_libraries(${PROJECT_NAME} PRIVATE littlefs )
-# TODO: Temporary only remove when removing old vfs
-target_link_libraries(${PROJECT_NAME} PUBLIC utils-bootconfig )
+target_link_libraries(${PROJECT_NAME} PUBLIC ${TARGET_LIBRARIES} module-bsp module-utils module-sys module-os)
+target_link_libraries(${PROJECT_NAME} PRIVATE littlefs)
if (${ENABLE_TESTS})
add_subdirectory(tests)
A module-vfs/include/internal/purefs/fs/notifier.hpp => module-vfs/include/internal/purefs/fs/notifier.hpp +130 -0
@@ 0,0 1,130 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+#pragma once
+
+#include <map>
+#include <string>
+#include <memory>
+#include <optional>
+#include <purefs/fs/fsnotify.hpp>
+#include <purefs/fs/inotify_flags.hpp>
+
+namespace sys
+{
+ class Service;
+}
+namespace cpp_freertos
+{
+ class MutexRecursive;
+}
+namespace purefs::fs::internal
+{
+ //! Internal class related to the notify VFS events
+ class notifier
+ {
+ //! Container for path item
+ struct path_item
+ {
+ path_item(std::string_view _path, bool _read_only) : path(_path), read_only(_read_only)
+ {}
+ const std::string path;
+ const bool read_only;
+ };
+ //! Container for service and subscribed events
+ struct service_item
+ {
+ service_item(std::weak_ptr<sys::Service> _service, inotify_flags _subscribed_events)
+ : service(_service), subscribed_events(_subscribed_events)
+ {}
+ const std::weak_ptr<sys::Service> service;
+ const inotify_flags subscribed_events;
+ };
+ //! Container for the the event
+ using container_t = std::multimap<std::string, service_item>;
+
+ public:
+ notifier();
+ notifier(notifier &) = delete;
+ notifier &operator=(notifier &) = delete;
+ virtual ~notifier();
+ //! Iterator for the registered event
+ using item_it = container_t::iterator;
+ /**
+ * @brief Register selected path for the monitoring
+ *
+ * @param path Path for monitor
+ * @param owner Service which should be notified
+ * @param flags Event mask which should be monitored
+ * @return std::optional<item_it> Registered event iterator or nothing if failed
+ */
+ auto register_path(std::string_view path, std::shared_ptr<sys::Service> owner, inotify_flags flags)
+ -> std::optional<item_it>;
+ /**
+ * @brief Unregister selected path from monitoring
+ *
+ * @param item Iterator returned by the @see register_path method
+ */
+ auto unregister_path(item_it item) -> void;
+ /**
+ * @brief Internal method called on file open
+ *
+ * @param path Open file path
+ * @param fd File descriptor assigned by open method
+ * @param ro File is opened in read only mode
+ */
+ auto notify_open(std::string_view path, int fd, bool ro) const -> void;
+ /**
+ * @brief Internal method called on closing gile
+ *
+ * @param fd File descriptor
+ */
+ auto notify_close(int fd) const -> void;
+ /**
+ * @brief Notify for event on the file system
+ *
+ * @param fd File descriptor for file
+ * @param mask Filesystem event type
+ */
+ auto notify(int fd, inotify_flags mask) const -> void;
+ /**
+ * @brief Notify for event on filesystem on path change
+ *
+ * @param path Path before event occured
+ * @param path_prv Path after event occured
+ * @param mask Filesystem event type
+ */
+ auto notify(std::string_view path, std::string_view path_prv, inotify_flags mask) const -> void;
+ /**
+ * @brief Notify for event on the filesystem
+ *
+ * @param path Path related to th event
+ * @param mask Filesystem event type
+ */
+ auto notify(std::string_view path, inotify_flags mask) const -> void
+ {
+ notify(path, "", mask);
+ }
+
+ private:
+ /**
+ * @brief Private method called for send file monitor event
+ *
+ * @param svc Target service
+ * @param flags Filesystem event type
+ * @param name Path related to the event before change
+ * @param name_dst Path realated to the event after change
+ */
+ virtual auto send_notification(std::shared_ptr<sys::Service> svc,
+ inotify_flags flags,
+ std::string_view name,
+ std::string_view name_dst) const -> void;
+
+ private:
+ //! Events container
+ container_t m_events;
+ //! Map file descriptors with path assiociated with it
+ mutable std::map<int, path_item> m_fd_map;
+ //! Internal mutex for lock the object
+ std::unique_ptr<cpp_freertos::MutexRecursive> m_lock;
+ };
+} // namespace purefs::fs::internal
D module-vfs/include/user/deprecated/vfsNotifier.hpp => module-vfs/include/user/deprecated/vfsNotifier.hpp +0 -98
@@ 1,98 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-//
-#pragma once
-#include <unordered_map>
-#include <mutex.hpp>
-#include <functional>
-#include <string>
-#include <thread.hpp>
-
-namespace vfsn::utility
-{
- class vfsNotifier
- {
- struct FF_FILE;
- using FILE = FF_FILE;
-
- public:
- //! Default constructor and destructor
- vfsNotifier() = default;
- vfsNotifier(const vfsNotifier &) = delete;
- vfsNotifier &operator=(const vfsNotifier &) = delete;
- //! Event type notified for indexer
- enum class FsEvent
- {
- initialized, //! Filesystem is intialized
- modified, //! File is modified
- deleted, //! File is deleted
- renamed
- };
- /** Notification handler type
- * Notify function callback defiinition
- */
- using NotifyHandler = std::function<void(std::string_view, FsEvent, std::string_view)>;
- /** This method is called by the vfs layer when vfs open file
- * @param[in] filename Opened file path
- * @param[in] mode Open mode
- * @param[in] Handle to opened file
- * @return None
- */
- auto onFileOpen(std::string_view filename, const char *mode, const FILE *file) noexcept -> void;
- /** This method is called by the vfs layer when vfs close file
- * @param[in] filee Closed file handle
- * @return None
- */
- auto onFileClose(const FILE *file) noexcept -> void;
- /** This method is called by the vfs layer when file is removed
- * @param[in] filename Removed file path
- * @return None
- */
- auto onFileRemove(std::string_view filename) noexcept -> void;
- /** This method is called by the vfs layer when the vfs rename file
- * @param[in] new_file New path name for the file
- * @param[in] old_file Old path for the file
- * @return None
- */
- auto onFileRename(std::string_view new_file, std::string_view old_file) noexcept -> void;
- /** This method is called by the vfs layer when the disk is intiialized
- * @return None
- */
- auto onFileSystemInitialized() noexcept -> void
- {
- notify("/", FsEvent::initialized);
- }
- /** Method for register notification handler
- * @note This function is called from the thread contest which use vfs call
- * @param[in] hwnd Notification handler funtion
- * @return None
- */
- auto registerNotificationHandler(NotifyHandler hwnd) -> void
- {
- notificationCallback = hwnd;
- threadHandle = hwnd ? cpp_freertos::Thread::GetCurrentThreadHandle() : nullptr;
- }
-
- private:
- /** Private notification helper internal method
- * @param[in] file Modified file path
- * @param[in] event Notification event type
- * @param[in] old_file Old file path
- * @return None
- */
- auto notify(std::string_view file, FsEvent event, std::string_view old_file = "") -> void
- {
- if (threadHandle != cpp_freertos::Thread::GetCurrentThreadHandle() && notificationCallback)
- notificationCallback(file, event, old_file);
- }
-
- private:
- //! Map for opened handles and paths
- std::unordered_map<const FILE *, std::string> mOpenedMap;
- //! Mutex for unordered map
- cpp_freertos::MutexStandard mMutex;
- //! Notification handler callback
- NotifyHandler notificationCallback;
- TaskHandle_t threadHandle;
- };
-} // namespace vfsn::utility
R module-vfs/include/internal/purefs/fs/directory_handle.hpp => module-vfs/include/user/purefs/fs/directory_handle.hpp +0 -0
R module-vfs/include/internal/purefs/fs/file_handle.hpp => module-vfs/include/user/purefs/fs/file_handle.hpp +1 -1
@@ 14,7 14,7 @@ namespace purefs::fs::internal
public:
file_handle(const file_handle &) = delete;
auto operator=(const file_handle &) = delete;
- virtual ~file_handle() = default;
+ virtual ~file_handle() = default;
file_handle(std::shared_ptr<mount_point> mp, unsigned flags) : m_mount_point(mp), m_flags(flags)
{}
[[nodiscard]] auto error() const noexcept
M module-vfs/include/user/purefs/fs/filesystem.hpp => module-vfs/include/user/purefs/fs/filesystem.hpp +11 -1
@@ 15,6 15,7 @@
#include <purefs/fs/directory_handle.hpp>
#include <purefs/fs/mount_point.hpp>
#include <purefs/fs/mount_flags.hpp>
+#include <purefs/fs/fsnotify.hpp>
#include <type_traits>
struct statvfs;
@@ 30,6 31,11 @@ namespace cpp_freertos
class MutexRecursive;
}
+namespace sys
+{
+ class Service;
+}
+
namespace purefs::fs
{
/** This is the filesystem class layer
@@ 41,6 47,7 @@ namespace purefs::fs
namespace internal
{
class directory_handle;
+ class notifier;
}
class filesystem
{
@@ 142,6 149,9 @@ namespace purefs::fs
auto getcwd() noexcept -> std::string_view;
auto chdir(std::string_view name) noexcept -> int;
+ /** Inotify API */
+ [[nodiscard]] auto inotify_create(std::shared_ptr<sys::Service> svc) -> std::shared_ptr<inotify>;
+
private:
/** Unregister filesystem driver
* @param[in] fsname Unique filesystem name for example fat
@@ 271,7 281,6 @@ namespace purefs::fs
}
}
}
-
private:
std::weak_ptr<blkdev::disk_manager> m_diskmm;
std::unordered_map<std::string, std::shared_ptr<filesystem_operations>> m_fstypes;
@@ 279,5 288,6 @@ namespace purefs::fs
std::unordered_set<std::string> m_partitions;
internal::handle_mapper<fsfile> m_fds;
std::unique_ptr<cpp_freertos::MutexRecursive> m_lock;
+ std::shared_ptr<internal::notifier> m_notifier;
};
} // namespace purefs::fs
A module-vfs/include/user/purefs/fs/fsnotify.hpp => module-vfs/include/user/purefs/fs/fsnotify.hpp +58 -0
@@ 0,0 1,58 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <string>
+#include <memory>
+#include <purefs/fs/inotify_flags.hpp>
+
+namespace sys
+{
+ class Service;
+}
+namespace cpp_freertos
+{
+ class MutexRecursive;
+}
+namespace purefs::fs
+{
+ namespace internal
+ {
+ class notifier;
+ struct inotify_container;
+ } // namespace internal
+
+ //! Inotifier object returned by the monitoring API
+ class inotify
+ {
+ public:
+ ~inotify();
+ /** Constructor for the inotify user object
+ * @param[in] svc Service owner
+ * @param[in] notifier Master notifier object
+ */
+ inotify(std::shared_ptr<sys::Service> svc, std::shared_ptr<purefs::fs::internal::notifier> notifier);
+ /** Add path for monitoring for monitoring
+ * @param[in] monitored_path Path or file which should be monitored
+ * @param[in] event_mask Event mask for file monitor
+ * @return Error code
+ */
+ int add_watch(std::string_view monitored_path, inotify_flags event_mask);
+ /**
+ * @param[in] monitored_path Monitored path for removal
+ * @return Error code
+ */
+ int rm_watch(std::string_view monitored_path);
+
+ private:
+ //! Owning service
+ std::weak_ptr<sys::Service> m_svc;
+ //! Owner notifier
+ std::weak_ptr<internal::notifier> m_notify;
+ //! Map for the devices
+ std::unique_ptr<internal::inotify_container> m_evlist;
+ //! Lock the object
+ std::unique_ptr<cpp_freertos::MutexRecursive> m_lock;
+ };
+
+} // namespace purefs::fs
R module-vfs/include/internal/purefs/fs/handle_mapper.hpp => module-vfs/include/user/purefs/fs/handle_mapper.hpp +0 -0
A module-vfs/include/user/purefs/fs/inotify.hpp => module-vfs/include/user/purefs/fs/inotify.hpp +22 -0
@@ 0,0 1,22 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+#pragma once
+#include <memory>
+#include <purefs/vfs_subsystem.hpp>
+#include <purefs/fs/fsnotify.hpp>
+
+namespace purefs::fs
+{
+ /** Create inotify class which owns the notifier interface
+ * @param[in] svc Owner of the service
+ * @return Inotify object shared ptr or errno if nullptr
+ */
+ inline auto inotify_create(std::shared_ptr<sys::Service> svc) -> std::shared_ptr<inotify>
+ {
+ const auto vfs = subsystem::vfs_core();
+ if (!vfs) {
+ return nullptr;
+ }
+ return vfs->inotify_create(svc);
+ }
+} // namespace purefs::fs
A module-vfs/include/user/purefs/fs/inotify_flags.hpp => module-vfs/include/user/purefs/fs/inotify_flags.hpp +36 -0
@@ 0,0 1,36 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+namespace purefs::fs
+{
+ //! Event monitor flag
+ enum class inotify_flags : unsigned
+ {
+ attrib = 0x01, //! Attribute changed
+ close_write = 0x02, //! File closed after write
+ close_nowrite = 0x04, //! File closed without write
+ del = 0x08, //! File was deleted
+ move_src = 0x10, //! File moved
+ move_dst = 0x20, //! File moved
+ open = 0x40, //! File was opended
+ dmodify = 0x80, //! Directory entry modified
+ };
+ inline auto operator|(inotify_flags fl1, inotify_flags fl2)
+ {
+ return static_cast<inotify_flags>(static_cast<unsigned>(fl1) | static_cast<unsigned>(fl2));
+ }
+ inline auto operator&(inotify_flags fl1, inotify_flags fl2)
+ {
+ return static_cast<inotify_flags>(static_cast<unsigned>(fl1) & static_cast<unsigned>(fl2));
+ }
+ inline auto operator&&(inotify_flags fl1, inotify_flags fl2) -> bool
+ {
+ return static_cast<bool>(static_cast<unsigned>(fl1) & static_cast<unsigned>(fl2));
+ }
+ inline auto operator||(inotify_flags fl1, inotify_flags fl2) -> bool
+ {
+ return static_cast<bool>(static_cast<unsigned>(fl1) | static_cast<unsigned>(fl2));
+ }
+
+} // namespace purefs::fs
A module-vfs/include/user/purefs/fs/inotify_message.hpp => module-vfs/include/user/purefs/fs/inotify_message.hpp +28 -0
@@ 0,0 1,28 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <Service/Message.hpp>
+#include <purefs/fs/inotify_flags.hpp>
+
+namespace purefs::fs::message
+{
+ //! Class message received when on new file event
+ struct inotify final : public ::sys::DataMessage
+ {
+ /**
+ * @brief Construct a new inotify object
+ *
+ * @param _flags Event type
+ * @param _name Filename path
+ * @param _name_prev Old path (when move)
+ */
+ inotify(inotify_flags _flags, std::string_view _name, std::string_view _name_prev)
+ : flags(_flags), name(_name), name_prev(_name_prev)
+ {}
+ virtual ~inotify() = default;
+ const inotify_flags flags;
+ const std::string name;
+ const std::string name_prev;
+ };
+} // namespace purefs::fs::message
R module-vfs/include/internal/purefs/fs/mount_flags.hpp => module-vfs/include/user/purefs/fs/mount_flags.hpp +0 -0
R module-vfs/include/internal/purefs/fs/mount_point.hpp => module-vfs/include/user/purefs/fs/mount_point.hpp +1 -1
@@ 31,7 31,7 @@ namespace purefs::fs::internal
{}
mount_point(const mount_point &) = delete;
auto operator=(const mount_point &) = delete;
- virtual ~mount_point() = default;
+ virtual ~mount_point() = default;
auto disk() const noexcept
{
return m_diskh.lock();
D module-vfs/src/deprecated/vfsNotifier.cpp => module-vfs/src/deprecated/vfsNotifier.cpp +0 -38
@@ 1,38 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "vfsNotifier.hpp"
-#include <vfs.hpp>
-#include <cstring>
-
-namespace vfsn::utility
-{
-
- auto vfsNotifier::onFileOpen(std::string_view filename, const char *mode, const FILE *file) noexcept -> void
- {
- if (file && std::strpbrk(mode, "+wa")) {
- cpp_freertos::LockGuard _lock(mMutex);
- mOpenedMap.emplace(file, vfs.getAbsolutePath(filename));
- }
- }
- auto vfsNotifier::onFileClose(const FILE *file) noexcept -> void
- {
- cpp_freertos::LockGuard _lock(mMutex);
- const auto item = mOpenedMap.find(file);
- if (item != mOpenedMap.end()) {
- const auto path = item->second;
- mOpenedMap.erase(item);
- notify(path, FsEvent::modified);
- }
- }
-
- auto vfsNotifier::onFileRemove(std::string_view filename) noexcept -> void
- {
- notify(vfs.getAbsolutePath(filename), FsEvent::deleted);
- }
-
- auto vfsNotifier::onFileRename(std::string_view new_file, std::string_view old_file) noexcept -> void
- {
- notify(vfs.getAbsolutePath(new_file), FsEvent::renamed, vfs.getAbsolutePath(old_file));
- }
-} // namespace vfsn::utility
M module-vfs/src/purefs/fs/filesystem.cpp => module-vfs/src/purefs/fs/filesystem.cpp +11 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <purefs/fs/filesystem.hpp>
#include <purefs/fs/filesystem_operations.hpp>
@@ 6,6 6,8 @@
#include <purefs/blkdev/disk_manager.hpp>
#include <purefs/fs/thread_local_cwd.hpp>
#include <purefs/blkdev/disk_handle.hpp>
+#include <purefs/fs/notifier.hpp>
+#include <purefs/fs/fsnotify.hpp>
#include <log/log.hpp>
#include <split_sv.hpp>
#include <errno.h>
@@ 21,7 23,8 @@ namespace purefs::fs
};
}
filesystem::filesystem(std::shared_ptr<blkdev::disk_manager> diskmm)
- : m_diskmm(diskmm), m_lock(new cpp_freertos::MutexRecursive)
+ : m_diskmm(diskmm), m_lock(std::make_unique<cpp_freertos::MutexRecursive>()),
+ m_notifier(std::make_unique<internal::notifier>())
{}
filesystem::~filesystem()
@@ 308,4 311,10 @@ namespace purefs::fs
return {};
}
}
+
+ auto filesystem::inotify_create(std::shared_ptr<sys::Service> svc) -> std::shared_ptr<inotify>
+ {
+ return std::make_shared<inotify>(svc, m_notifier);
+ }
+
} // namespace purefs::fs
M module-vfs/src/purefs/fs/filesystem_syscalls.cpp => module-vfs/src/purefs/fs/filesystem_syscalls.cpp +47 -10
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <purefs/fs/filesystem.hpp>
#include <errno.h>
@@ 7,6 7,7 @@
#include <purefs/fs/file_handle.hpp>
#include <purefs/fs/directory_handle.hpp>
#include <purefs/fs/thread_local_cwd.hpp>
+#include <purefs/fs/notifier.hpp>
#include <fcntl.h>
namespace purefs::fs
@@ 23,12 24,20 @@ namespace purefs::fs
auto filesystem::unlink(std::string_view name) noexcept -> int
{
- return invoke_fops(iaccess::rw, &filesystem_operations::unlink, name);
+ const auto err = invoke_fops(iaccess::rw, &filesystem_operations::unlink, name);
+ if (!err) {
+ m_notifier->notify(name, inotify_flags::del);
+ }
+ return err;
}
auto filesystem::mkdir(std::string_view path, int mode) noexcept -> int
{
- return invoke_fops(iaccess::rw, &filesystem_operations::mkdir, path, mode);
+ const auto err = invoke_fops(iaccess::rw, &filesystem_operations::mkdir, path, mode);
+ if (!err) {
+ m_notifier->notify(path, inotify_flags::dmodify);
+ }
+ return err;
}
auto filesystem::ioctl(std::string_view path, int cmd, void *arg) noexcept -> int
@@ 38,7 47,11 @@ namespace purefs::fs
auto filesystem::utimens(std::string_view path, std::array<timespec, 2> &tv) noexcept -> int
{
- return invoke_fops(iaccess::ro, &filesystem_operations::utimens, path, tv);
+ const auto err = invoke_fops(iaccess::ro, &filesystem_operations::utimens, path, tv);
+ if (!err) {
+ m_notifier->notify(path, inotify_flags::attrib);
+ }
+ return err;
}
auto filesystem::flock(int fd, int cmd) noexcept -> int
@@ 53,7 66,11 @@ namespace purefs::fs
auto filesystem::chmod(std::string_view path, mode_t mode) noexcept -> int
{
- return invoke_fops(iaccess::rw, &filesystem_operations::chmod, path, mode);
+ const auto err = invoke_fops(iaccess::rw, &filesystem_operations::chmod, path, mode);
+ if (!err) {
+ m_notifier->notify(path, inotify_flags::attrib);
+ }
+ return err;
}
auto filesystem::write(int fd, const char *ptr, size_t len) noexcept -> ssize_t
@@ 88,22 105,39 @@ namespace purefs::fs
auto filesystem::fchmod(int fd, mode_t mode) noexcept -> int
{
- return invoke_fops(&filesystem_operations::fchmod, fd, mode);
+ const auto err = invoke_fops(&filesystem_operations::fchmod, fd, mode);
+ if (!err) {
+ m_notifier->notify(fd, inotify_flags::attrib);
+ }
+ return err;
}
auto filesystem::symlink(std::string_view existing, std::string_view newlink) noexcept -> int
{
- return invoke_fops_same_mp(&filesystem_operations::symlink, existing, newlink);
+ const auto err = invoke_fops_same_mp(&filesystem_operations::symlink, existing, newlink);
+ if (!err) {
+ m_notifier->notify(newlink, inotify_flags::dmodify);
+ }
+ return err;
}
auto filesystem::link(std::string_view existing, std::string_view newlink) noexcept -> int
{
- return invoke_fops_same_mp(&filesystem_operations::link, existing, newlink);
+ const auto err = invoke_fops_same_mp(&filesystem_operations::link, existing, newlink);
+ if (!err) {
+ m_notifier->notify(newlink, inotify_flags::dmodify);
+ }
+ return err;
}
auto filesystem::rename(std::string_view oldname, std::string_view newname) noexcept -> int
{
- return invoke_fops_same_mp(&filesystem_operations::rename, oldname, newname);
+ const auto err = invoke_fops_same_mp(&filesystem_operations::rename, oldname, newname);
+ if (!err) {
+ m_notifier->notify(oldname, newname, inotify_flags::move_src);
+ m_notifier->notify(newname, oldname, inotify_flags::move_dst);
+ }
+ return err;
}
auto filesystem::open(std::string_view path, int flags, int mode) noexcept -> int
@@ 129,7 163,9 @@ namespace purefs::fs
if (err) {
return err;
}
- return add_filehandle(fh);
+ const auto fd = add_filehandle(fh);
+ m_notifier->notify_open(path, fd, (flags & O_ACCMODE) == O_RDONLY);
+ return fd;
}
else {
LOG_ERROR("VFS: Unable to lock fops");
@@ 142,6 178,7 @@ namespace purefs::fs
auto ret = invoke_fops(&filesystem_operations::close, fd);
if (!ret) {
ret = (remove_filehandle(fd)) ? (0) : (-EBADF);
+ m_notifier->notify_close(fd);
}
return ret;
}
A module-vfs/src/purefs/fs/fsnotify.cpp => module-vfs/src/purefs/fs/fsnotify.cpp +83 -0
@@ 0,0 1,83 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <purefs/fs/fsnotify.hpp>
+#include <purefs/fs/notifier.hpp>
+#include <log/log.hpp>
+#include <mutex.hpp>
+#include <cerrno>
+
+namespace purefs::fs
+{
+ namespace internal
+ {
+ struct inotify_container
+ {
+ std::map<std::string, internal::notifier::item_it> items;
+ };
+ } // namespace internal
+ inotify::inotify(std::shared_ptr<sys::Service> svc, std::shared_ptr<internal::notifier> notifier)
+ : m_svc(svc), m_notify(notifier), m_evlist(std::make_unique<internal::inotify_container>()),
+ m_lock(std::make_unique<cpp_freertos::MutexRecursive>())
+ {}
+
+ inotify::~inotify()
+ {
+ const auto notifier = m_notify.lock();
+ if (!notifier) {
+ LOG_ERROR("Unable lock notifier");
+ }
+ const auto svc = m_svc.lock();
+ if (!svc) {
+ LOG_ERROR("Unable lock service");
+ }
+ for (const auto &[_, val] : m_evlist->items) {
+ notifier->unregister_path(val);
+ }
+ }
+
+ int inotify::add_watch(std::string_view monitored_path, inotify_flags event_mask)
+ {
+ const auto notifier = m_notify.lock();
+ if (!notifier) {
+ LOG_ERROR("Unable lock notifier");
+ return -ENXIO;
+ }
+ const auto svc = m_svc.lock();
+ if (!svc) {
+ LOG_ERROR("Unable lock service");
+ return -ENXIO;
+ }
+ auto it = notifier->register_path(monitored_path, svc, event_mask);
+ if (!it) {
+ LOG_ERROR("Unable to register path");
+ return -EIO;
+ }
+ cpp_freertos::LockGuard _lck(*m_lock);
+ m_evlist->items.emplace(std::make_pair(std::string(monitored_path), *it));
+ return {};
+ }
+
+ int inotify::rm_watch(std::string_view monitored_path)
+ {
+ const auto notifier = m_notify.lock();
+ if (!notifier) {
+ LOG_ERROR("Unable lock notifier");
+ return -ENXIO;
+ }
+ const auto svc = m_svc.lock();
+ if (!svc) {
+ LOG_ERROR("Unable lock service");
+ return -ENXIO;
+ }
+ cpp_freertos::LockGuard _lck(*m_lock);
+ auto it = m_evlist->items.find(std::string(monitored_path));
+ if (it == std::end(m_evlist->items)) {
+ LOG_ERROR("Unable to find registered path %s", std::string(monitored_path).c_str());
+ return -ENOENT;
+ }
+ notifier->unregister_path(it->second);
+ m_evlist->items.erase(it);
+ return {};
+ }
+} // namespace purefs::fs
A module-vfs/src/purefs/fs/notifier.cpp => module-vfs/src/purefs/fs/notifier.cpp +115 -0
@@ 0,0 1,115 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+#include <purefs/fs/notifier.hpp>
+#include <purefs/fs/inotify_message.hpp>
+#include <functional>
+#include <Service/Service.hpp>
+#include <purefs/fs/inotify_message.hpp>
+#include <purefs/fs/thread_local_cwd.hpp>
+#include <log/log.hpp>
+
+namespace purefs::fs::internal
+{
+ namespace
+ {
+ void for_path(std::string_view path, std::function<void(std::string_view)> fun)
+ {
+ constexpr auto sep = '/';
+ for (auto it = (path.back() == sep) ? (path.size() - 1) : (path.size()); (it && it != std::string::npos);
+ it = path.rfind(sep, it - 1))
+ fun(path.substr(0, it));
+ }
+ std::string absolute_path(std::string_view path)
+ {
+ using namespace std::string_literals;
+ std::string ret;
+ if (!path.empty() && path[0] != '/') {
+ ret = std::string(internal::get_thread_local_cwd_path()) + "/"s + std::string(path);
+ }
+ else {
+ ret = std::string(path);
+ }
+ if (!ret.empty() && ret.back() == '/') {
+ ret.pop_back();
+ }
+ return ret;
+ }
+ } // namespace
+ notifier::notifier() : m_lock(std::make_unique<cpp_freertos::MutexRecursive>())
+ {}
+ notifier::~notifier()
+ {}
+ auto notifier::register_path(std::string_view path, std::shared_ptr<sys::Service> owner, inotify_flags flags)
+ -> std::optional<item_it>
+ {
+ cpp_freertos::LockGuard _lck(*m_lock);
+ const auto abspath = absolute_path(path);
+ // # Check if it is already registered for same path
+ const auto range = m_events.equal_range(abspath);
+ for (auto i = range.first; i != range.second; ++i) {
+ if (i->second.service.lock() == owner) {
+ return std::nullopt;
+ }
+ }
+ return m_events.emplace(std::make_pair(abspath, service_item(owner, flags)));
+ }
+ auto notifier::unregister_path(item_it item) -> void
+ {
+ cpp_freertos::LockGuard _lck(*m_lock);
+ m_events.erase(item);
+ }
+ auto notifier::notify(int fd, inotify_flags mask) const -> void
+ {
+ cpp_freertos::LockGuard _lck(*m_lock);
+ const auto fname_it = m_fd_map.find(fd);
+ if (fname_it != std::end(m_fd_map)) {
+ notify(fname_it->second.path, mask);
+ }
+ }
+ void notifier::notify(std::string_view path, std::string_view path_prv, inotify_flags mask) const
+ {
+ cpp_freertos::LockGuard _lck(*m_lock);
+ const auto abs_path = absolute_path(path);
+ const auto abs_path_prv = absolute_path(path_prv);
+ for_path(abs_path, [this, abs_path, abs_path_prv, mask](std::string_view path) {
+ const auto range = m_events.equal_range(std::string(path));
+ for (auto i = range.first; i != range.second; ++i) {
+ if (i->second.subscribed_events && mask) {
+ auto svc = i->second.service.lock();
+ if (svc) {
+ send_notification(svc, mask, abs_path, abs_path_prv);
+ }
+ }
+ }
+ });
+ }
+ auto notifier::notify_open(std::string_view path, int fd, bool ro) const -> void
+ {
+ cpp_freertos::LockGuard _lck(*m_lock);
+ m_fd_map.emplace(std::make_pair(fd, path_item(path, ro)));
+ notify(path, inotify_flags::open);
+ }
+ auto notifier::notify_close(int fd) const -> void
+ {
+ cpp_freertos::LockGuard _lck(*m_lock);
+ const auto fname_it = m_fd_map.find(fd);
+ if (fname_it != std::end(m_fd_map)) {
+ notify(fname_it->first,
+ fname_it->second.read_only ? inotify_flags::close_nowrite : inotify_flags::close_write);
+ m_fd_map.erase(fname_it);
+ }
+ }
+ auto notifier::send_notification(std::shared_ptr<sys::Service> svc,
+ inotify_flags flags,
+ std::string_view name,
+ std::string_view name_dst) const -> void
+ {
+ if (svc->GetHandle() != cpp_freertos::Thread::GetCurrentThreadHandle()) {
+ auto msg = std::make_shared<message::inotify>(flags, name, name_dst);
+ svc->bus.sendUnicast(std::move(msg), svc->GetName());
+ }
+ else {
+ LOG_WARN("Sent notification to the same thread is forbidded");
+ }
+ }
+} // namespace purefs::fs::internal
M module-vfs/tests/CMakeLists.txt => module-vfs/tests/CMakeLists.txt +17 -0
@@ 22,6 22,8 @@ add_catch2_executable(
NAME vfs-core-fs
SRCS
${CMAKE_CURRENT_LIST_DIR}/unittest_filesystem_core.cpp
+ INCLUDE
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include/internal
LIBS
module-vfs
)
@@ 38,6 40,8 @@ add_catch2_executable(
NAME vfs-littlefs
SRCS
${CMAKE_CURRENT_LIST_DIR}/unittest_filesystem_littlefs.cpp
+ INCLUDE
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include/internal
LIBS
module-vfs
DEPS
@@ 48,12 52,25 @@ add_catch2_executable(
NAME vfs-dualmount
SRCS
${CMAKE_CURRENT_LIST_DIR}/unittest_filesystem_dualmount.cpp
+ INCLUDE
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include/internal
+
LIBS
module-vfs
DEPS
${LITTLEFS_IMAGE}
)
+add_catch2_executable(
+ NAME vfs-inotify
+ SRCS
+ ${CMAKE_CURRENT_LIST_DIR}/unittest_filesystem_inotify.cpp
+ LIBS
+ module-vfs
+ INCLUDE
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include/internal
+)
+
# prepare test assets
set(ASSETS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/test_dir")
set(ASSETS_TARGET_DIR "${CMAKE_BINARY_DIR}/module-vfs/test_dir")
A module-vfs/tests/unittest_filesystem_inotify.cpp => module-vfs/tests/unittest_filesystem_inotify.cpp +168 -0
@@ 0,0 1,168 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+#define CATCH_CONFIG_MAIN
+#include <catch2/catch.hpp>
+#include <purefs/fs/notifier.hpp>
+#include <purefs/fs/inotify_message.hpp>
+
+namespace purefs::fs
+{
+
+ struct notifier_mock final : public internal::notifier
+ {
+ virtual ~notifier_mock() = default;
+ auto send_notification(std::shared_ptr<sys::Service> svc,
+ inotify_flags flags,
+ std::string_view name,
+ std::string_view name_dst) const -> void override
+ {
+ messages.emplace_back(flags, name, name_dst);
+ xsvc.push_back(svc.get());
+ }
+ mutable std::vector<message::inotify> messages;
+ mutable std::vector<sys::Service *> xsvc;
+ };
+} // namespace purefs::fs
+
+namespace sys
+{
+ class Service
+ {};
+} // namespace sys
+
+TEST_CASE("vfsinotify: Notifier base class test")
+{
+ using namespace purefs::fs;
+ auto svc = std::make_shared<sys::Service>();
+ notifier_mock notify;
+ notify.register_path("/sys/ala",
+ svc,
+ inotify_flags::open | inotify_flags::close_nowrite | inotify_flags::close_write |
+ inotify_flags::attrib | inotify_flags::move_src | inotify_flags::move_dst);
+ SECTION("open and close simple")
+ {
+ notify.notify_open("/sys/ala", 77, true);
+ notify.notify_close(77);
+ REQUIRE(notify.messages.size() == 2);
+ REQUIRE(notify.messages[0].name == "/sys/ala");
+ REQUIRE(notify.messages[0].name_prev.empty());
+ REQUIRE((notify.messages[0].flags && inotify_flags::open));
+ REQUIRE(notify.messages[1].name == "/sys/ala");
+ REQUIRE(notify.messages[1].name_prev.empty());
+ REQUIRE((notify.messages[1].flags && inotify_flags::close_nowrite));
+ notify.messages.clear();
+ }
+ SECTION("open and close pairing")
+ {
+ notify.notify_open("/sys/ala/1", 100, true);
+ notify.notify_open("/sys/ala/2", 200, false);
+ notify.notify_open("/sys/ala/3", 300, true);
+ REQUIRE(notify.messages.size() == 3);
+ notify.notify(200, inotify_flags::attrib);
+ REQUIRE(notify.messages.size() == 4);
+ notify.notify_close(200);
+ REQUIRE(notify.messages.size() == 5);
+ notify.notify_close(200);
+ REQUIRE(notify.messages.size() == 5);
+ REQUIRE(notify.messages[0].name == "/sys/ala/1");
+ REQUIRE((notify.messages[0].flags && inotify_flags::open));
+ REQUIRE(notify.messages[1].name == "/sys/ala/2");
+ REQUIRE((notify.messages[1].flags && inotify_flags::open));
+ REQUIRE(notify.messages[2].name == "/sys/ala/3");
+ REQUIRE((notify.messages[2].flags && inotify_flags::open));
+ REQUIRE(notify.messages[3].name == "/sys/ala/2");
+ REQUIRE((notify.messages[3].flags && inotify_flags::attrib));
+ REQUIRE(notify.messages[4].name == "/sys/ala/2");
+ REQUIRE((notify.messages[4].flags && inotify_flags::close_write));
+ notify.messages.clear();
+ notify.notify_close(100);
+ notify.notify_close(300);
+ REQUIRE(notify.messages.size() == 2);
+ REQUIRE(notify.messages[0].name == "/sys/ala/1");
+ REQUIRE((notify.messages[0].flags && inotify_flags::close_nowrite));
+ REQUIRE(notify.messages[1].name == "/sys/ala/3");
+ REQUIRE((notify.messages[1].flags && inotify_flags::close_nowrite));
+ notify.notify_close(300);
+ notify.notify_close(300);
+ REQUIRE(notify.messages.size() == 2);
+ notify.messages.clear();
+ }
+ SECTION("Other notifies tests")
+ {
+ notify.notify("/sys/ala/100", "/sys/ala/555", inotify_flags::move_src);
+ notify.notify("/sys/ala/555", "/sys/ala/100", inotify_flags::move_dst);
+ notify.notify("/sys/ala/999/989", inotify_flags::attrib);
+ REQUIRE(notify.messages.size() == 3);
+ REQUIRE(notify.messages[0].name == "/sys/ala/100");
+ REQUIRE(notify.messages[0].name_prev == "/sys/ala/555");
+ REQUIRE((notify.messages[0].flags && inotify_flags::move_src));
+ REQUIRE(notify.messages[1].name == "/sys/ala/555");
+ REQUIRE(notify.messages[1].name_prev == "/sys/ala/100");
+ REQUIRE((notify.messages[1].flags && inotify_flags::move_dst));
+ }
+}
+
+TEST_CASE("vfsinotify: Filtering test")
+{
+ using namespace purefs::fs;
+ SECTION("Different mask for services")
+ {
+ notifier_mock notify;
+ auto svc1 = std::make_shared<sys::Service>();
+ auto svc2 = std::make_shared<sys::Service>();
+ notify.register_path(
+ "/sys/path1", svc1, inotify_flags::open | inotify_flags::close_nowrite | inotify_flags::close_write);
+ notify.register_path("/sys/path1/", svc2, inotify_flags::open | inotify_flags::close_write);
+ notify.notify_open("/sys/path1/file.txt", 100, false);
+ notify.notify_open("/sys/path1/file1.txt", 200, true);
+ REQUIRE(notify.messages.size() == 4);
+ notify.notify_close(100);
+ REQUIRE(notify.messages.size() == 6);
+ notify.notify_close(200);
+ REQUIRE(notify.messages.size() == 7);
+ // Checking values in the queue
+ REQUIRE(notify.messages[0].name == "/sys/path1/file.txt");
+ REQUIRE((notify.messages[0].flags && inotify_flags::open));
+ REQUIRE(notify.xsvc[0] == svc1.get());
+ REQUIRE(notify.messages[1].name == "/sys/path1/file.txt");
+ REQUIRE((notify.messages[1].flags && inotify_flags::open));
+ REQUIRE(notify.xsvc[1] == svc2.get());
+ REQUIRE(notify.messages[2].name == "/sys/path1/file1.txt");
+ REQUIRE((notify.messages[2].flags && inotify_flags::open));
+ REQUIRE(notify.xsvc[2] == svc1.get());
+ REQUIRE(notify.messages[3].name == "/sys/path1/file1.txt");
+ REQUIRE((notify.messages[3].flags && inotify_flags::open));
+ REQUIRE(notify.xsvc[3] == svc2.get());
+ REQUIRE(notify.messages[4].name == "/sys/path1/file.txt");
+ REQUIRE((notify.messages[4].flags && inotify_flags::close_write));
+ REQUIRE(notify.xsvc[4] == svc1.get());
+ REQUIRE(notify.messages[5].name == "/sys/path1/file.txt");
+ REQUIRE((notify.messages[5].flags && inotify_flags::close_write));
+ REQUIRE(notify.xsvc[5] == svc2.get());
+ REQUIRE(notify.messages[6].name == "/sys/path1/file1.txt");
+ REQUIRE((notify.messages[6].flags && inotify_flags::close_nowrite));
+ REQUIRE(notify.xsvc[6] == svc1.get());
+ }
+ SECTION("Different paths for services")
+ {
+ notifier_mock notify;
+ auto svc1 = std::make_shared<sys::Service>();
+ auto svc2 = std::make_shared<sys::Service>();
+ notify.register_path("/sys/path1", svc1, inotify_flags::attrib);
+ notify.register_path("/sys/path2", svc2, inotify_flags::attrib);
+ notify.notify("/sys/path1/file.txt", inotify_flags::attrib);
+ REQUIRE(notify.messages.size() == 1);
+ notify.notify("/sys/path1/file2.txt", inotify_flags::attrib);
+ REQUIRE(notify.messages.size() == 2);
+ notify.notify("/sys/path3", inotify_flags::attrib);
+ REQUIRE(notify.messages.size() == 2);
+ notify.notify("/sys/path2/", inotify_flags::attrib);
+ REQUIRE(notify.messages.size() == 3);
+ REQUIRE(notify.messages[0].name == "/sys/path1/file.txt");
+ REQUIRE(notify.xsvc[0] == svc1.get());
+ REQUIRE(notify.messages[1].name == "/sys/path1/file2.txt");
+ REQUIRE(notify.xsvc[1] == svc1.get());
+ REQUIRE(notify.messages[2].name == "/sys/path2");
+ REQUIRE(notify.xsvc[2] == svc2.get());
+ }
+}