Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CloseWrite event flag (inotify, kqueue): file open for write has been closed. #331

2 changes: 2 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \
fi \
&& rm -f /tmp/reinstall-cmake.sh

RUN apt-get update && apt-get install -y nodejs npm

# [Optional] Uncomment this section to install additional vcpkg ports.
# RUN su vscode -c "${VCPKG_ROOT}/vcpkg install <your-port-name-here>"

Expand Down
1 change: 1 addition & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"extensions": [
"sonarsource.sonarlint-vscode",
"ms-vscode.cpptools-themes",
"ms-vscode.cpptools-extension-pack",
"maelvalais.autoconf",
"eamodio.gitlens"
]
Expand Down
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2014-2024 Enrico M. Crisostomo
# Copyright (c) 2014-2025 Enrico M. Crisostomo
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
Expand All @@ -14,12 +14,12 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
#
cmake_minimum_required(VERSION 3.14)
project(fswatch VERSION 1.18.0 LANGUAGES C CXX)
project(fswatch VERSION 1.19.0 LANGUAGES C CXX)

#@formatter:off
set(PACKAGE "${PROJECT_NAME}")
set(PACKAGE_NAME "${PACKAGE}")
set(PACKAGE_VERSION "${PROJECT_VERSION}")
set(PACKAGE_VERSION "${PROJECT_VERSION}-develop")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_AUTHOR "[email protected]")
set(PACKAGE_BUGREPORT "${PACKAGE_AUTHOR}")
Expand Down
10 changes: 10 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
NEWS
****

New in current-develop:

* Added event flag CloseWrite: file open for write has been closed.

* kqueue_monitor: added support for CloseWrite, adding support for events of
type NOTE_CLOSE_WRITE.

* inotify_monitor: added support for CloseWrite, adding support for events of
type IN_CLOSE_WRITE.

New in 1.18.0:

* The C++17 standard has been adopted: code has been rewritten and simplified
Expand Down
6 changes: 4 additions & 2 deletions libfswatch/src/libfswatch/c++/event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ namespace fsw
FSW_MAKE_PAIR_FROM_NAME(IsDir),
FSW_MAKE_PAIR_FROM_NAME(IsSymLink),
FSW_MAKE_PAIR_FROM_NAME(Link),
FSW_MAKE_PAIR_FROM_NAME(Overflow)
FSW_MAKE_PAIR_FROM_NAME(Overflow),
FSW_MAKE_PAIR_FROM_NAME(CloseWrite)
};
#undef FSW_MAKE_PAIR_FROM_NAME

Expand Down Expand Up @@ -102,7 +103,8 @@ namespace fsw
FSW_MAKE_PAIR_FROM_NAME(IsDir),
FSW_MAKE_PAIR_FROM_NAME(IsSymLink),
FSW_MAKE_PAIR_FROM_NAME(Link),
FSW_MAKE_PAIR_FROM_NAME(Overflow)
FSW_MAKE_PAIR_FROM_NAME(Overflow),
FSW_MAKE_PAIR_FROM_NAME(CloseWrite)
};
#undef FSW_MAKE_PAIR_FROM_NAME

Expand Down
32 changes: 19 additions & 13 deletions libfswatch/src/libfswatch/c++/inotify_monitor.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2024 Enrico M. Crisostomo
* Copyright (c) 2014-2025 Enrico M. Crisostomo
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
Expand Down Expand Up @@ -137,6 +137,11 @@ namespace fsw
{
auto status = std::filesystem::symlink_status(path);

if (!std::filesystem::exists(status))
{
return;
}

// Check if the path is a symbolic link
if (follow_symlinks && std::filesystem::is_symlink(status))
{
Expand Down Expand Up @@ -195,6 +200,16 @@ namespace fsw

if (event->mask & IN_ISDIR) flags.push_back(fsw_event_flag::IsDir);
if (event->mask & IN_MOVE_SELF) flags.push_back(fsw_event_flag::Updated);
if (event->mask & IN_MOVED_FROM)
{
flags.push_back(fsw_event_flag::Removed);
flags.push_back(fsw_event_flag::MovedFrom);
}
if (event->mask & IN_MOVED_TO)
{
flags.push_back(fsw_event_flag::Created);
flags.push_back(fsw_event_flag::MovedTo);
}
if (event->mask & IN_UNMOUNT) flags.push_back(fsw_event_flag::PlatformSpecific);

if (!flags.empty())
Expand All @@ -216,20 +231,11 @@ namespace fsw
if (event->mask & IN_ACCESS) flags.push_back(fsw_event_flag::PlatformSpecific);
if (event->mask & IN_ATTRIB) flags.push_back(fsw_event_flag::AttributeModified);
if (event->mask & IN_CLOSE_NOWRITE) flags.push_back(fsw_event_flag::PlatformSpecific);
if (event->mask & IN_CLOSE_WRITE) flags.push_back(fsw_event_flag::Updated);
if (event->mask & IN_CLOSE_WRITE) flags.push_back(fsw_event_flag::CloseWrite);
if (event->mask & IN_CREATE) flags.push_back(fsw_event_flag::Created);
if (event->mask & IN_DELETE) flags.push_back(fsw_event_flag::Removed);
if (event->mask & IN_DELETE_SELF) flags.push_back(fsw_event_flag::Removed);
if (event->mask & IN_MODIFY) flags.push_back(fsw_event_flag::Updated);
if (event->mask & IN_MOVED_FROM)
{
flags.push_back(fsw_event_flag::Removed);
flags.push_back(fsw_event_flag::MovedFrom);
}
if (event->mask & IN_MOVED_TO)
{
flags.push_back(fsw_event_flag::Created);
flags.push_back(fsw_event_flag::MovedTo);
}
if (event->mask & IN_OPEN) flags.push_back(fsw_event_flag::PlatformSpecific);

// Build the file name.
Expand Down Expand Up @@ -276,7 +282,7 @@ namespace fsw
* unnoticed when a watched file x is removed and a new file named x is
* created thereafter. In this case, fswatch could be blocked on read and
* it would not have any chance to create a new watch descriptor for x until
* an event is received and read unblocks.
* an event is received and read unblocks.
*/
if (event->mask & IN_MOVE_SELF)
{
Expand Down
23 changes: 18 additions & 5 deletions libfswatch/src/libfswatch/c++/kqueue_monitor.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2024 Enrico M. Crisostomo
* Copyright (c) 2014-2025 Enrico M. Crisostomo
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
Expand Down Expand Up @@ -81,6 +81,9 @@ namespace fsw
static std::vector<KqueueFlagType> create_flag_type_vector()
{
std::vector<KqueueFlagType> flags;
#ifdef NOTE_CLOSE_WRITE
flags.push_back({NOTE_CLOSE_WRITE, fsw_event_flag::CloseWrite});
#endif
flags.push_back({NOTE_DELETE, fsw_event_flag::Removed});
flags.push_back({NOTE_WRITE, fsw_event_flag::Updated});
flags.push_back({NOTE_EXTEND, fsw_event_flag::PlatformSpecific});
Expand Down Expand Up @@ -180,6 +183,11 @@ namespace fsw
{
const auto status = std::filesystem::symlink_status(path);

if (!std::filesystem::exists(status))
{
return;
}

// Check if the path is a symbolic link
if (follow_symlinks && std::filesystem::is_symlink(status))
{
Expand Down Expand Up @@ -391,14 +399,19 @@ namespace fsw
{
struct kevent change{};

// TODO: update the flags to be monitored
// TODO: there is a use case for NOTE_CLOSE_WRITE which can be used to
// monitor for file changes in a more efficient way.
// Set the flags to be monitored
int flags = NOTE_DELETE | NOTE_EXTEND | NOTE_RENAME | NOTE_WRITE | NOTE_ATTRIB | NOTE_LINK | NOTE_REVOKE;

// Conditionally include NOTE_CLOSE_WRITE if it is defined
#ifdef NOTE_CLOSE_WRITE
flags |= NOTE_CLOSE_WRITE;
#endif

EV_SET(&change,
key,
EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_CLEAR,
NOTE_DELETE | NOTE_EXTEND | NOTE_RENAME | NOTE_WRITE | NOTE_ATTRIB | NOTE_LINK | NOTE_REVOKE,
flags,
0,
0);

Expand Down
7 changes: 2 additions & 5 deletions libfswatch/src/libfswatch/c++/monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ monitor::~monitor()
for (;;)
{
{
std::unique_lock<std::mutex> run_guard(mon->run_mutex);
std::unique_lock run_guard(mon->run_mutex);
if (mon->should_stop) break;
}

Expand Down Expand Up @@ -367,11 +367,8 @@ monitor::~monitor()
}

filtered_events.clear();
for (auto const& evt : bubbled_events)
for (const auto& [bubble_key, flags] : bubbled_events)
{
auto const& bubble_key = evt.first;
auto const& flags = evt.second;

std::vector<fsw_event_flag> bubbled_flags(flags.size());
std::move(flags.begin(), flags.end(), bubbled_flags.begin());

Expand Down
9 changes: 8 additions & 1 deletion libfswatch/src/libfswatch/c++/poll_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,15 @@ namespace fsw
{
try
{
auto status = std::filesystem::symlink_status(path);

if (!std::filesystem::exists(status))
{
return;
}

// Check if the path is a symbolic link
if (follow_symlinks && std::filesystem::is_symlink(std::filesystem::symlink_status(path)))
if (follow_symlinks && std::filesystem::is_symlink(status))
{
auto link_path = std::filesystem::read_symlink(path);
scan(link_path, fn);
Expand Down
5 changes: 3 additions & 2 deletions libfswatch/src/libfswatch/c/cevent.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2021 Enrico M. Crisostomo
* Copyright (c) 2015-2025 Enrico M. Crisostomo
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
Expand Down Expand Up @@ -38,7 +38,8 @@ const fsw_event_flag FSW_ALL_EVENT_FLAGS[] =
IsDir,
IsSymLink,
Link,
Overflow
Overflow,
CloseWrite
};

FSW_STATUS fsw_get_event_flag_by_name(const char *name, fsw_event_flag *flag)
Expand Down
10 changes: 6 additions & 4 deletions libfswatch/src/libfswatch/c/cevent.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2015 Enrico M. Crisostomo
* Copyright (c) 2014-2025 Enrico M. Crisostomo
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
Expand All @@ -22,7 +22,8 @@
* @copyright Copyright (c) 2014-2015 Enrico M. Crisostomo
* @license GNU General Public License v. 3.0
* @author Enrico M. Crisostomo
* @version 1.8.0
* @version 13:1:0
* TODO: Update version number reflecting changes of the API.
*/
#ifndef FSW__CEVENT_H
# define FSW__CEVENT_H
Expand Down Expand Up @@ -76,10 +77,11 @@ extern "C"
IsDir = (1 << 10), /**< The object is a directory. */
IsSymLink = (1 << 11), /**< The object is a symbolic link. */
Link = (1 << 12), /**< The link count of an object has changed. */
Overflow = (1 << 13) /**< The event queue has overflowed. */
Overflow = (1 << 13), /**< The event queue has overflowed. */
CloseWrite = (1 << 14) /**< A file was closed after being opened in write mode. */
};

extern const enum fsw_event_flag FSW_ALL_EVENT_FLAGS[15];
extern const enum fsw_event_flag FSW_ALL_EVENT_FLAGS[16];

/**
* @brief Get event flag by name.
Expand Down
4 changes: 2 additions & 2 deletions m4/fswatch_version.m4
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2014-2024 Enrico M. Crisostomo
# Copyright (c) 2014-2025 Enrico M. Crisostomo
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
Expand All @@ -13,5 +13,5 @@
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
#
m4_define([FSWATCH_VERSION], [1.18.0])
m4_define([FSWATCH_VERSION], [1.19.0-develop])
m4_define([FSWATCH_REVISION], [1])
4 changes: 2 additions & 2 deletions m4/libfswatch_version.m4
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2014-2024 Enrico M. Crisostomo
# Copyright (c) 2014-2025 Enrico M. Crisostomo
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
Expand Down Expand Up @@ -37,6 +37,6 @@
#
# Libtool documentation, 7.3 Updating library version information
#
m4_define([LIBFSWATCH_VERSION], [1.18.0])
m4_define([LIBFSWATCH_VERSION], [1.19.0-develop])
m4_define([LIBFSWATCH_API_VERSION], [13:1:0])
m4_define([LIBFSWATCH_REVISION], [1])
Loading