e-dant / watcher

Filesystem watcher. Works anywhere. Simple, efficient and friendly.
MIT License
639 stars 32 forks source link

[macOS] Sometimes the path is not available in a change event. #47

Closed atishay closed 1 month ago

atishay commented 1 month ago

Problem

The file path in the watch event is coming out to be null for certain file operations on macOS.

Details

The API used in the code https://github.com/e-dant/watcher/blob/release/devel/include/detail/wtr/watcher/adapter/darwin/watch.hpp#L114 is CFStringGetCStringPtr

The official documentation clearly states that this method may return null if the internal implementation in macOS cannot provide a no allocation pointer and should not be relied on.

https://developer.apple.com/documentation/corefoundation/1542133-cfstringgetcstringptr?language=objc

Alternate function that works for me:

inline auto path_from_event_at(void* event_recv_paths, unsigned long i)
  -> std::filesystem::path
{
  if (event_recv_paths)
    if (
      void const* from_arr = CFArrayGetValueAtIndex(
        static_cast<CFArrayRef>(event_recv_paths),
        static_cast<CFIndex>(i)))
      if (
        void const* from_dict = CFDictionaryGetValue(
          static_cast<CFDictionaryRef>(from_arr),
          kFSEventStreamEventExtendedDataPathKey)) {

        auto cfString = static_cast<CFStringRef>(from_dict);

        CFIndex length = CFStringGetLength(cfString);
        CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
        char *buffer = new char[static_cast<size_t>(maxSize)];

        if (CFStringGetCString(cfString, buffer, maxSize, kCFStringEncodingUTF8)) {
            std::string result(buffer);
            delete[] buffer;
            return result;
        } else {
            delete[] buffer;
            return std::string(); // Return an empty string if conversion fails
        }
    }

  return {};
}
e-dant commented 1 month ago

While I don't doubt that this is a bug (and we'll fix it), I'm very curious the story behind how you stumbled across it.

e-dant commented 1 month ago

Should be fixed around here: https://github.com/e-dant/watcher/commit/d9d9d8ba0d8019cf9ab1b90f9139e3630b1b9f22#diff-5e556a082ae9130c476cd18ad3e9e7fba7ca7ff2b18810917c7550e1964ce84eL101-R107 and https://github.com/e-dant/watcher/commit/d9d9d8ba0d8019cf9ab1b90f9139e3630b1b9f22#diff-5e556a082ae9130c476cd18ad3e9e7fba7ca7ff2b18810917c7550e1964ce84eL29-R30

Thank you