InodeWatcher.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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. #include <Kernel/FileSystem/Inode.h>
  8. #include <Kernel/FileSystem/InodeWatcher.h>
  9. #include <Kernel/Process.h>
  10. namespace Kernel {
  11. ErrorOr<NonnullLockRefPtr<InodeWatcher>> InodeWatcher::try_create()
  12. {
  13. return adopt_nonnull_lock_ref_or_enomem(new (nothrow) InodeWatcher);
  14. }
  15. InodeWatcher::~InodeWatcher()
  16. {
  17. (void)close();
  18. }
  19. bool InodeWatcher::can_read(OpenFileDescription const&, u64) const
  20. {
  21. MutexLocker locker(m_lock);
  22. return !m_queue.is_empty();
  23. }
  24. ErrorOr<size_t> InodeWatcher::read(OpenFileDescription&, u64, UserOrKernelBuffer& buffer, size_t buffer_size)
  25. {
  26. MutexLocker locker(m_lock);
  27. if (m_queue.is_empty())
  28. // can_read will catch the blocking case.
  29. return EAGAIN;
  30. auto event = m_queue.dequeue();
  31. size_t bytes_to_write = sizeof(InodeWatcherEvent);
  32. if (event.path)
  33. bytes_to_write += event.path->length() + 1;
  34. if (buffer_size < bytes_to_write)
  35. return EINVAL;
  36. auto result = buffer.write_buffered<MAXIMUM_EVENT_SIZE>(bytes_to_write, [&](Bytes bytes) {
  37. size_t offset = 0;
  38. memcpy(bytes.offset(offset), &event.wd, sizeof(InodeWatcherEvent::watch_descriptor));
  39. offset += sizeof(InodeWatcherEvent::watch_descriptor);
  40. memcpy(bytes.offset(offset), &event.type, sizeof(InodeWatcherEvent::type));
  41. offset += sizeof(InodeWatcherEvent::type);
  42. if (event.path) {
  43. size_t name_length = event.path->length() + 1;
  44. memcpy(bytes.offset(offset), &name_length, sizeof(InodeWatcherEvent::name_length));
  45. offset += sizeof(InodeWatcherEvent::name_length);
  46. memcpy(bytes.offset(offset), event.path->characters(), name_length);
  47. } else {
  48. memset(bytes.offset(offset), 0, sizeof(InodeWatcherEvent::name_length));
  49. }
  50. return bytes.size();
  51. });
  52. evaluate_block_conditions();
  53. return result;
  54. }
  55. ErrorOr<void> InodeWatcher::close()
  56. {
  57. MutexLocker locker(m_lock);
  58. for (auto& entry : m_wd_to_watches) {
  59. auto& inode = const_cast<Inode&>(entry.value->inode);
  60. inode.unregister_watcher({}, *this);
  61. }
  62. m_wd_to_watches.clear();
  63. m_inode_to_watches.clear();
  64. return {};
  65. }
  66. ErrorOr<NonnullOwnPtr<KString>> InodeWatcher::pseudo_path(OpenFileDescription const&) const
  67. {
  68. return KString::formatted("InodeWatcher:({})", m_wd_to_watches.size());
  69. }
  70. void InodeWatcher::notify_inode_event(Badge<Inode>, InodeIdentifier inode_id, InodeWatcherEvent::Type event_type, StringView name)
  71. {
  72. MutexLocker locker(m_lock);
  73. auto it = m_inode_to_watches.find(inode_id);
  74. if (it == m_inode_to_watches.end())
  75. return;
  76. auto& watcher = *it->value;
  77. if (!(watcher.event_mask & static_cast<unsigned>(event_type)))
  78. return;
  79. OwnPtr<KString> path;
  80. if (!name.is_null())
  81. path = KString::try_create(name).release_value_but_fixme_should_propagate_errors();
  82. m_queue.enqueue({ watcher.wd, event_type, move(path) });
  83. evaluate_block_conditions();
  84. }
  85. ErrorOr<int> InodeWatcher::register_inode(Inode& inode, unsigned event_mask)
  86. {
  87. MutexLocker locker(m_lock);
  88. if (m_inode_to_watches.find(inode.identifier()) != m_inode_to_watches.end())
  89. return EEXIST;
  90. int wd;
  91. do {
  92. wd = m_wd_counter.value();
  93. m_wd_counter++;
  94. if (m_wd_counter.has_overflow())
  95. m_wd_counter = 1;
  96. } while (m_wd_to_watches.find(wd) != m_wd_to_watches.end());
  97. auto description = TRY(WatchDescription::create(wd, inode, event_mask));
  98. TRY(m_inode_to_watches.try_set(inode.identifier(), description.ptr()));
  99. auto set_result = m_wd_to_watches.try_set(wd, move(description));
  100. if (set_result.is_error()) {
  101. m_inode_to_watches.remove(inode.identifier());
  102. return set_result.release_error();
  103. }
  104. auto register_result = inode.register_watcher({}, *this);
  105. if (register_result.is_error()) {
  106. m_inode_to_watches.remove(inode.identifier());
  107. m_wd_to_watches.remove(wd);
  108. return register_result.release_error();
  109. }
  110. return wd;
  111. }
  112. ErrorOr<void> InodeWatcher::unregister_by_wd(int wd)
  113. {
  114. MutexLocker locker(m_lock);
  115. auto it = m_wd_to_watches.find(wd);
  116. if (it == m_wd_to_watches.end())
  117. return ENOENT;
  118. auto& inode = it->value->inode;
  119. inode.unregister_watcher({}, *this);
  120. m_inode_to_watches.remove(inode.identifier());
  121. m_wd_to_watches.remove(it);
  122. return {};
  123. }
  124. void InodeWatcher::unregister_by_inode(Badge<Inode>, InodeIdentifier identifier)
  125. {
  126. MutexLocker locker(m_lock);
  127. auto it = m_inode_to_watches.find(identifier);
  128. if (it == m_inode_to_watches.end())
  129. return;
  130. // NOTE: no need to call unregister_watcher here, the Inode calls us.
  131. m_inode_to_watches.remove(identifier);
  132. m_wd_to_watches.remove(it->value->wd);
  133. }
  134. }