Serenity Operating System
at master 131 lines 3.7 kB view raw
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 8#pragma once 9 10#include <AK/DeprecatedString.h> 11#include <AK/EnumBits.h> 12#include <AK/Function.h> 13#include <AK/Noncopyable.h> 14#include <AK/NonnullRefPtr.h> 15#include <AK/RefCounted.h> 16#include <LibCore/Notifier.h> 17 18namespace Core { 19 20struct FileWatcherEvent { 21 enum class Type { 22 Invalid = 0, 23 MetadataModified = 1 << 0, 24 ContentModified = 1 << 1, 25 Deleted = 1 << 2, 26 ChildCreated = 1 << 3, 27 ChildDeleted = 1 << 4, 28 }; 29 Type type { Type::Invalid }; 30 DeprecatedString event_path; 31}; 32 33AK_ENUM_BITWISE_OPERATORS(FileWatcherEvent::Type); 34 35enum class FileWatcherFlags : u32 { 36 None = 0, 37 Nonblock = 1 << 0, 38 CloseOnExec = 1 << 1, 39}; 40 41AK_ENUM_BITWISE_OPERATORS(FileWatcherFlags); 42 43class FileWatcherBase { 44public: 45 virtual ~FileWatcherBase() = default; 46 47 ErrorOr<bool> add_watch(DeprecatedString path, FileWatcherEvent::Type event_mask); 48 ErrorOr<bool> remove_watch(DeprecatedString path); 49 bool is_watching(DeprecatedString const& path) const { return m_path_to_wd.find(path) != m_path_to_wd.end(); } 50 51protected: 52 FileWatcherBase(int watcher_fd) 53 : m_watcher_fd(watcher_fd) 54 { 55 } 56 57 int m_watcher_fd { -1 }; 58 HashMap<DeprecatedString, unsigned> m_path_to_wd; 59 HashMap<unsigned, DeprecatedString> m_wd_to_path; 60}; 61 62class BlockingFileWatcher final : public FileWatcherBase { 63 AK_MAKE_NONCOPYABLE(BlockingFileWatcher); 64 65public: 66 explicit BlockingFileWatcher(FileWatcherFlags = FileWatcherFlags::None); 67 ~BlockingFileWatcher(); 68 69 Optional<FileWatcherEvent> wait_for_event(); 70}; 71 72class FileWatcher : public FileWatcherBase 73 , public RefCounted<FileWatcher> { 74 AK_MAKE_NONCOPYABLE(FileWatcher); 75 76public: 77 static ErrorOr<NonnullRefPtr<FileWatcher>> create(FileWatcherFlags = FileWatcherFlags::None); 78 ~FileWatcher(); 79 80 Function<void(FileWatcherEvent const&)> on_change; 81 82protected: 83 FileWatcher(int watcher_fd, NonnullRefPtr<Notifier>); 84 85 NonnullRefPtr<Notifier> m_notifier; 86}; 87 88} 89 90namespace AK { 91 92template<> 93struct Formatter<Core::FileWatcherEvent> : Formatter<FormatString> { 94 ErrorOr<void> format(FormatBuilder& builder, Core::FileWatcherEvent const& value) 95 { 96 return Formatter<FormatString>::format(builder, "FileWatcherEvent(\"{}\", {})"sv, value.event_path, value.type); 97 } 98}; 99 100template<> 101struct Formatter<Core::FileWatcherEvent::Type> : Formatter<FormatString> { 102 ErrorOr<void> format(FormatBuilder& builder, Core::FileWatcherEvent::Type const& value) 103 { 104 bool had_any_flag = false; 105 106 auto put_string_if_has_flag = [&](auto mask, auto name) -> ErrorOr<void> { 107 if (!has_flag(value, mask)) 108 return {}; 109 110 if (had_any_flag) 111 TRY(builder.put_string(", "sv)); 112 TRY(builder.put_string(name)); 113 114 had_any_flag = true; 115 return {}; 116 }; 117 118 TRY(builder.put_string("["sv)); 119 TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::ChildCreated, "ChildCreated"sv)); 120 TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::ChildDeleted, "ChildDeleted"sv)); 121 TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::Deleted, "Deleted"sv)); 122 TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::ContentModified, "ContentModified"sv)); 123 TRY(put_string_if_has_flag(Core::FileWatcherEvent::Type::MetadataModified, "MetadataModified"sv)); 124 TRY(builder.put_string("]"sv)); 125 126 VERIFY(had_any_flag); 127 return {}; 128 } 129}; 130 131}