Follow-on to the work done to allow Windows to work against network-mounted repos for macOS. Have macOS take advantage of the same configuration option, 'fsmonitor.allowRemote' that was introduced for Windows. Setting this option to true will override the default behavior (erroring-out) when a network-mounted repo is detected by fsmonitor. The added wrinkle being that the Unix domain socket (UDS) file used for IPC cannot be created in a network location; instead $HOME is used if the default location is on the network. The user may, optionally, set the 'fsmonitor.socketDir' configuration option to a valid, local directory if $HOME itself is on the network or is simply not the desired location for the UDS file. An additional issue is that for mount points in the root directory, FSEvents does not report a path that matches the worktree directory due to the introduction of 'synthetic firmlinks'. fsmonitor must map the FSEvents paths to the worktree directory by interrogating the root filesystem for synthetic firmlinks and using that information to translate the path. v14 differs from v13: * code review feedback v13 differs from v12: * code review feedback v12 differs from v11: * bug fixes v11 differs from v10: * incorporates code review feedback * fix memory leak in fsm-listen-darwin.c v10 differs from v9: * incorporates code review feedback * improves error messaging for incompatible socket directory v9 differs from v8: * incorporates code review feedback * check for incompatibility before communicating with fsmonitor v8 differs from v7: * incorporates code review feedback * gets the rebase right v7 differs from v6: * incorporates code review feedback v6 differs from v5: * incorporates earlier, Windows-specific changes that have not made it back yet to the master branch * incorporates code review feedback * adds documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir' v5 differs significantly from earlier versions: * redesign of handling 'fsmonitor.allowRemote' and 'fsmonitor.socketDir' such that these options are no longer added to the settings data structure but are rather read from config at point of use * refactoring of code for handling platform-specific file system checks via a common interface to avoid platform #ifdef in IPC code and be in-model with other platform-specific fsmonitor code * dealing with 'synthetic firmlinks' on macOS Eric DeCosta (6): fsmonitor: refactor filesystem checks to common interface fsmonitor: relocate socket file if .git directory is remote fsmonitor: avoid socket location check if using hook fsmonitor: deal with synthetic firmlinks on macOS fsmonitor: check for compatability before communicating with fsmonitor fsmonitor: add documentation for allowRemote and socketDir options Documentation/config.txt | 2 + Documentation/config/fsmonitor--daemon.txt | 11 ++ Documentation/git-fsmonitor--daemon.txt | 37 ++++- Makefile | 2 + builtin/fsmonitor--daemon.c | 11 +- compat/fsmonitor/fsm-ipc-darwin.c | 52 ++++++ compat/fsmonitor/fsm-ipc-win32.c | 9 ++ compat/fsmonitor/fsm-listen-darwin.c | 14 +- compat/fsmonitor/fsm-path-utils-darwin.c | 132 ++++++++++++++++ compat/fsmonitor/fsm-path-utils-win32.c | 145 +++++++++++++++++ compat/fsmonitor/fsm-settings-darwin.c | 72 +++------ compat/fsmonitor/fsm-settings-win32.c | 174 +-------------------- contrib/buildsystems/CMakeLists.txt | 4 + fsmonitor--daemon.h | 3 + fsmonitor-ipc.c | 18 +-- fsmonitor-ipc.h | 4 +- fsmonitor-path-utils.h | 57 +++++++ fsmonitor-settings.c | 68 +++++++- fsmonitor-settings.h | 4 +- fsmonitor.c | 7 + 20 files changed, 580 insertions(+), 246 deletions(-) create mode 100644 Documentation/config/fsmonitor--daemon.txt create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c create mode 100644 compat/fsmonitor/fsm-ipc-win32.c create mode 100644 compat/fsmonitor/fsm-path-utils-darwin.c create mode 100644 compat/fsmonitor/fsm-path-utils-win32.c create mode 100644 fsmonitor-path-utils.h base-commit: 2a7d63a2453e2c30353342a2c9385fa22a846987 Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v14 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v14 Pull-Request: https://github.com/gitgitgadget/git/pull/1326 Range-diff vs v13: 1: 0b9b64428c5 = 1: 0b9b64428c5 fsmonitor: refactor filesystem checks to common interface 2: 680d4c83f99 = 2: 680d4c83f99 fsmonitor: relocate socket file if .git directory is remote 3: 7987d0c1f33 = 3: 7987d0c1f33 fsmonitor: avoid socket location check if using hook 4: 324eb5acd85 ! 4: 241043b7c15 fsmonitor: deal with synthetic firmlinks on macOS @@ builtin/fsmonitor--daemon.c: static int fsmonitor_run_daemon(void) + strbuf_init(&state.alias.alias, 0); + strbuf_init(&state.alias.points_to, 0); -+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) { -+ err = error(_("could not get worktree alias")); ++ if ((err = fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias))) + goto done; -+ } + /* * We create and delete cookie files somewhere inside the .git @@ compat/fsmonitor/fsm-path-utils-darwin.c: int fsmonitor__is_fs_remote(const char +int fsmonitor__get_alias(const char *path, struct alias_info *info) +{ + DIR *dir; -+ int read; + int retval = -1; ++ const char *const root = "/"; ++ struct stat st; + struct dirent *de; + struct strbuf alias; -+ struct strbuf points_to; ++ struct strbuf points_to = STRBUF_INIT; + -+ dir = opendir("/"); -+ if (!dir) { -+ error_errno("opendir('/') failed"); -+ return -1; -+ } ++ dir = opendir(root); ++ if (!dir) ++ return error_errno(_("opendir('%s') failed"), root); + + strbuf_init(&alias, 256); + -+ /* no way of knowing what the link will resolve to, so MAXPATHLEN */ -+ strbuf_init(&points_to, MAXPATHLEN); -+ + while ((de = readdir(dir)) != NULL) { + strbuf_reset(&alias); -+ strbuf_addch(&alias, '/'); -+ strbuf_add(&alias, de->d_name, strlen(de->d_name)); ++ strbuf_addf(&alias, "%s%s", root, de->d_name); + -+ read = readlink(alias.buf, points_to.buf, MAXPATHLEN); -+ if (read > 0) { -+ strbuf_setlen(&points_to, read); -+ if ((!strncmp(points_to.buf, path, points_to.len)) -+ && path[points_to.len] == '/') { -+ strbuf_addbuf(&info->alias, &alias); -+ strbuf_addbuf(&info->points_to, &points_to); -+ trace_printf_key(&trace_fsmonitor, -+ "Found alias for '%s' : '%s' -> '%s'", -+ path, info->alias.buf, info->points_to.buf); -+ retval = 0; -+ goto done; -+ } -+ } else if (!read) { -+ BUG("readlink returned 0"); -+ } else if (errno != EINVAL) { /* Something other than not a link */ -+ error_errno("readlink('%s') failed", alias.buf); ++ if (lstat(alias.buf, &st) < 0) { ++ error_errno(_("lstat('%s') failed"), alias.buf); ++ goto done; ++ } ++ ++ if (!S_ISLNK(st.st_mode)) ++ continue; ++ ++ if (strbuf_readlink(&points_to, alias.buf, st.st_size) < 0) { ++ error_errno(_("strbuf_readlink('%s') failed"), alias.buf); ++ goto done; ++ } ++ ++ if (!strncmp(points_to.buf, path, points_to.len) && ++ (path[points_to.len] == '/')) { ++ strbuf_addbuf(&info->alias, &alias); ++ strbuf_addbuf(&info->points_to, &points_to); ++ trace_printf_key(&trace_fsmonitor, ++ "Found alias for '%s' : '%s' -> '%s'", ++ path, info->alias.buf, info->points_to.buf); ++ retval = 0; + goto done; + } + } + retval = 0; /* no alias */ + +done: -+ if (closedir(dir) < 0) -+ warning_errno("closedir('/') failed"); + strbuf_release(&alias); + strbuf_release(&points_to); ++ if (closedir(dir) < 0) ++ return error_errno(_("closedir('%s') failed"), root); + return retval; +} + 5: b1ea378dff7 = 5: d906debba5e fsmonitor: check for compatability before communicating with fsmonitor 6: 04f607b1f21 = 6: ed14fbd009e fsmonitor: add documentation for allowRemote and socketDir options -- gitgitgadget