From 8db3dcc8d0cbe8b1f6a40df835ec9cb0d4a13e84 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <vital.had@gmail.com>
Date: Tue, 2 Dec 2025 20:48:56 +0800
Subject: [PATCH] wt-monitor-macos.c: support < 10.7

---
 daemon/wt-monitor-macos.c | 97 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/daemon/wt-monitor-macos.c b/daemon/wt-monitor-macos.c
index 5deec4f6..f53017a5 100644
--- a/daemon/wt-monitor-macos.c
+++ b/daemon/wt-monitor-macos.c
@@ -1,6 +1,13 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 #include "common.h"
 
+#include <AvailabilityMacros.h>
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+#define USE_LEGACY_FSEVENT_API
+typedef char uuid_string_t[37];
+#endif
+
 #include <CoreServices/CoreServices.h>
 #include <sys/event.h>
 
@@ -18,6 +25,42 @@
 
 #define RENAME_EXPIRE_TIME 10
 
+#ifndef kFSEventStreamCreateFlagFileEvents
+#define kFSEventStreamCreateFlagFileEvents 0x00000010
+#endif
+
+#ifndef kFSEventStreamEventFlagItemIsFile
+#define kFSEventStreamEventFlagItemIsFile 0x00010000
+#endif
+
+#ifndef kFSEventStreamEventFlagItemIsDir
+#define kFSEventStreamEventFlagItemIsDir 0x00020000
+#endif
+
+#ifndef kFSEventStreamEventFlagItemIsSymlink
+#define kFSEventStreamEventFlagItemIsSymlink 0x00040000
+#endif
+
+#ifndef kFSEventStreamEventFlagItemCreated
+#define kFSEventStreamEventFlagItemCreated 0x00000100
+#endif
+
+#ifndef kFSEventStreamEventFlagItemRemoved
+#define kFSEventStreamEventFlagItemRemoved 0x00000200
+#endif
+
+#ifndef kFSEventStreamEventFlagItemModified
+#define kFSEventStreamEventFlagItemModified 0x00001000
+#endif
+
+#ifndef kFSEventStreamEventFlagItemRenamed
+#define kFSEventStreamEventFlagItemRenamed 0x00000800
+#endif
+
+#ifndef kFSEventStreamEventFlagItemXattrMod
+#define kFSEventStreamEventFlagItemXattrMod 0x00008000
+#endif
+
 typedef struct RenameInfo {
     char *old_path;
     char *old_event_path;
@@ -157,6 +200,7 @@ check_and_handle_rename (WTStatus *status, RenameInfo *rename_info,
     unset_rename_processing_state (rename_info);
 }
 
+#ifndef USE_LEGACY_FSEVENT_API
 static void
 handle_rename (RepoWatchInfo *info,
                const FSEventStreamEventFlags eventFlags,
@@ -215,6 +259,7 @@ handle_rename (RepoWatchInfo *info,
         }
     }
 }
+#endif
 
 static void
 add_event_to_queue (WTStatus *status,
@@ -273,6 +318,39 @@ add_event_to_queue (WTStatus *status,
     }
 }
 
+#ifdef USE_LEGACY_FSEVENT_API
+static void
+process_one_event_legacy (const char* eventPath,
+                         RepoWatchInfo *info,
+                         const char *worktree,
+                         const FSEventStreamEventId eventId,
+                         const FSEventStreamEventFlags eventFlags)
+{
+    WTStatus *status = info->status;
+    char *dirname;
+    char *event_path_nfc;
+    const char *tmp;
+
+    event_path_nfc = g_utf8_normalize (eventPath, -1, G_NORMALIZE_NFC);
+
+    tmp = event_path_nfc + strlen(worktree);
+    if (*tmp == '/')
+        tmp++;
+    dirname = g_strdup(tmp);
+    g_free (event_path_nfc);
+
+    /* Path for folder returned from system may contain a '/' at the end.  */
+    int len = strlen(dirname);
+    if (len > 0 && dirname[len - 1] == '/')
+        dirname[len - 1] = 0;
+
+    seaf_debug ("Event in dir: %s \n", dirname);
+    add_event_to_queue (status, WT_EVENT_CREATE_OR_UPDATE, dirname, NULL);
+
+    g_free (dirname);
+    g_atomic_int_set (&info->status->last_changed, (gint)time(NULL));
+}
+#else
 static void
 process_one_event (const char* eventPath,
                    RepoWatchInfo *info,
@@ -347,6 +425,7 @@ process_one_event (const char* eventPath,
     g_free (filename);
     g_atomic_int_set (&info->status->last_changed, (gint)time(NULL));
 }
+#endif
 
 #if 0
 static void
@@ -418,8 +497,13 @@ stream_callback (ConstFSEventStreamRef streamRef,
     for (i = 0; i < numEvents; i++) {
         seaf_debug("%ld Change %llu in %s, flags %x\n", (long)CFRunLoopGetCurrent(),
                    eventIds[i], paths[i], eventFlags[i]);
+#ifdef USE_LEGACY_FSEVENT_API
+        process_one_event_legacy (paths[i], info, info->worktree,
+                                  eventIds[i], eventFlags[i]);
+#else
         process_one_event (paths[i], info, info->worktree,
                            eventIds[i], eventFlags[i], i==(numEvents - 1));
+#endif
     }
 }
 
@@ -443,6 +527,18 @@ add_watch (SeafWTMonitor *monitor, const char* repo_id, const char* worktree)
     // kFSEventStreamCreateFlagFileEvents does not work for libraries with name
     // containing accent characters.
     struct FSEventStreamContext ctx = {0, monitor, NULL, NULL, NULL};
+
+#ifdef USE_LEGACY_FSEVENT_API
+    /* macOS < 10.7 - directory-level monitoring */
+    stream = FSEventStreamCreate(kCFAllocatorDefault,
+                                 stream_callback,
+                                 &ctx,
+                                 pathsToWatch,
+                                 kFSEventStreamEventIdSinceNow,
+                                 latency,
+                                 kFSEventStreamCreateFlagNone
+                                 );
+#else
     stream = FSEventStreamCreate(kCFAllocatorDefault,
                                  stream_callback,
                                  &ctx,
@@ -451,6 +547,7 @@ add_watch (SeafWTMonitor *monitor, const char* repo_id, const char* worktree)
                                  latency,
                                  kFSEventStreamCreateFlagFileEvents
                                  );
+#endif
 
     CFRelease (mypaths[0]);
     CFRelease (pathsToWatch);
