FileWatcher.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
  3. * Copyright (c) 2021-2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/ByteString.h>
  9. #include <AK/EnumBits.h>
  10. #include <AK/Function.h>
  11. #include <AK/Noncopyable.h>
  12. #include <AK/NonnullRefPtr.h>
  13. #include <AK/RefCounted.h>
  14. #include <LibCore/Notifier.h>
  15. namespace Core {
  16. struct FileWatcherEvent {
  17. enum class Type {
  18. Invalid = 0,
  19. MetadataModified = 1 << 0,
  20. ContentModified = 1 << 1,
  21. Deleted = 1 << 2,
  22. ChildCreated = 1 << 3,
  23. ChildDeleted = 1 << 4,
  24. };
  25. Type type { Type::Invalid };
  26. ByteString event_path;
  27. };
  28. AK_ENUM_BITWISE_OPERATORS(FileWatcherEvent::Type);
  29. enum class FileWatcherFlags : u32 {
  30. None = 0,
  31. Nonblock = 1 << 0,
  32. CloseOnExec = 1 << 1,
  33. };
  34. AK_ENUM_BITWISE_OPERATORS(FileWatcherFlags);
  35. class FileWatcherBase {
  36. public:
  37. virtual ~FileWatcherBase() = default;
  38. ErrorOr<bool> add_watch(ByteString path, FileWatcherEvent::Type event_mask);
  39. ErrorOr<bool> remove_watch(ByteString path);
  40. bool is_watching(ByteString const& path) const { return m_path_to_wd.find(path) != m_path_to_wd.end(); }
  41. protected:
  42. FileWatcherBase(int watcher_fd)
  43. : m_watcher_fd(watcher_fd)
  44. {
  45. }
  46. int m_watcher_fd { -1 };
  47. HashMap<ByteString, unsigned> m_path_to_wd;
  48. HashMap<unsigned, ByteString> m_wd_to_path;
  49. };
  50. class BlockingFileWatcher final : public FileWatcherBase {
  51. AK_MAKE_NONCOPYABLE(BlockingFileWatcher);
  52. public:
  53. explicit BlockingFileWatcher(FileWatcherFlags = FileWatcherFlags::None);
  54. ~BlockingFileWatcher();
  55. Optional<FileWatcherEvent> wait_for_event();
  56. };
  57. class FileWatcher : public FileWatcherBase
  58. , public RefCounted<FileWatcher> {
  59. AK_MAKE_NONCOPYABLE(FileWatcher);
  60. public:
  61. static ErrorOr<NonnullRefPtr<FileWatcher>> create(FileWatcherFlags = FileWatcherFlags::None);
  62. ~FileWatcher();
  63. Function<void(FileWatcherEvent const&)> on_change;
  64. protected:
  65. FileWatcher(int watcher_fd, NonnullRefPtr<Notifier>);
  66. NonnullRefPtr<Notifier> m_notifier;
  67. };
  68. }
  69. namespace AK {
  70. template<>
  71. struct Formatter<Core::FileWatcherEvent> : Formatter<FormatString> {
  72. ErrorOr<void> format(FormatBuilder& builder, Core::FileWatcherEvent const& value)
  73. {
  74. return Formatter<FormatString>::format(builder, "FileWatcherEvent(\"{}\", {})"sv, value.event_path, value.type);
  75. }
  76. };
  77. template<>
  78. struct Formatter<Core::FileWatcherEvent::Type> : Formatter<FormatString> {
  79. ErrorOr<void> format(FormatBuilder& builder, Core::FileWatcherEvent::Type const& value)
  80. {
  81. bool had_any_flag = false;
  82. auto put_string_if_has_flag = [&](auto mask, auto name) -> ErrorOr<void> {
  83. if (!has_flag(value, mask))
  84. return {};
  85. if (had_any_flag)
  86. TRY(builder.put_string(", "sv));
  87. TRY(builder.put_string(name));
  88. had_any_flag = true;
  89. return {};
  90. };
  91. TRY(builder.put_string("["sv));
  92. TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::ChildCreated, "ChildCreated"sv));
  93. TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::ChildDeleted, "ChildDeleted"sv));
  94. TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::Deleted, "Deleted"sv));
  95. TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::ContentModified, "ContentModified"sv));
  96. TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::MetadataModified, "MetadataModified"sv));
  97. TRY(builder.put_string("]"sv));
  98. VERIFY(had_any_flag);
  99. return {};
  100. }
  101. };
  102. }