~aleteoryx/muditaos

ref: 2ec5be1061f31b00850d8a9623687d5042def297 muditaos/module-vfs/src/purefs/fs/notifier.cpp -rw-r--r-- 4.5 KiB
2ec5be10 — Dawid Wojtas [BH-1822] Disable Address Sanitizer 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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