Serenity Operating System
at master 173 lines 5.0 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <Kernel/FileSystem/Inode.h> 9#include <Kernel/FileSystem/InodeWatcher.h> 10#include <Kernel/Process.h> 11 12namespace Kernel { 13 14ErrorOr<NonnullRefPtr<InodeWatcher>> InodeWatcher::try_create() 15{ 16 return adopt_nonnull_ref_or_enomem(new (nothrow) InodeWatcher); 17} 18 19InodeWatcher::~InodeWatcher() 20{ 21 (void)close(); 22} 23 24bool InodeWatcher::can_read(OpenFileDescription const&, u64) const 25{ 26 MutexLocker locker(m_lock); 27 return !m_queue.is_empty(); 28} 29 30ErrorOr<size_t> InodeWatcher::read(OpenFileDescription&, u64, UserOrKernelBuffer& buffer, size_t buffer_size) 31{ 32 MutexLocker locker(m_lock); 33 if (m_queue.is_empty()) 34 // can_read will catch the blocking case. 35 return EAGAIN; 36 37 auto event = m_queue.dequeue(); 38 39 size_t bytes_to_write = sizeof(InodeWatcherEvent); 40 if (event.path) 41 bytes_to_write += event.path->length() + 1; 42 43 if (buffer_size < bytes_to_write) 44 return EINVAL; 45 46 auto result = buffer.write_buffered<MAXIMUM_EVENT_SIZE>(bytes_to_write, [&](Bytes bytes) { 47 size_t offset = 0; 48 49 memcpy(bytes.offset(offset), &event.wd, sizeof(InodeWatcherEvent::watch_descriptor)); 50 offset += sizeof(InodeWatcherEvent::watch_descriptor); 51 memcpy(bytes.offset(offset), &event.type, sizeof(InodeWatcherEvent::type)); 52 offset += sizeof(InodeWatcherEvent::type); 53 54 if (event.path) { 55 size_t name_length = event.path->length() + 1; 56 memcpy(bytes.offset(offset), &name_length, sizeof(InodeWatcherEvent::name_length)); 57 offset += sizeof(InodeWatcherEvent::name_length); 58 memcpy(bytes.offset(offset), event.path->characters(), name_length); 59 } else { 60 memset(bytes.offset(offset), 0, sizeof(InodeWatcherEvent::name_length)); 61 } 62 63 return bytes.size(); 64 }); 65 evaluate_block_conditions(); 66 return result; 67} 68 69ErrorOr<void> InodeWatcher::close() 70{ 71 MutexLocker locker(m_lock); 72 73 for (auto& entry : m_wd_to_watches) { 74 auto& inode = const_cast<Inode&>(entry.value->inode); 75 inode.unregister_watcher({}, *this); 76 } 77 78 m_wd_to_watches.clear(); 79 m_inode_to_watches.clear(); 80 return {}; 81} 82 83ErrorOr<NonnullOwnPtr<KString>> InodeWatcher::pseudo_path(OpenFileDescription const&) const 84{ 85 return KString::formatted("InodeWatcher:({})", m_wd_to_watches.size()); 86} 87 88void InodeWatcher::notify_inode_event(Badge<Inode>, InodeIdentifier inode_id, InodeWatcherEvent::Type event_type, StringView name) 89{ 90 MutexLocker locker(m_lock); 91 92 auto it = m_inode_to_watches.find(inode_id); 93 if (it == m_inode_to_watches.end()) 94 return; 95 96 auto& watcher = *it->value; 97 if (!(watcher.event_mask & static_cast<unsigned>(event_type))) 98 return; 99 100 OwnPtr<KString> path; 101 if (!name.is_null()) 102 path = KString::try_create(name).release_value_but_fixme_should_propagate_errors(); 103 m_queue.enqueue({ watcher.wd, event_type, move(path) }); 104 evaluate_block_conditions(); 105} 106 107ErrorOr<int> InodeWatcher::register_inode(Inode& inode, unsigned event_mask) 108{ 109 MutexLocker locker(m_lock); 110 111 if (m_inode_to_watches.find(inode.identifier()) != m_inode_to_watches.end()) 112 return EEXIST; 113 114 int wd; 115 do { 116 wd = m_wd_counter.value(); 117 118 m_wd_counter++; 119 if (m_wd_counter.has_overflow()) 120 m_wd_counter = 1; 121 } while (m_wd_to_watches.find(wd) != m_wd_to_watches.end()); 122 123 auto description = TRY(WatchDescription::create(wd, inode, event_mask)); 124 125 TRY(m_inode_to_watches.try_set(inode.identifier(), description.ptr())); 126 auto set_result = m_wd_to_watches.try_set(wd, move(description)); 127 if (set_result.is_error()) { 128 m_inode_to_watches.remove(inode.identifier()); 129 return set_result.release_error(); 130 } 131 132 auto register_result = inode.register_watcher({}, *this); 133 if (register_result.is_error()) { 134 m_inode_to_watches.remove(inode.identifier()); 135 m_wd_to_watches.remove(wd); 136 return register_result.release_error(); 137 } 138 139 return wd; 140} 141 142ErrorOr<void> InodeWatcher::unregister_by_wd(int wd) 143{ 144 MutexLocker locker(m_lock); 145 146 auto it = m_wd_to_watches.find(wd); 147 if (it == m_wd_to_watches.end()) 148 return ENOENT; 149 150 auto& inode = it->value->inode; 151 inode.unregister_watcher({}, *this); 152 153 m_inode_to_watches.remove(inode.identifier()); 154 m_wd_to_watches.remove(it); 155 156 return {}; 157} 158 159void InodeWatcher::unregister_by_inode(Badge<Inode>, InodeIdentifier identifier) 160{ 161 MutexLocker locker(m_lock); 162 163 auto it = m_inode_to_watches.find(identifier); 164 if (it == m_inode_to_watches.end()) 165 return; 166 167 // NOTE: no need to call unregister_watcher here, the Inode calls us. 168 169 m_inode_to_watches.remove(identifier); 170 m_wd_to_watches.remove(it->value->wd); 171} 172 173}