* [PATCH v5 1/4] fsmonitor: refactor filesystem checks to common interface
2022-09-10 20:00 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
@ 2022-09-10 20:00 ` Eric DeCosta via GitGitGadget
2022-09-10 20:00 ` [PATCH v5 2/4] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-10 20:00 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 +++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 89 +++++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 ++++----------
compat/fsmonitor/fsm-settings-win32.c | 104 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++++
fsmonitor-settings.c | 50 +++++++++++
8 files changed, 224 insertions(+), 147 deletions(-)
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
diff --git a/Makefile b/Makefile
index 924b864ae83..265fc585286 100644
--- a/Makefile
+++ b/Makefile
@@ -2042,6 +2042,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..dc211de514f
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,89 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE)
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index 907655720bb..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,103 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -129,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2237109b57f..b88494bf59b 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v5 2/4] fsmonitor: relocate socket file if .git directory is remote
2022-09-10 20:00 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-10 20:00 ` [PATCH v5 1/4] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-10 20:00 ` Eric DeCosta via GitGitGadget
2022-09-10 20:00 ` [PATCH v5 3/4] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-10 20:00 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote file system, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-ipc-darwin.c | 46 +++++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 4 +++
contrib/buildsystems/CMakeLists.txt | 2 ++
fsmonitor-ipc.c | 2 --
5 files changed, 53 insertions(+), 2 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index 265fc585286..cf9c51040a0 100644
--- a/Makefile
+++ b/Makefile
@@ -2037,6 +2037,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..afaca96dab9
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,46 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(void)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
+ char *sock_dir;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (ipc_path)
+ return ipc_path;
+
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
+ return ipc_path;
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, the_repository->worktree, strlen(the_repository->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(the_repository, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir)
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ else
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..769a88639f6
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,4 @@
+#include "cache.h"
+#include "fsmonitor-ipc.h"
+
+GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index b88494bf59b..7e7b6b9a362 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..caad2e246a0 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -47,8 +47,6 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
return ipc_get_active_state(fsmonitor_ipc__get_path());
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v5 3/4] fsmonitor: avoid socket location check if using hook
2022-09-10 20:00 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-10 20:00 ` [PATCH v5 1/4] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-10 20:00 ` [PATCH v5 2/4] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-10 20:00 ` Eric DeCosta via GitGitGadget
2022-09-10 20:00 ` [PATCH v5 4/4] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-10 20:00 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..3463c71763e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v5 4/4] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-10 20:00 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-10 20:00 ` [PATCH v5 3/4] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-10 20:00 ` Eric DeCosta via GitGitGadget
2022-09-11 1:01 ` Eric Sunshine
2022-09-12 15:27 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Junio C Hamano
` (2 subsequent siblings)
6 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-10 20:00 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path invloves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 91 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 6 ++
fsmonitor-path-utils.h | 26 +++++++
6 files changed, 153 insertions(+), 1 deletion(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..2559150d9e7 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ 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"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..179886bc15b 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -209,7 +210,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ path_k = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (!path_k)
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +241,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..1f1550c485a 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,91 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogteher.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR * dir;
+ int read;
+ int retval;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ retval = 0;
+ dir = opendir("/");
+ if (!dir)
+ return -1;
+
+ strbuf_init(&alias, 256);
+ 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));
+
+ 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) == 0)
+ && 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 (errno != EINVAL) { /* Something other than not a link */
+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
+ retval = -1;
+ goto done;
+ }
+ }
+
+ done:
+ closedir(dir);
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ int len = info->alias.len;
+
+ if (!len)
+ return NULL;
+
+ if ((strncmp(info->alias.buf, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
+ int rem_len = strlen(remainder);
+
+ strbuf_init(&tmp, info->points_to.len + rem_len);
+ strbuf_addbuf(&tmp, &info->points_to);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index dc211de514f..0ca366bfe08 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -87,3 +87,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..98cbb430083 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
@@ -167,5 +170,8 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state,
*/
void fsmonitor_force_resync(struct fsmonitor_daemon_state *state);
+char *fsmonitor_resolve_alias(const char *path,
+ struct alias_info *alias);
+
#endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
#endif /* FSMONITOR_DAEMON_H */
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..7d9d71cb043 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,6 +1,14 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ struct strbuf alias;
+ struct strbuf points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
@@ -20,4 +28,22 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * Returns -1 on error, 0 otherwise.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v5 4/4] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-10 20:00 ` [PATCH v5 4/4] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-11 1:01 ` Eric Sunshine
0 siblings, 0 replies; 170+ messages in thread
From: Eric Sunshine @ 2022-09-11 1:01 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: Git List, Jeff Hostetler, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On Sat, Sep 10, 2022 at 4:00 PM Eric DeCosta via GitGitGadget
<gitgitgadget@gmail.com> wrote:
> Starting with macOS 10.15 (Catalina), Apple introduced a new feature
> called 'firmlinks' in order to separate the boot volume into two
> volumes, one read-only and one writable but still present them to the
> user as a single volume. Along with this change, Apple removed the
> ability to create symlinks in the root directory and replaced them with
> 'synthetic firmlinks'. See 'man synthetic.conf'
>
> When FSEevents reports the path of changed files, if the path invloves
> a synthetic firmlink, the path is reported from the point of the
> synthetic firmlink and not the real path. For example:
s/invloves/involves/
> Real path:
> /System/Volumes/Data/network/working/directory/foo.txt
>
> Synthetic firmlink:
> /network -> /System/Volumes/Data/network
>
> FSEvents path:
> /network/working/directory/foo.txt
>
> This causes the FSEvents path to not match against the worktree
> directory.
>
> There are several ways in which synthetic firmlinks can be created:
> they can be defined in /etc/synthetic.conf, the automounter can create
> them, and there may be other means. Simply reading /etc/synthetic.conf
> is insufficient. No matter what process creates synthetic firmlinks,
> they all get created in the root directory.
>
> Therefore, in order to deal with synthetic firmlinks, the root directory
> is scanned and the first possible synthetic firmink that, when resolved,
> is a prefix of the worktree is used to map FSEvents paths to worktree
> paths.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
> @@ -38,3 +41,91 @@ int fsmonitor__is_fs_remote(const char *path)
> +/*
> + * Scan the root directory for synthetic firmlinks that when resolved
> + * are a prefix of the path, stopping at the first one found.
> + *
> + * Some information about firmlinks and synthetic firmlinks:
> + * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
> + *
> + * macOS no longer allows symlinks in the root directory; any link found
> + * there is therefore a synthetic firmlink.
> + *
> + * If this function gets called often, will want to cache all the firmlink
> + * information, but for now there is only one caller of this function.
> + *
> + * If there is more than one alias for the path, that is another
> + * matter altogteher.
> + */
s/altogteher/altogether/
> diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
> @@ -1,6 +1,14 @@
> +struct alias_info
> +{
> + struct strbuf alias;
> + struct strbuf points_to;
> +};
> +/*
> + * Get the alias in given path, if any.
> + *
> + * Sets alias to the first alias that matches any part of the path.
> + *
> + * Returns -1 on error, 0 otherwise.
> + */
> +int fsmonitor__get_alias(const char *path, struct alias_info *info);
I suppose it's somewhat clear here that the caller is responsible for
releasing the strbufs in alias_info (though it's not clear why they
need to be strbufs in the first place)...
> +/*
> + * Resolve the path against the given alias.
> + *
> + * Returns the resolved path if there is one, NULL otherwise.
> + */
> +char *fsmonitor__resolve_alias(const char *path,
> + const struct alias_info *info);
But what about the return value from this function? It's `char*` which
suggests a possible ownership transfer(?). Is the caller responsible
for freeing it? If so, perhaps the documentation could state that.
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-10 20:00 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-10 20:00 ` [PATCH v5 4/4] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-12 15:27 ` Junio C Hamano
2022-09-12 19:37 ` Junio C Hamano
2022-09-12 15:35 ` Junio C Hamano
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
6 siblings, 1 reply; 170+ messages in thread
From: Junio C Hamano @ 2022-09-12 15:27 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
"Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
> 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.
>
> Eric DeCosta (4):
> 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
It looks like this one is organized quite differently from the last
iteration <pull.1326.v4.git.1661962145.gitgitgadget@gmail.com>
Unless the changes since the last iteration is so obvious [*] that
range-diff will explain all of it, it would help the topic to make
it easier for reviewers what has changed relative to the previous
one in your own words here in the cover letter.
[*} Here, "obvious" does not mean "diff is small and can be read in
10 minutes". It is "diff shows the reason why these changes are
made, so there is no need for additional explanation", e.g. typofixes,
renaming of variables, making a helper function that was added as
extern in the previous iteration to static, etc.
Thanks.
> Makefile | 2 +
> builtin/fsmonitor--daemon.c | 8 ++
> compat/fsmonitor/fsm-ipc-darwin.c | 46 ++++++++
> compat/fsmonitor/fsm-ipc-win32.c | 4 +
> compat/fsmonitor/fsm-listen-darwin.c | 6 +-
> compat/fsmonitor/fsm-path-utils-darwin.c | 131 +++++++++++++++++++++++
> compat/fsmonitor/fsm-path-utils-win32.c | 106 ++++++++++++++++++
> compat/fsmonitor/fsm-settings-darwin.c | 70 ++++--------
> compat/fsmonitor/fsm-settings-win32.c | 106 +-----------------
> contrib/buildsystems/CMakeLists.txt | 4 +
> fsmonitor--daemon.h | 6 ++
> fsmonitor-ipc.c | 2 -
> fsmonitor-path-utils.h | 49 +++++++++
> fsmonitor-settings.c | 58 +++++++++-
> fsmonitor-settings.h | 2 +-
> 15 files changed, 441 insertions(+), 159 deletions(-)
> 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: be1a02a17ede4082a86dfbfee0f54f345e8b43ac
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v5
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v5
> Pull-Request: https://github.com/gitgitgadget/git/pull/1326
>
> Range-diff vs v4:
>
> -: ----------- > 1: 2f647b53e4d fsmonitor: refactor filesystem checks to common interface
> 2: 2cb026a6317 ! 2: 28d08bcf808 fsmonitor: generate unique Unix socket file name in the desired location
> @@ Metadata
> Author: Eric DeCosta <edecosta@mathworks.com>
>
> ## Commit message ##
> - fsmonitor: generate unique Unix socket file name in the desired location
> + fsmonitor: relocate socket file if .git directory is remote
>
> - Based on the values of fsmonitor.allowRemote and fsmonitor.socketDir
> - locate the Unix domain socket file in the desired location (either
> - the .git directory, $HOME, or fsmonitor.socketDir). If the location
> - is other than the .git directory, generate a unique file name based
> - on the SHA1 has of the path to the .git directory.
> + If the .git directory is on a remote file system, create the socket
> + file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
>
> - ## fsmonitor-ipc.c ##
> -@@
> - #include "cache.h"
> --#include "fsmonitor.h"
> --#include "simple-ipc.h"
> - #include "fsmonitor-ipc.h"
> -+#include "fsmonitor-settings.h"
> - #include "run-command.h"
> - #include "strbuf.h"
> - #include "trace2.h"
> -@@ fsmonitor-ipc.c: int fsmonitor_ipc__is_supported(void)
> - return 1;
> - }
> + ## Makefile ##
> +@@ Makefile: ifdef FSMONITOR_DAEMON_BACKEND
> + COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
> + COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
> + COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
> ++ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
> + endif
>
> --GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
> -+GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
> + ifdef FSMONITOR_OS_SETTINGS
> +
> + ## compat/fsmonitor/fsm-ipc-darwin.c (new) ##
> +@@
> ++#include "cache.h"
> ++#include "config.h"
> ++#include "strbuf.h"
> ++#include "fsmonitor.h"
> ++#include "fsmonitor-ipc.h"
> ++#include "fsmonitor-path-utils.h"
> ++
> ++static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
> +
> +const char *fsmonitor_ipc__get_path(void)
> +{
> -+#ifdef WIN32
> -+ return fsmonitor_ipc__get_default_path();
> -+#else
> -+ char *retval;
> ++ static const char *ipc_path;
> + SHA_CTX sha1ctx;
> -+ const char *git_dir;
> -+ const char *sock_dir;
> ++ char *sock_dir;
> + struct strbuf ipc_file = STRBUF_INIT;
> + unsigned char hash[SHA_DIGEST_LENGTH];
> +
> -+ if (fsm_settings__get_allow_remote(the_repository) < 1)
> -+ return fsmonitor_ipc__get_default_path();
> ++ if (ipc_path)
> ++ return ipc_path;
> +
> -+ git_dir = get_git_dir();
> -+ sock_dir = fsm_settings__get_socket_dir(the_repository);
> ++ ipc_path = fsmonitor_ipc__get_default_path();
> ++
> ++ /* By default the socket file is created in the .git directory */
> ++ if (fsmonitor__is_fs_remote(ipc_path) < 1)
> ++ return ipc_path;
> +
> + SHA1_Init(&sha1ctx);
> -+ SHA1_Update(&sha1ctx, git_dir, strlen(git_dir));
> ++ SHA1_Update(&sha1ctx, the_repository->worktree, strlen(the_repository->worktree));
> + SHA1_Final(hash, &sha1ctx);
> +
> ++ repo_config_get_string(the_repository, "fsmonitor.socketdir", &sock_dir);
> ++
> ++ /* Create the socket file in either socketDir or $HOME */
> + if (sock_dir && *sock_dir)
> + strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
> + sock_dir, hash_to_hex(hash));
> + else
> + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
> -+ retval = interpolate_path(ipc_file.buf, 1);
> -+ if (!retval)
> ++
> ++ ipc_path = interpolate_path(ipc_file.buf, 1);
> ++ if (!ipc_path)
> + die(_("Invalid path: %s"), ipc_file.buf);
> ++
> + strbuf_release(&ipc_file);
> -+ return retval;
> -+#endif
> ++ return ipc_path;
> +}
> +
> + ## compat/fsmonitor/fsm-ipc-win32.c (new) ##
> +@@
> ++#include "cache.h"
> ++#include "fsmonitor-ipc.h"
> ++
> ++GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
> +
> + ## contrib/buildsystems/CMakeLists.txt ##
> +@@ contrib/buildsystems/CMakeLists.txt: if(SUPPORTS_SIMPLE_IPC)
> + add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
> + list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
> + list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
> ++ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
> + list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
>
> - enum ipc_active_state fsmonitor_ipc__get_state(void)
> - {
> + add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
> +@@ contrib/buildsystems/CMakeLists.txt: if(SUPPORTS_SIMPLE_IPC)
> + add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
> + list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
> + list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
> ++ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
> + list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
> +
> + add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
>
> - ## fsmonitor-ipc.h ##
> -@@ fsmonitor-ipc.h: int fsmonitor_ipc__is_supported(void);
> - */
> - const char *fsmonitor_ipc__get_path(void);
> + ## fsmonitor-ipc.c ##
> +@@ fsmonitor-ipc.c: int fsmonitor_ipc__is_supported(void)
> + return 1;
> + }
>
> -+/*
> -+ * Returns the pathname to the default IPC named pipe or Unix domain
> -+ * socket.
> -+ */
> -+const char *fsmonitor_ipc__get_default_path(void);
> -+
> - /*
> - * Try to determine whether there is a `git-fsmonitor--daemon` process
> - * listening on the IPC pipe/socket.
> +-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
> +-
> + enum ipc_active_state fsmonitor_ipc__get_state(void)
> + {
> + return ipc_get_active_state(fsmonitor_ipc__get_path());
> 1: 836a791e6b7 ! 3: ff54b6e0bb5 fsmonitor: add two new config options, allowRemote and socketDir
> @@ Metadata
> Author: Eric DeCosta <edecosta@mathworks.com>
>
> ## Commit message ##
> - fsmonitor: add two new config options, allowRemote and socketDir
> + fsmonitor: avoid socket location check if using hook
>
> - Introduce two new configuration options
> -
> - fsmonitor.allowRemote - setting this to true overrides fsmonitor's
> - default behavior of erroring out when enountering network file
> - systems. Additionly, when true, the Unix domain socket (UDS) file
> - used for IPC is located in $HOME rather than in the .git directory.
> -
> - fsmonitor.socketDir - allows for the UDS file to be located
> - anywhere the user chooses rather $HOME.
> + If monitoring is done via fsmonitor hook rather than IPC there is no
> + need to check if the location of the Unix Domain socket (UDS) file is
> + on a remote filesystem.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
>
> - ## fsmonitor-settings.c ##
> -@@
> - struct fsmonitor_settings {
> - enum fsmonitor_mode mode;
> + ## compat/fsmonitor/fsm-settings-darwin.c ##
> +@@ compat/fsmonitor/fsm-settings-darwin.c: static enum fsmonitor_reason check_uds_volume(struct repository *r)
> + return FSMONITOR_REASON_OK;
> + }
> +
> +-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
> ++enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
> + {
> enum fsmonitor_reason reason;
> -+ int allow_remote;
> - char *hook_path;
> -+ char *sock_dir;
> - };
>
> - static enum fsmonitor_reason check_for_incompatible(struct repository *r)
> -@@ fsmonitor-settings.c: static struct fsmonitor_settings *alloc_settings(void)
> - CALLOC_ARRAY(s, 1);
> - s->mode = FSMONITOR_MODE_DISABLED;
> - s->reason = FSMONITOR_REASON_UNTESTED;
> -+ s->allow_remote = -1;
> +- reason = check_uds_volume(r);
> +- if (reason != FSMONITOR_REASON_OK)
> +- return reason;
> ++ if (ipc) {
> ++ reason = check_uds_volume(r);
> ++ if (reason != FSMONITOR_REASON_OK)
> ++ return reason;
> ++ }
>
> - return s;
> + return FSMONITOR_REASON_OK;
> }
> -@@ fsmonitor-settings.c: static void lookup_fsmonitor_settings(struct repository *r)
> - fsm_settings__set_disabled(r);
> +
> + ## compat/fsmonitor/fsm-settings-win32.c ##
> +@@ compat/fsmonitor/fsm-settings-win32.c: static enum fsmonitor_reason check_vfs4git(struct repository *r)
> + return FSMONITOR_REASON_OK;
> }
>
> -+int fsm_settings__get_allow_remote(struct repository *r)
> -+{
> -+ if (!r)
> -+ r = the_repository;
> -+ if (!r->settings.fsmonitor)
> -+ lookup_fsmonitor_settings(r);
> -+
> -+ return r->settings.fsmonitor->allow_remote;
> -+}
> -+
> -+const char *fsm_settings__get_socket_dir(struct repository *r)
> -+{
> -+ if (!r)
> -+ r = the_repository;
> -+ if (!r->settings.fsmonitor)
> -+ lookup_fsmonitor_settings(r);
> -+
> -+ return r->settings.fsmonitor->sock_dir;
> -+}
> -+
> - enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
> +-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
> ++enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
> {
> - if (!r)
> -@@ fsmonitor-settings.c: enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
> - return r->settings.fsmonitor->mode;
> + enum fsmonitor_reason reason;
> +
> +
> + ## fsmonitor-settings.c ##
> +@@ fsmonitor-settings.c: static enum fsmonitor_reason check_remote(struct repository *r)
> }
> + #endif
>
> -+
> - const char *fsm_settings__get_hook_path(struct repository *r)
> +-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
> ++static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
> {
> - if (!r)
> + if (!r->worktree) {
> + /*
> +@@ fsmonitor-settings.c: static enum fsmonitor_reason check_for_incompatible(struct repository *r)
> + reason = check_remote(r);
> + if (reason != FSMONITOR_REASON_OK)
> + return reason;
> +- reason = fsm_os__incompatible(r);
> ++ reason = fsm_os__incompatible(r, ipc);
> + if (reason != FSMONITOR_REASON_OK)
> + return reason;
> + }
> @@ fsmonitor-settings.c: const char *fsm_settings__get_hook_path(struct repository *r)
> - return r->settings.fsmonitor->hook_path;
> - }
>
> -+void fsm_settings__set_allow_remote(struct repository *r)
> -+{
> -+ int allow;
> -+
> -+ if (!r)
> -+ r = the_repository;
> -+ if (!r->settings.fsmonitor)
> -+ r->settings.fsmonitor = alloc_settings();
> -+ if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
> -+ r->settings.fsmonitor->allow_remote = allow;
> -+
> -+ return;
> -+}
> -+
> -+void fsm_settings__set_socket_dir(struct repository *r)
> -+{
> -+ const char *path;
> -+
> -+ if (!r)
> -+ r = the_repository;
> -+ if (!r->settings.fsmonitor)
> -+ r->settings.fsmonitor = alloc_settings();
> -+
> -+ if (!repo_config_get_pathname(r, "fsmonitor.socketdir", &path)) {
> -+ FREE_AND_NULL(r->settings.fsmonitor->sock_dir);
> -+ r->settings.fsmonitor->sock_dir = strdup(path);
> -+ }
> -+
> -+ return;
> -+}
> -+
> void fsm_settings__set_ipc(struct repository *r)
> {
> - enum fsmonitor_reason reason = check_for_incompatible(r);
> -+ enum fsmonitor_reason reason;
> -+
> -+ fsm_settings__set_allow_remote(r);
> -+ fsm_settings__set_socket_dir(r);
> -+ reason = check_for_incompatible(r);
> ++ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
>
> if (reason != FSMONITOR_REASON_OK) {
> fsm_settings__set_incompatible(r, reason);
> @@ fsmonitor-settings.c: void fsm_settings__set_ipc(struct repository *r)
> void fsm_settings__set_hook(struct repository *r, const char *path)
> {
> - enum fsmonitor_reason reason = check_for_incompatible(r);
> -+ enum fsmonitor_reason reason;
> -+
> -+ fsm_settings__set_allow_remote(r);
> -+ fsm_settings__set_socket_dir(r);
> -+ reason = check_for_incompatible(r);
> ++ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
>
> if (reason != FSMONITOR_REASON_OK) {
> fsm_settings__set_incompatible(r, reason);
>
> ## fsmonitor-settings.h ##
> -@@ fsmonitor-settings.h: enum fsmonitor_reason {
> - FSMONITOR_REASON_NOSOCKETS, /* NTFS,FAT32 do not support Unix sockets */
> - };
> -
> -+void fsm_settings__set_allow_remote(struct repository *r);
> -+void fsm_settings__set_socket_dir(struct repository *r);
> - void fsm_settings__set_ipc(struct repository *r);
> - void fsm_settings__set_hook(struct repository *r, const char *path);
> - void fsm_settings__set_disabled(struct repository *r);
> - void fsm_settings__set_incompatible(struct repository *r,
> - enum fsmonitor_reason reason);
> -
> -+int fsm_settings__get_allow_remote(struct repository *r);
> -+const char *fsm_settings__get_socket_dir(struct repository *r);
> - enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
> - const char *fsm_settings__get_hook_path(struct repository *r);
> +@@ fsmonitor-settings.h: struct fsmonitor_settings;
> + * fsm_os__* routines should considered private to fsm_settings__
> + * routines.
> + */
> +-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
> ++enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
> + #endif /* HAVE_FSMONITOR_OS_SETTINGS */
>
> + #endif /* FSMONITOR_SETTINGS_H */
> 3: a3110f1e25a < -: ----------- fsmonitor: ensure filesystem and unix socket filesystem are compatible
> 4: 56cabf3be3b ! 4: b7d6cf44695 fsmonitor: normalize FSEvents event paths to the real path
> @@ Metadata
> Author: Eric DeCosta <edecosta@mathworks.com>
>
> ## Commit message ##
> - fsmonitor: normalize FSEvents event paths to the real path
> + fsmonitor: deal with synthetic firmlinks on macOS
>
> - Consider the following network working directory that is mounted under
> - /System/Volumes/Data:
> + Starting with macOS 10.15 (Catalina), Apple introduced a new feature
> + called 'firmlinks' in order to separate the boot volume into two
> + volumes, one read-only and one writable but still present them to the
> + user as a single volume. Along with this change, Apple removed the
> + ability to create symlinks in the root directory and replaced them with
> + 'synthetic firmlinks'. See 'man synthetic.conf'
>
> - /network/working/directory
> + When FSEevents reports the path of changed files, if the path invloves
> + a synthetic firmlink, the path is reported from the point of the
> + synthetic firmlink and not the real path. For example:
>
> - The git working directory path is:
> + Real path:
> + /System/Volumes/Data/network/working/directory/foo.txt
>
> - /System/Volumes/Data/network/working/directory
> + Synthetic firmlink:
> + /network -> /System/Volumes/Data/network
>
> - The paths reported by FSEvents always start with /network. fsmonitor
> - expects paths to be under the working directory; therefore it
> - fails to match /network/... and ignores the change.
> + FSEvents path:
> + /network/working/directory/foo.txt
>
> - Change things such that if fsmonitor.allowRemote is true that the
> - paths reported via FSEevents are normalized to the real path.
> + This causes the FSEvents path to not match against the worktree
> + directory.
> +
> + There are several ways in which synthetic firmlinks can be created:
> + they can be defined in /etc/synthetic.conf, the automounter can create
> + them, and there may be other means. Simply reading /etc/synthetic.conf
> + is insufficient. No matter what process creates synthetic firmlinks,
> + they all get created in the root directory.
> +
> + Therefore, in order to deal with synthetic firmlinks, the root directory
> + is scanned and the first possible synthetic firmink that, when resolved,
> + is a prefix of the worktree is used to map FSEvents paths to worktree
> + paths.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
>
> + ## builtin/fsmonitor--daemon.c ##
> +@@
> + #include "parse-options.h"
> + #include "fsmonitor.h"
> + #include "fsmonitor-ipc.h"
> ++#include "fsmonitor-path-utils.h"
> + #include "compat/fsmonitor/fsm-health.h"
> + #include "compat/fsmonitor/fsm-listen.h"
> + #include "fsmonitor--daemon.h"
> +@@ builtin/fsmonitor--daemon.c: static int fsmonitor_run_daemon(void)
> + strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
> + state.nr_paths_watching = 1;
> +
> ++ 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"));
> ++ goto done;
> ++ }
> ++
> + /*
> + * We create and delete cookie files somewhere inside the .git
> + * directory to help us keep sync with the file system. If
> +
> ## compat/fsmonitor/fsm-listen-darwin.c ##
> @@
> #include "fsmonitor.h"
> #include "fsm-listen.h"
> #include "fsmonitor--daemon.h"
> -+#include "fsmonitor-settings.h"
> ++#include "fsmonitor-path-utils.h"
>
> struct fsm_listen_data
> {
> -@@ compat/fsmonitor/fsm-listen-darwin.c: static void my_add_path(struct fsmonitor_batch *batch, const char *path)
> - free(composed);
> - }
> -
> --
> - static void fsevent_callback(ConstFSEventStreamRef streamRef,
> - void *ctx,
> - size_t num_of_events,
> @@ compat/fsmonitor/fsm-listen-darwin.c: static void fsevent_callback(ConstFSEventStreamRef streamRef,
> /*
> * On Mac, we receive an array of absolute paths.
> */
> - path_k = paths[k];
> -+ if (fsm_settings__get_allow_remote(the_repository) > 0) {
> -+ strbuf_reset(&tmp);
> -+ strbuf_realpath_forgiving(&tmp, paths[k], 0);
> -+ path_k = tmp.buf;
> -+ } else
> ++ path_k = fsmonitor__resolve_alias(paths[k], &state->alias);
> ++ if (!path_k)
> + path_k = paths[k];
>
> /*
> * If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
> @@ compat/fsmonitor/fsm-listen-darwin.c: static void fsevent_callback(ConstFSEventStreamRef streamRef,
> -
> fsmonitor_force_resync(state);
> fsmonitor_batch__free_list(batch);
> -+ batch = NULL;
> string_list_clear(&cookie_list, 0);
> ++ batch = NULL;
>
> /*
> -@@ compat/fsmonitor/fsm-listen-darwin.c: static void fsevent_callback(ConstFSEventStreamRef streamRef,
> + * We assume that any events that we received
> +
> + ## compat/fsmonitor/fsm-path-utils-darwin.c ##
> +@@
> + #include "fsmonitor.h"
> + #include "fsmonitor-path-utils.h"
> ++#include <dirent.h>
> ++#include <errno.h>
> ++#include <fcntl.h>
> + #include <sys/param.h>
> + #include <sys/mount.h>
> +
> +@@ compat/fsmonitor/fsm-path-utils-darwin.c: int fsmonitor__is_fs_remote(const char *path)
> + return -1;
> + return fs.is_remote;
> + }
> ++
> ++/*
> ++ * Scan the root directory for synthetic firmlinks that when resolved
> ++ * are a prefix of the path, stopping at the first one found.
> ++ *
> ++ * Some information about firmlinks and synthetic firmlinks:
> ++ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
> ++ *
> ++ * macOS no longer allows symlinks in the root directory; any link found
> ++ * there is therefore a synthetic firmlink.
> ++ *
> ++ * If this function gets called often, will want to cache all the firmlink
> ++ * information, but for now there is only one caller of this function.
> ++ *
> ++ * If there is more than one alias for the path, that is another
> ++ * matter altogteher.
> ++ */
> ++int fsmonitor__get_alias(const char *path, struct alias_info *info)
> ++{
> ++ DIR * dir;
> ++ int read;
> ++ int retval;
> ++ struct dirent *de;
> ++ struct strbuf alias;
> ++ struct strbuf points_to;
> ++
> ++ retval = 0;
> ++ dir = opendir("/");
> ++ if (!dir)
> ++ return -1;
> ++
> ++ strbuf_init(&alias, 256);
> ++ 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));
> ++
> ++ 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) == 0)
> ++ && 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 (errno != EINVAL) { /* Something other than not a link */
> ++ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
> ++ retval = -1;
> ++ goto done;
> ++ }
> ++ }
> ++
> ++ done:
> ++ closedir(dir);
> ++ strbuf_release(&alias);
> ++ strbuf_release(&points_to);
> ++ return retval;
> ++}
> ++
> ++char *fsmonitor__resolve_alias(const char *path,
> ++ const struct alias_info *info)
> ++{
> ++ int len = info->alias.len;
> ++
> ++ if (!len)
> ++ return NULL;
> ++
> ++ if ((strncmp(info->alias.buf, path, len) == 0)
> ++ && path[len] == '/') {
> ++ struct strbuf tmp;
> ++ const char *remainder = path + len;
> ++ int rem_len = strlen(remainder);
> ++
> ++ strbuf_init(&tmp, info->points_to.len + rem_len);
> ++ strbuf_addbuf(&tmp, &info->points_to);
> ++ strbuf_add(&tmp, remainder, rem_len);
> ++ return strbuf_detach(&tmp, NULL);
> ++ }
> ++
> ++ return NULL;
> ++}
> +
> + ## compat/fsmonitor/fsm-path-utils-win32.c ##
> +@@ compat/fsmonitor/fsm-path-utils-win32.c: int fsmonitor__is_fs_remote(const char *path)
> + return -1;
> + return fs.is_remote;
> + }
> ++
> ++/*
> ++ * No-op for now.
> ++ */
> ++int fsmonitor__get_alias(const char *path, struct alias_info *info)
> ++{
> ++ return 0;
> ++}
> ++
> ++/*
> ++ * No-op for now.
> ++ */
> ++char *fsmonitor__resolve_alias(const char *path,
> ++ const struct alias_info *info)
> ++{
> ++ return NULL;
> ++}
> +
> + ## fsmonitor--daemon.h ##
> +@@
> + #include "run-command.h"
> + #include "simple-ipc.h"
> + #include "thread-utils.h"
> ++#include "fsmonitor-path-utils.h"
> +
> + struct fsmonitor_batch;
> + struct fsmonitor_token_data;
> +@@ fsmonitor--daemon.h: struct fsmonitor_daemon_state {
> +
> + struct strbuf path_worktree_watch;
> + struct strbuf path_gitdir_watch;
> ++ struct alias_info alias;
> + int nr_paths_watching;
> +
> + struct fsmonitor_token_data *current_token_data;
> +@@ fsmonitor--daemon.h: struct fsmonitor_daemon_state {
> +
> + struct ipc_server_data *ipc_server_data;
> + struct strbuf path_ipc;
> ++
> + };
> +
> + /*
> +@@ fsmonitor--daemon.h: void fsmonitor_publish(struct fsmonitor_daemon_state *state,
> + */
> + void fsmonitor_force_resync(struct fsmonitor_daemon_state *state);
> +
> ++char *fsmonitor_resolve_alias(const char *path,
> ++ struct alias_info *alias);
> ++
> + #endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
> + #endif /* FSMONITOR_DAEMON_H */
> +
> + ## fsmonitor-path-utils.h ##
> +@@
> + #ifndef FSM_PATH_UTILS_H
> + #define FSM_PATH_UTILS_H
>
> - case IS_WORKDIR_PATH:
> - /* try to queue normal pathnames */
> --
> - if (trace_pass_fl(&trace_fsmonitor))
> - log_flags_set(path_k, event_flags[k]);
> ++#include "strbuf.h"
> ++
> ++struct alias_info
> ++{
> ++ struct strbuf alias;
> ++ struct strbuf points_to;
> ++};
> ++
> + struct fs_info {
> + int is_remote;
> + char *typename;
> +@@ fsmonitor-path-utils.h: int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
> + */
> + int fsmonitor__is_fs_remote(const char *path);
>
> ++/*
> ++ * Get the alias in given path, if any.
> ++ *
> ++ * Sets alias to the first alias that matches any part of the path.
> ++ *
> ++ * Returns -1 on error, 0 otherwise.
> ++ */
> ++int fsmonitor__get_alias(const char *path, struct alias_info *info);
> ++
> ++/*
> ++ * Resolve the path against the given alias.
> ++ *
> ++ * Returns the resolved path if there is one, NULL otherwise.
> ++ */
> ++char *fsmonitor__resolve_alias(const char *path,
> ++ const struct alias_info *info);
> ++
> ++
> + #endif
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-12 15:27 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Junio C Hamano
@ 2022-09-12 19:37 ` Junio C Hamano
2022-09-12 19:39 ` Eric DeCosta
0 siblings, 1 reply; 170+ messages in thread
From: Junio C Hamano @ 2022-09-12 19:37 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
Junio C Hamano <gitster@pobox.com> writes:
>> Eric DeCosta (4):
>> 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
>
> It looks like this one is organized quite differently from the last
> iteration <pull.1326.v4.git.1661962145.gitgitgadget@gmail.com>
Given that we are very close to -rc period, I am very tempted to say
that this follow-up effort can and should be separated out of the
previous "windows only" one, and we should merge the single patch
that has been in 'next' to 'master' without waiting for this "macOS,
too" topic. What do people think?
Thanks.
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-12 19:37 ` Junio C Hamano
@ 2022-09-12 19:39 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-12 19:39 UTC (permalink / raw)
To: Junio C Hamano, Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Junio C Hamano <jch2355@gmail.com> On Behalf Of Junio C Hamano
> Sent: Monday, September 12, 2022 3:38 PM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Cc: git@vger.kernel.org; Jeff Hostetler <git@jeffhostetler.com>; Eric Sunshine
> <sunshine@sunshineco.com>; Torsten Bögershausen <tboegi@web.de>;
> Ævar Arnfjörð Bjarmason <avarab@gmail.com>; Ramsay Jones
> <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run
> against network-mounted repos
>
> Junio C Hamano <gitster@pobox.com> writes:
>
> >> Eric DeCosta (4):
> >> 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
> >
> > It looks like this one is organized quite differently from the last
> > iteration <pull.1326.v4.git.1661962145.gitgitgadget@gmail.com>
>
> Given that we are very close to -rc period, I am very tempted to say that this
> follow-up effort can and should be separated out of the previous "windows
> only" one, and we should merge the single patch that has been in 'next' to
> 'master' without waiting for this "macOS, too" topic. What do people think?
>
> Thanks.
I'm totally fine with that, turned out to be a bit more involved than I initially anticipated.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-10 20:00 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-12 15:27 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Junio C Hamano
@ 2022-09-12 15:35 ` Junio C Hamano
2022-09-12 19:35 ` Eric DeCosta
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
6 siblings, 1 reply; 170+ messages in thread
From: Junio C Hamano @ 2022-09-12 15:35 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
"Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
> Eric DeCosta (4):
> 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
>
> Makefile | 2 +
> builtin/fsmonitor--daemon.c | 8 ++
> compat/fsmonitor/fsm-ipc-darwin.c | 46 ++++++++
> compat/fsmonitor/fsm-ipc-win32.c | 4 +
> compat/fsmonitor/fsm-listen-darwin.c | 6 +-
> compat/fsmonitor/fsm-path-utils-darwin.c | 131 +++++++++++++++++++++++
> compat/fsmonitor/fsm-path-utils-win32.c | 106 ++++++++++++++++++
> compat/fsmonitor/fsm-settings-darwin.c | 70 ++++--------
> compat/fsmonitor/fsm-settings-win32.c | 106 +-----------------
> contrib/buildsystems/CMakeLists.txt | 4 +
> fsmonitor--daemon.h | 6 ++
> fsmonitor-ipc.c | 2 -
> fsmonitor-path-utils.h | 49 +++++++++
> fsmonitor-settings.c | 58 +++++++++-
> fsmonitor-settings.h | 2 +-
> 15 files changed, 441 insertions(+), 159 deletions(-)
> 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: be1a02a17ede4082a86dfbfee0f54f345e8b43ac
Another curious thing I need your help on.
The cover letter says that this work is a follow-up to extend the
previous work for Windows, and I would have expected these patches
to build on 85dc0da6 (fsmonitor: option to allow fsmonitor to run
against network-mounted repos, 2022-08-11), which is not yet in
be1a02a1 (The seventeenth batch, 2022-09-01).
What is going on?
Thanks.
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-12 15:35 ` Junio C Hamano
@ 2022-09-12 19:35 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-12 19:35 UTC (permalink / raw)
To: Junio C Hamano, Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Junio C Hamano <jch2355@gmail.com> On Behalf Of Junio C Hamano
> Sent: Monday, September 12, 2022 11:36 AM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Cc: git@vger.kernel.org; Jeff Hostetler <git@jeffhostetler.com>; Eric Sunshine
> <sunshine@sunshineco.com>; Torsten Bögershausen <tboegi@web.de>;
> Ævar Arnfjörð Bjarmason <avarab@gmail.com>; Ramsay Jones
> <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run
> against network-mounted repos
>
> "Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > Eric DeCosta (4):
> > 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
> >
> > Makefile | 2 +
> > builtin/fsmonitor--daemon.c | 8 ++
> > compat/fsmonitor/fsm-ipc-darwin.c | 46 ++++++++
> > compat/fsmonitor/fsm-ipc-win32.c | 4 +
> > compat/fsmonitor/fsm-listen-darwin.c | 6 +-
> > compat/fsmonitor/fsm-path-utils-darwin.c | 131
> > +++++++++++++++++++++++ compat/fsmonitor/fsm-path-utils-win32.c |
> 106 ++++++++++++++++++
> > compat/fsmonitor/fsm-settings-darwin.c | 70 ++++--------
> > compat/fsmonitor/fsm-settings-win32.c | 106 +-----------------
> > contrib/buildsystems/CMakeLists.txt | 4 +
> > fsmonitor--daemon.h | 6 ++
> > fsmonitor-ipc.c | 2 -
> > fsmonitor-path-utils.h | 49 +++++++++
> > fsmonitor-settings.c | 58 +++++++++-
> > fsmonitor-settings.h | 2 +-
> > 15 files changed, 441 insertions(+), 159 deletions(-) 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: be1a02a17ede4082a86dfbfee0f54f345e8b43ac
>
> Another curious thing I need your help on.
>
> The cover letter says that this work is a follow-up to extend the previous
> work for Windows, and I would have expected these patches to build on
> 85dc0da6 (fsmonitor: option to allow fsmonitor to run against network-
> mounted repos, 2022-08-11), which is not yet in
> be1a02a1 (The seventeenth batch, 2022-09-01).
>
> What is going on?
>
> Thanks.
I've been rolling that around in the back of my head over the last couple of days
actually. Initially I though the macOS changes were going to be independent of
my earlier changes, but with all the refactoring that has occurred, that is no
longer the case. I've rebased my current patch set on top of those earlier changes.
v6 will incorporate that, the review feedback that I've received so far and add doc
for the new config options. I'll be sure to note all of this in the cover letter for v6.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v6 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-10 20:00 ` [PATCH v5 0/4] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-12 15:35 ` Junio C Hamano
@ 2022-09-13 20:27 ` Eric DeCosta via GitGitGadget
2022-09-13 20:27 ` [PATCH v6 1/6] " Eric DeCosta via GitGitGadget
` (7 more replies)
6 siblings, 8 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-13 20:27 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
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: option to allow fsmonitor to run against network-mounted
repos
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: add documentation for allowRemote and socketDir options
Documentation/git-fsmonitor--daemon.txt | 35 ++++++
Makefile | 2 +
builtin/fsmonitor--daemon.c | 8 ++
compat/fsmonitor/fsm-ipc-darwin.c | 46 +++++++
compat/fsmonitor/fsm-ipc-win32.c | 4 +
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 132 +++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 145 +++++++++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 70 ++++-------
compat/fsmonitor/fsm-settings-win32.c | 106 +----------------
contrib/buildsystems/CMakeLists.txt | 4 +
fsmonitor--daemon.h | 6 +
fsmonitor-ipc.c | 2 -
fsmonitor-path-utils.h | 59 +++++++++
fsmonitor-settings.c | 58 ++++++++-
fsmonitor-settings.h | 2 +-
16 files changed, 526 insertions(+), 159 deletions(-)
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: dd3f6c4cae7e3b15ce984dce8593ff7569650e24
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v5:
-: ----------- > 1: 3233c908c4a fsmonitor: option to allow fsmonitor to run against network-mounted repos
1: 2f647b53e4d ! 2: d2a8fc6b707 fsmonitor: refactor filesystem checks to common interface
@@ compat/fsmonitor/fsm-path-utils-win32.c (new)
+#include "fsmonitor-path-utils.h"
+
+/*
++ * Check remote working directory protocol.
++ *
++ * Return -1 if client machine cannot get remote protocol information.
++ */
++static int check_remote_protocol(wchar_t *wpath)
++{
++ HANDLE h;
++ FILE_REMOTE_PROTOCOL_INFO proto_info;
++
++ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
++ FILE_FLAG_BACKUP_SEMANTICS, NULL);
++
++ if (h == INVALID_HANDLE_VALUE) {
++ error(_("[GLE %ld] unable to open for read '%ls'"),
++ GetLastError(), wpath);
++ return -1;
++ }
++
++ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
++ &proto_info, sizeof(proto_info))) {
++ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
++ GetLastError(), wpath);
++ CloseHandle(h);
++ return -1;
++ }
++
++ CloseHandle(h);
++
++ trace_printf_key(&trace_fsmonitor,
++ "check_remote_protocol('%ls') remote protocol %#8.8lx",
++ wpath, proto_info.Protocol);
++
++ return 0;
++}
++
++/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
@@ compat/fsmonitor/fsm-path-utils-win32.c (new)
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
-+ if (driveType == DRIVE_REMOTE)
++ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
-+ else
++ if (check_remote_protocol(wfullpath) < 0)
++ return -1;
++ } else {
+ fs_info->is_remote = 0;
++ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
@@ compat/fsmonitor/fsm-settings-win32.c: static enum fsmonitor_reason check_vfs4gi
return FSMONITOR_REASON_OK;
}
+-/*
+- * Check if monitoring remote working directories is allowed.
+- *
+- * By default, monitoring remote working directories is
+- * disabled. Users may override this behavior in enviroments where
+- * they have proper support.
+- */
+-static int check_config_allowremote(struct repository *r)
+-{
+- int allow;
+-
+- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
+- return allow;
+-
+- return -1; /* fsmonitor.allowremote not set */
+-}
+-
+-/*
+- * Check remote working directory protocol.
+- *
+- * Error if client machine cannot get remote protocol information.
+- */
+-static int check_remote_protocol(wchar_t *wpath)
+-{
+- HANDLE h;
+- FILE_REMOTE_PROTOCOL_INFO proto_info;
+-
+- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+- FILE_FLAG_BACKUP_SEMANTICS, NULL);
+-
+- if (h == INVALID_HANDLE_VALUE) {
+- error(_("[GLE %ld] unable to open for read '%ls'"),
+- GetLastError(), wpath);
+- return -1;
+- }
+-
+- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+- &proto_info, sizeof(proto_info))) {
+- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+- GetLastError(), wpath);
+- CloseHandle(h);
+- return -1;
+- }
+-
+- CloseHandle(h);
+-
+- trace_printf_key(&trace_fsmonitor,
+- "check_remote_protocol('%ls') remote protocol %#8.8lx",
+- wpath, proto_info.Protocol);
+-
+- return 0;
+-}
+-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
@@ compat/fsmonitor/fsm-settings-win32.c: static enum fsmonitor_reason check_vfs4gi
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
+- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
@@ compat/fsmonitor/fsm-settings-win32.c: static enum fsmonitor_reason check_vfs4gi
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
+-
+- ret = check_remote_protocol(wfullpath);
+- if (ret < 0)
+- return FSMONITOR_REASON_ERROR;
+-
+- switch (check_config_allowremote(r)) {
+- case 0: /* config overrides and disables */
+- return FSMONITOR_REASON_REMOTE;
+- case 1: /* config overrides and enables */
+- return FSMONITOR_REASON_OK;
+- default:
+- break; /* config has no opinion */
+- }
+-
- return FSMONITOR_REASON_REMOTE;
- }
-
2: 28d08bcf808 = 3: edef029a298 fsmonitor: relocate socket file if .git directory is remote
3: ff54b6e0bb5 = 4: 3428bcf8763 fsmonitor: avoid socket location check if using hook
4: b7d6cf44695 ! 5: 9c1f408ae6d fsmonitor: deal with synthetic firmlinks on macOS
@@ Commit message
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
- When FSEevents reports the path of changed files, if the path invloves
+ When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
@@ builtin/fsmonitor--daemon.c: static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
-+ strbuf_init(&state.alias.alias, 0);
-+ strbuf_init(&state.alias.points_to, 0);
++ state.alias.alias = NULL;
++ state.alias.points_to = NULL;
+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
+ err = error(_("could not get worktree alias"));
+ goto done;
@@ compat/fsmonitor/fsm-path-utils-darwin.c: int fsmonitor__is_fs_remote(const char
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
-+ * matter altogteher.
++ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
@@ compat/fsmonitor/fsm-path-utils-darwin.c: int fsmonitor__is_fs_remote(const char
+ strbuf_setlen(&points_to, read);
+ if ((strncmp(points_to.buf, path, points_to.len) == 0)
+ && path[points_to.len] == '/') {
-+ strbuf_addbuf(&info->alias, &alias);
-+ strbuf_addbuf(&info->points_to, &points_to);
++ info->alias = strbuf_detach(&alias, NULL);
++ info->points_to = strbuf_detach(&points_to, NULL);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
-+ path, info->alias.buf, info->points_to.buf);
++ path, info->alias, info->points_to);
+ retval = 0;
+ goto done;
+ }
@@ compat/fsmonitor/fsm-path-utils-darwin.c: int fsmonitor__is_fs_remote(const char
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
-+ int len = info->alias.len;
++ int len = info->alias ? strlen(info->alias) : 0;
+
+ if (!len)
+ return NULL;
+
-+ if ((strncmp(info->alias.buf, path, len) == 0)
++ if ((strncmp(info->alias, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
++ int ptr_len = strlen(info->points_to);
+ int rem_len = strlen(remainder);
+
-+ strbuf_init(&tmp, info->points_to.len + rem_len);
-+ strbuf_addbuf(&tmp, &info->points_to);
++ strbuf_init(&tmp, ptr_len + rem_len);
++ strbuf_add(&tmp, info->points_to, ptr_len);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
@@ fsmonitor-path-utils.h
+
+struct alias_info
+{
-+ struct strbuf alias;
-+ struct strbuf points_to;
++ char *alias;
++ char *points_to;
+};
+
struct fs_info {
@@ fsmonitor-path-utils.h: int fsmonitor__get_fs_info(const char *path, struct fs_i
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
++ * If an alias is found, info.alias and info.points_to are set to the
++ * found mapping.
++ *
+ * Returns -1 on error, 0 otherwise.
++ *
++ * The caller owns the storage that is occupied by set info.alias and
++ * info.points_to and is responsible for releasing it with `free(3)`
++ * when done.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
@@ fsmonitor-path-utils.h: int fsmonitor__get_fs_info(const char *path, struct fs_i
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
++ *
++ * The caller owns the storage that the returned string occupies and
++ * is responsible for releasing it with `free(3)` when done.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
-: ----------- > 6: d2c95e34d3a fsmonitor: add documentation for allowRemote and socketDir options
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v6 1/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
@ 2022-09-13 20:27 ` Eric DeCosta via GitGitGadget
2022-09-13 20:27 ` [PATCH v6 2/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (6 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-13 20:27 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Though perhaps not common, there are use cases where users have large,
network-mounted repos. Having the ability to run fsmonitor against
network paths would benefit those users.
Most modern Samba-based filers have the necessary support to enable
fsmonitor on network-mounted repos. As a first step towards enabling
fsmonitor to work against network-mounted repos, introduce a
configuration option, 'fsmonitor.allowRemote'. Setting this option to
true will override the default behavior (erroring-out) when a
network-mounted repo is detected by fsmonitor.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-win32.c | 68 +++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index 907655720bb..e5ec5b0a9f7 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -24,6 +24,59 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
+/*
+ * Check if monitoring remote working directories is allowed.
+ *
+ * By default, monitoring remote working directories is
+ * disabled. Users may override this behavior in enviroments where
+ * they have proper support.
+ */
+static int check_config_allowremote(struct repository *r)
+{
+ int allow;
+
+ if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
+ return allow;
+
+ return -1; /* fsmonitor.allowremote not set */
+}
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Error if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
/*
* Remote working directories are problematic for FSMonitor.
*
@@ -76,6 +129,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
*/
static enum fsmonitor_reason check_remote(struct repository *r)
{
+ int ret;
wchar_t wpath[MAX_PATH];
wchar_t wfullpath[MAX_PATH];
size_t wlen;
@@ -115,6 +169,20 @@ static enum fsmonitor_reason check_remote(struct repository *r)
trace_printf_key(&trace_fsmonitor,
"check_remote('%s') true",
r->worktree);
+
+ ret = check_remote_protocol(wfullpath);
+ if (ret < 0)
+ return FSMONITOR_REASON_ERROR;
+
+ switch (check_config_allowremote(r)) {
+ case 0: /* config overrides and disables */
+ return FSMONITOR_REASON_REMOTE;
+ case 1: /* config overrides and enables */
+ return FSMONITOR_REASON_OK;
+ default:
+ break; /* config has no opinion */
+ }
+
return FSMONITOR_REASON_REMOTE;
}
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v6 2/6] fsmonitor: refactor filesystem checks to common interface
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
2022-09-13 20:27 ` [PATCH v6 1/6] " Eric DeCosta via GitGitGadget
@ 2022-09-13 20:27 ` Eric DeCosta via GitGitGadget
2022-09-13 20:27 ` [PATCH v6 3/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-13 20:27 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index c6e126e54c2..b026f3e8cf0 100644
--- a/Makefile
+++ b/Makefile
@@ -2038,6 +2038,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2237109b57f..b88494bf59b 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v6 3/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
2022-09-13 20:27 ` [PATCH v6 1/6] " Eric DeCosta via GitGitGadget
2022-09-13 20:27 ` [PATCH v6 2/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-13 20:27 ` Eric DeCosta via GitGitGadget
2022-09-14 0:48 ` Junio C Hamano
2022-09-13 20:27 ` [PATCH v6 4/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
7 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-13 20:27 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote file system, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-ipc-darwin.c | 46 +++++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 4 +++
contrib/buildsystems/CMakeLists.txt | 2 ++
fsmonitor-ipc.c | 2 --
5 files changed, 53 insertions(+), 2 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index b026f3e8cf0..5cd5ad818b8 100644
--- a/Makefile
+++ b/Makefile
@@ -2033,6 +2033,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..afaca96dab9
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,46 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(void)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
+ char *sock_dir;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (ipc_path)
+ return ipc_path;
+
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
+ return ipc_path;
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, the_repository->worktree, strlen(the_repository->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(the_repository, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir)
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ else
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..769a88639f6
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,4 @@
+#include "cache.h"
+#include "fsmonitor-ipc.h"
+
+GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index b88494bf59b..7e7b6b9a362 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..caad2e246a0 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -47,8 +47,6 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
return ipc_get_active_state(fsmonitor_ipc__get_path());
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v6 3/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-13 20:27 ` [PATCH v6 3/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-14 0:48 ` Junio C Hamano
2022-09-14 15:47 ` Eric DeCosta
0 siblings, 1 reply; 170+ messages in thread
From: Junio C Hamano @ 2022-09-14 0:48 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
"Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
> +const char *fsmonitor_ipc__get_path(void)
> +{
Looks like a bit klunky API. I would have expected it to take at
least the path to the worktree or a pointer to struct repository.
> + static const char *ipc_path;
> + SHA_CTX sha1ctx;
> + char *sock_dir;
> + struct strbuf ipc_file = STRBUF_INIT;
> + unsigned char hash[SHA_DIGEST_LENGTH];
> +
> + if (ipc_path)
> + return ipc_path;
> +
> + ipc_path = fsmonitor_ipc__get_default_path();
> +
> + /* By default the socket file is created in the .git directory */
> + if (fsmonitor__is_fs_remote(ipc_path) < 1)
> + return ipc_path;
> +
> + SHA1_Init(&sha1ctx);
> + SHA1_Update(&sha1ctx, the_repository->worktree, strlen(the_repository->worktree));
> + SHA1_Final(hash, &sha1ctx);
I would not worry about SHA-1 hash collision for this use case, but
would worry more about .worktree possible being unique.
Can the .worktree string be aliased for the same directory in some
way (e.g. depending on the initialization sequence, can it be a full
pathname, a relative pathname, or can a pathname that looks like a
full-pathname have symbolic link component in it?) that ends up
creating two or more socket for the same worktree?
> + repo_config_get_string(the_repository, "fsmonitor.socketdir", &sock_dir);
> +
> + /* Create the socket file in either socketDir or $HOME */
> + if (sock_dir && *sock_dir)
> + strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
> + sock_dir, hash_to_hex(hash));
> + else
> + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
> +
> + ipc_path = interpolate_path(ipc_file.buf, 1);
> + if (!ipc_path)
> + die(_("Invalid path: %s"), ipc_file.buf);
> +
> + strbuf_release(&ipc_file);
> + return ipc_path;
> +}
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v6 3/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-14 0:48 ` Junio C Hamano
@ 2022-09-14 15:47 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-14 15:47 UTC (permalink / raw)
To: Junio C Hamano, Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Junio C Hamano <gitster@pobox.com>
> Sent: Tuesday, September 13, 2022 8:48 PM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Cc: git@vger.kernel.org; Jeff Hostetler <git@jeffhostetler.com>; Eric Sunshine
> <sunshine@sunshineco.com>; Torsten Bögershausen <tboegi@web.de>;
> Ævar Arnfjörð Bjarmason <avarab@gmail.com>; Ramsay Jones
> <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v6 3/6] fsmonitor: relocate socket file if .git directory is
> remote
>
> "Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > +const char *fsmonitor_ipc__get_path(void) {
>
> Looks like a bit klunky API. I would have expected it to take at least the path
> to the worktree or a pointer to struct repository.
>
OK, I'll change it to take a pointer to struct repository.
> > + static const char *ipc_path;
> > + SHA_CTX sha1ctx;
> > + char *sock_dir;
> > + struct strbuf ipc_file = STRBUF_INIT;
> > + unsigned char hash[SHA_DIGEST_LENGTH];
> > +
> > + if (ipc_path)
> > + return ipc_path;
> > +
> > + ipc_path = fsmonitor_ipc__get_default_path();
> > +
> > + /* By default the socket file is created in the .git directory */
> > + if (fsmonitor__is_fs_remote(ipc_path) < 1)
> > + return ipc_path;
> > +
> > + SHA1_Init(&sha1ctx);
> > + SHA1_Update(&sha1ctx, the_repository->worktree,
> strlen(the_repository->worktree));
> > + SHA1_Final(hash, &sha1ctx);
>
> I would not worry about SHA-1 hash collision for this use case, but would
> worry more about .worktree possible being unique.
>
> Can the .worktree string be aliased for the same directory in some way (e.g.
> depending on the initialization sequence, can it be a full pathname, a relative
> pathname, or can a pathname that looks like a full-pathname have symbolic
> link component in it?) that ends up creating two or more socket for the same
> worktree?
>
.worktree is set to the real path and since hardlinks are not allowed across file systems, I think we are OK.
> > + repo_config_get_string(the_repository, "fsmonitor.socketdir",
> > +&sock_dir);
> > +
> > + /* Create the socket file in either socketDir or $HOME */
> > + if (sock_dir && *sock_dir)
> > + strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
> > + sock_dir, hash_to_hex(hash));
> > + else
> > + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s",
> hash_to_hex(hash));
> > +
> > + ipc_path = interpolate_path(ipc_file.buf, 1);
> > + if (!ipc_path)
> > + die(_("Invalid path: %s"), ipc_file.buf);
> > +
> > + strbuf_release(&ipc_file);
> > + return ipc_path;
> > +}
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v6 4/6] fsmonitor: avoid socket location check if using hook
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-13 20:27 ` [PATCH v6 3/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-13 20:27 ` Eric DeCosta via GitGitGadget
2022-09-14 1:48 ` Junio C Hamano
2022-09-13 20:27 ` [PATCH v6 5/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
7 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-13 20:27 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..3463c71763e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v6 4/6] fsmonitor: avoid socket location check if using hook
2022-09-13 20:27 ` [PATCH v6 4/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-14 1:48 ` Junio C Hamano
0 siblings, 0 replies; 170+ messages in thread
From: Junio C Hamano @ 2022-09-14 1:48 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
"Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
> From: Eric DeCosta <edecosta@mathworks.com>
>
> If monitoring is done via fsmonitor hook rather than IPC there is no
> need to check if the location of the Unix Domain socket (UDS) file is
> on a remote filesystem.
Nicely done.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
> compat/fsmonitor/fsm-settings-win32.c | 2 +-
> fsmonitor-settings.c | 8 ++++----
> fsmonitor-settings.h | 2 +-
> 4 files changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
> index dba3ced6bb7..3463c71763e 100644
> --- a/compat/fsmonitor/fsm-settings-darwin.c
> +++ b/compat/fsmonitor/fsm-settings-darwin.c
> @@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
> return FSMONITOR_REASON_OK;
> }
>
> -enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
> +enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
> {
> enum fsmonitor_reason reason;
>
> - reason = check_uds_volume(r);
> - if (reason != FSMONITOR_REASON_OK)
> - return reason;
> + if (ipc) {
> + reason = check_uds_volume(r);
> + if (reason != FSMONITOR_REASON_OK)
> + return reason;
> + }
>
> return FSMONITOR_REASON_OK;
> }
> diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
> index d88b06ae610..a8af31b71de 100644
> --- a/compat/fsmonitor/fsm-settings-win32.c
> +++ b/compat/fsmonitor/fsm-settings-win32.c
> @@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
> return FSMONITOR_REASON_OK;
> }
>
> -enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
> +enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
> {
> enum fsmonitor_reason reason;
>
> diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
> index d288cbad479..531a1b6f956 100644
> --- a/fsmonitor-settings.c
> +++ b/fsmonitor-settings.c
> @@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
> }
> #endif
>
> -static enum fsmonitor_reason check_for_incompatible(struct repository *r)
> +static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
> {
> if (!r->worktree) {
> /*
> @@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
> reason = check_remote(r);
> if (reason != FSMONITOR_REASON_OK)
> return reason;
> - reason = fsm_os__incompatible(r);
> + reason = fsm_os__incompatible(r, ipc);
> if (reason != FSMONITOR_REASON_OK)
> return reason;
> }
> @@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
>
> void fsm_settings__set_ipc(struct repository *r)
> {
> - enum fsmonitor_reason reason = check_for_incompatible(r);
> + enum fsmonitor_reason reason = check_for_incompatible(r, 1);
>
> if (reason != FSMONITOR_REASON_OK) {
> fsm_settings__set_incompatible(r, reason);
> @@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
>
> void fsm_settings__set_hook(struct repository *r, const char *path)
> {
> - enum fsmonitor_reason reason = check_for_incompatible(r);
> + enum fsmonitor_reason reason = check_for_incompatible(r, 0);
>
> if (reason != FSMONITOR_REASON_OK) {
> fsm_settings__set_incompatible(r, reason);
> diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
> index d9c2605197f..0721617b95a 100644
> --- a/fsmonitor-settings.h
> +++ b/fsmonitor-settings.h
> @@ -48,7 +48,7 @@ struct fsmonitor_settings;
> * fsm_os__* routines should considered private to fsm_settings__
> * routines.
> */
> -enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
> +enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
> #endif /* HAVE_FSMONITOR_OS_SETTINGS */
>
> #endif /* FSMONITOR_SETTINGS_H */
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v6 5/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-13 20:27 ` [PATCH v6 4/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-13 20:27 ` Eric DeCosta via GitGitGadget
2022-09-13 20:27 ` [PATCH v6 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-13 20:27 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 6 ++
fsmonitor-path-utils.h | 36 ++++++++++
6 files changed, 164 insertions(+), 1 deletion(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..32475962c92 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ state.alias.alias = NULL;
+ state.alias.points_to = NULL;
+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
+ err = error(_("could not get worktree alias"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..179886bc15b 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -209,7 +210,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ path_k = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (!path_k)
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +241,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..13807f58e95 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,92 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR * dir;
+ int read;
+ int retval;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ retval = 0;
+ dir = opendir("/");
+ if (!dir)
+ return -1;
+
+ strbuf_init(&alias, 256);
+ 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));
+
+ 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) == 0)
+ && path[points_to.len] == '/') {
+ info->alias = strbuf_detach(&alias, NULL);
+ info->points_to = strbuf_detach(&points_to, NULL);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
+ path, info->alias, info->points_to);
+ retval = 0;
+ goto done;
+ }
+ } else if (errno != EINVAL) { /* Something other than not a link */
+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
+ retval = -1;
+ goto done;
+ }
+ }
+
+ done:
+ closedir(dir);
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ int len = info->alias ? strlen(info->alias) : 0;
+
+ if (!len)
+ return NULL;
+
+ if ((strncmp(info->alias, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
+ int ptr_len = strlen(info->points_to);
+ int rem_len = strlen(remainder);
+
+ strbuf_init(&tmp, ptr_len + rem_len);
+ strbuf_add(&tmp, info->points_to, ptr_len);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..98cbb430083 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
@@ -167,5 +170,8 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state,
*/
void fsmonitor_force_resync(struct fsmonitor_daemon_state *state);
+char *fsmonitor_resolve_alias(const char *path,
+ struct alias_info *alias);
+
#endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
#endif /* FSMONITOR_DAEMON_H */
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..50ef37e57bb 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,6 +1,14 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ char *alias;
+ char *points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
@@ -20,4 +28,32 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by set info.alias and
+ * info.points_to and is responsible for releasing it with `free(3)`
+ * when done.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it with `free(3)` when done.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v6 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-13 20:27 ` [PATCH v6 5/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-13 20:27 ` Eric DeCosta via GitGitGadget
2022-09-16 17:58 ` [PATCH v6 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Jeff Hostetler
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-13 20:27 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
system support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/git-fsmonitor--daemon.txt | 35 +++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..0adccd0eced 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -70,6 +70,41 @@ the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this my be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositores and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS).
+Usage of UDS requires the creation of a file which, by default, is created
+in the .git directory. If the fsmonitor daemon detects that the .git directory
+is on a network-mounted file system, it will create the UDS file in $HOME. If
+$HOME itself is on a network-mounted file system or if $HOME is not the desired
+location for the UDS file, 'fsmonitor.socketDir' may be set to any valid, local
+directory on a file system with proper support. Mac OS native file systems have
+the required support. File systems known to lack support include FAT32 and
+NTFS. Other file systems may or many not have the needed support; the fsmonitor
+daemon is not guaranteed to work with these file systems and such use is
+considered experimental.
+
+CONFIGURATION
+-------------
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+the fsmonitor daemon will pay attention to the following configuration
+variables:
+
+fsmonitor.allowRemote::
+ By default, the daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
+ this behavior.
+
+fsmonitor.socketDir::
+ This option is only used by the Mac OS implementation of the fsmonitor
+ daemon. If set, 'fsmonitor.socketDir' must be set to a valid, local
+ directory on a file system that can support Unix domain sockets (UDS).
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v6 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-13 20:27 ` [PATCH v6 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-16 17:58 ` Jeff Hostetler
2022-09-16 20:02 ` Eric DeCosta
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
7 siblings, 1 reply; 170+ messages in thread
From: Jeff Hostetler @ 2022-09-16 17:58 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget, git
Cc: Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On 9/13/22 4:27 PM, Eric DeCosta via GitGitGadget wrote:
> 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.
>
> 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
>
I've looked at v5 and v6 and I like the direction this is heading,
so I'll mark this LGTM. (I'm still traveling back from Git Merge,
so I haven't had time to test it out, but I think we should proceed
with it.)
Thanks for you patience and attention to detail on this!
Jeff
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v6 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-16 17:58 ` [PATCH v6 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Jeff Hostetler
@ 2022-09-16 20:02 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-16 20:02 UTC (permalink / raw)
To: Jeff Hostetler, Eric DeCosta via GitGitGadget, git
Cc: Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Jeff Hostetler <git@jeffhostetler.com>
> Sent: Friday, September 16, 2022 1:59 PM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>;
> git@vger.kernel.org
> Cc: Eric Sunshine <sunshine@sunshineco.com>; Torsten Bögershausen
> <tboegi@web.de>; Ævar Arnfjörð Bjarmason <avarab@gmail.com>; Ramsay
> Jones <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v6 0/6] fsmonitor: option to allow fsmonitor to run
> against network-mounted repos
>
>
>
> On 9/13/22 4:27 PM, Eric DeCosta via GitGitGadget wrote:
> > 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.
> >
> > 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
> >
>
> I've looked at v5 and v6 and I like the direction this is heading, so I'll mark this
> LGTM. (I'm still traveling back from Git Merge, so I haven't had time to test it
> out, but I think we should proceed with it.)
>
> Thanks for you patience and attention to detail on this!
> Jeff
Great! I just created v7 with some small updates based on Junio's feedback.
I think this landed in a pretty good place. I don't know that the plans are for fsmonitor on Linux, but I've already started tinkering around with an inotify-based implementation for that platform. The devil is in the details, of course, but it looks fairly straight-forward.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v7 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-13 20:27 ` [PATCH v6 0/6] " Eric DeCosta via GitGitGadget
` (6 preceding siblings ...)
2022-09-16 17:58 ` [PATCH v6 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Jeff Hostetler
@ 2022-09-16 19:53 ` Eric DeCosta via GitGitGadget
2022-09-16 19:53 ` [PATCH v7 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (7 more replies)
7 siblings, 8 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-16 19:53 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
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: deal with synthetic firmlinks on macOS
fsmonitor: add documentation for allowRemote and socketDir options
Documentation/git-fsmonitor--daemon.txt | 35 +++++
Makefile | 2 +
builtin/fsmonitor--daemon.c | 11 +-
compat/fsmonitor/fsm-ipc-darwin.c | 49 +++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 ++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 132 +++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 145 +++++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 70 +++------
compat/fsmonitor/fsm-settings-win32.c | 174 +----------------------
contrib/buildsystems/CMakeLists.txt | 4 +
fsmonitor--daemon.h | 6 +
fsmonitor-ipc.c | 18 ++-
fsmonitor-ipc.h | 4 +-
fsmonitor-path-utils.h | 59 ++++++++
fsmonitor-settings.c | 58 +++++++-
fsmonitor-settings.h | 2 +-
17 files changed, 547 insertions(+), 237 deletions(-)
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: d3fa443f97e3a8d75b51341e2d5bac380b7422df
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v7
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v7
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v6:
1: 3233c908c4a < -: ----------- fsmonitor: option to allow fsmonitor to run against network-mounted repos
2: d2a8fc6b707 = 1: 155a6890806 fsmonitor: refactor filesystem checks to common interface
3: edef029a298 ! 2: 075340bd2a7 fsmonitor: relocate socket file if .git directory is remote
@@ Makefile: ifdef FSMONITOR_DAEMON_BACKEND
ifdef FSMONITOR_OS_SETTINGS
+ ## builtin/fsmonitor--daemon.c ##
+@@ builtin/fsmonitor--daemon.c: static int fsmonitor_run_daemon(void)
+ * directory.)
+ */
+ strbuf_init(&state.path_ipc, 0);
+- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
++ strbuf_addstr(&state.path_ipc,
++ absolute_path(fsmonitor_ipc__get_path(the_repository)));
+
+ /*
+ * Confirm that we can create platform-specific resources for the
+
## compat/fsmonitor/fsm-ipc-darwin.c (new) ##
@@
+#include "cache.h"
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
-+const char *fsmonitor_ipc__get_path(void)
++const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+ if (ipc_path)
+ return ipc_path;
+
++ if (!r)
++ r = the_repository;
++
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+ return ipc_path;
+
+ SHA1_Init(&sha1ctx);
-+ SHA1_Update(&sha1ctx, the_repository->worktree, strlen(the_repository->worktree));
++ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
-+ repo_config_get_string(the_repository, "fsmonitor.socketdir", &sock_dir);
++ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir)
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
## compat/fsmonitor/fsm-ipc-win32.c (new) ##
@@
-+#include "cache.h"
++#include "config.h"
+#include "fsmonitor-ipc.h"
+
-+GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
++const char *fsmonitor_ipc__get_path(struct repository *r) {
++ static char *ret;
++ if (!ret)
++ ret = git_pathdup("fsmonitor--daemon.ipc");
++ return ret;
++}
+ \ No newline at end of file
+
+ ## compat/fsmonitor/fsm-settings-darwin.c ##
+@@
+ static enum fsmonitor_reason check_uds_volume(struct repository *r)
+ {
+ struct fs_info fs;
+- const char *ipc_path = fsmonitor_ipc__get_path();
++ const char *ipc_path = fsmonitor_ipc__get_path(r);
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
+
## contrib/buildsystems/CMakeLists.txt ##
@@ contrib/buildsystems/CMakeLists.txt: if(SUPPORTS_SIMPLE_IPC)
@@ contrib/buildsystems/CMakeLists.txt: if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
## fsmonitor-ipc.c ##
+@@ fsmonitor-ipc.c: int fsmonitor_ipc__is_supported(void)
+ return 0;
+ }
+
+-const char *fsmonitor_ipc__get_path(void)
++const char *fsmonitor_ipc__get_path(struct repository *r)
+ {
+ return NULL;
+ }
@@ fsmonitor-ipc.c: int fsmonitor_ipc__is_supported(void)
return 1;
}
@@ fsmonitor-ipc.c: int fsmonitor_ipc__is_supported(void)
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+- return ipc_get_active_state(fsmonitor_ipc__get_path());
++ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
+ }
+
+ static int spawn_daemon(void)
+@@ fsmonitor-ipc.c: int fsmonitor_ipc__send_query(const char *since_token,
+ trace2_data_string("fsm_client", NULL, "query/command", tok);
+
+ try_again:
+- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
+- &connection);
++ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
++ &options, &connection);
+
+ switch (state) {
+ case IPC_STATE__LISTENING:
+@@ fsmonitor-ipc.c: try_again:
+
+ case IPC_STATE__INVALID_PATH:
+ ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
+- fsmonitor_ipc__get_path());
++ fsmonitor_ipc__get_path(the_repository));
+ goto done;
+
+ case IPC_STATE__OTHER_ERROR:
+ default:
+ ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
+- fsmonitor_ipc__get_path());
++ fsmonitor_ipc__get_path(the_repository));
+ goto done;
+ }
+
+@@ fsmonitor-ipc.c: int fsmonitor_ipc__send_command(const char *command,
+ options.wait_if_busy = 1;
+ options.wait_if_not_found = 0;
+
+- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
+- &connection);
++ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
++ &options, &connection);
+ if (state != IPC_STATE__LISTENING) {
+ die(_("fsmonitor--daemon is not running"));
+ return -1;
+
+ ## fsmonitor-ipc.h ##
+@@
+
+ #include "simple-ipc.h"
+
++struct repository;
++
+ /*
+ * Returns true if built-in file system monitor daemon is defined
+ * for this platform.
+@@ fsmonitor-ipc.h: int fsmonitor_ipc__is_supported(void);
+ *
+ * Returns NULL if the daemon is not supported on this platform.
+ */
+-const char *fsmonitor_ipc__get_path(void);
++const char *fsmonitor_ipc__get_path(struct repository *r);
+
+ /*
+ * Try to determine whether there is a `git-fsmonitor--daemon` process
4: 3428bcf8763 = 3: 5518d2f3e03 fsmonitor: avoid socket location check if using hook
5: 9c1f408ae6d ! 4: 3a9fe473cf4 fsmonitor: deal with synthetic firmlinks on macOS
@@ fsmonitor--daemon.h: struct fsmonitor_daemon_state {
};
/*
-@@ fsmonitor--daemon.h: void fsmonitor_publish(struct fsmonitor_daemon_state *state,
- */
- void fsmonitor_force_resync(struct fsmonitor_daemon_state *state);
-
-+char *fsmonitor_resolve_alias(const char *path,
-+ struct alias_info *alias);
-+
- #endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
- #endif /* FSMONITOR_DAEMON_H */
## fsmonitor-path-utils.h ##
@@
-: ----------- > 5: 4d00adb1deb fsmonitor: deal with synthetic firmlinks on macOS
6: d2c95e34d3a = 6: 260591f5820 fsmonitor: add documentation for allowRemote and socketDir options
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v7 1/6] fsmonitor: refactor filesystem checks to common interface
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
@ 2022-09-16 19:53 ` Eric DeCosta via GitGitGadget
2022-09-16 19:53 ` [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (6 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-16 19:53 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index d9247ead45b..6e492a67547 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2237109b57f..b88494bf59b 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
2022-09-16 19:53 ` [PATCH v7 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-16 19:53 ` Eric DeCosta via GitGitGadget
2022-09-16 20:11 ` Junio C Hamano
2022-09-16 19:53 ` [PATCH v7 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
7 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-16 19:53 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote file system, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 49 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 ++
fsmonitor-ipc.c | 18 +++++-----
fsmonitor-ipc.h | 4 ++-
8 files changed, 75 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index 6e492a67547..58bb9248471 100644
--- a/Makefile
+++ b/Makefile
@@ -2034,6 +2034,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..c238ed9c5d7
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,49 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
+ char *sock_dir;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (ipc_path)
+ return ipc_path;
+
+ if (!r)
+ r = the_repository;
+
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
+ return ipc_path;
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir)
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ else
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..3a3a46db209
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
\ No newline at end of file
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..681d8bf963e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index b88494bf59b..7e7b6b9a362 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-16 19:53 ` [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-16 20:11 ` Junio C Hamano
2022-09-19 12:31 ` Jeff Hostetler
0 siblings, 1 reply; 170+ messages in thread
From: Junio C Hamano @ 2022-09-16 20:11 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
"Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
> +const char *fsmonitor_ipc__get_path(struct repository *r)
> +{
> + static const char *ipc_path;
> + SHA_CTX sha1ctx;
> + char *sock_dir;
> + struct strbuf ipc_file = STRBUF_INIT;
> + unsigned char hash[SHA_DIGEST_LENGTH];
> +
> + if (ipc_path)
> + return ipc_path;
> +
> + if (!r)
> + r = the_repository;
I'd prefer not to see this "NULL means the_repository". It would be
a different story if the caller does not necessarily have a ready
access to the_repository, but it is a global, so the caller can pass
the_repository and be more explicit. Giving two ways to the caller
to express same thing is not a good idea.
Thanks.
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-16 20:11 ` Junio C Hamano
@ 2022-09-19 12:31 ` Jeff Hostetler
2022-09-19 16:42 ` Junio C Hamano
0 siblings, 1 reply; 170+ messages in thread
From: Jeff Hostetler @ 2022-09-19 12:31 UTC (permalink / raw)
To: Junio C Hamano, Eric DeCosta via GitGitGadget
Cc: git, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On 9/16/22 4:11 PM, Junio C Hamano wrote:
> "Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
>> +const char *fsmonitor_ipc__get_path(struct repository *r)
>> +{
>> + static const char *ipc_path;
>> + SHA_CTX sha1ctx;
>> + char *sock_dir;
>> + struct strbuf ipc_file = STRBUF_INIT;
>> + unsigned char hash[SHA_DIGEST_LENGTH];
>> +
>> + if (ipc_path)
>> + return ipc_path;
>> +
>> + if (!r)
>> + r = the_repository;
>
> I'd prefer not to see this "NULL means the_repository". It would be
> a different story if the caller does not necessarily have a ready
> access to the_repository, but it is a global, so the caller can pass
> the_repository and be more explicit. Giving two ways to the caller
> to express same thing is not a good idea.
>
> Thanks.
>
To be fair, I added several "if (!r) r = the_repository;" statements
to the original public FSMonitor routines. There were obscure cases
where tests would sometimes randomly fail because "r" wasn't completely
passed down via some hard to isolate call stack. Offlist, AEvar told me
that he managed to isolate it and has a fix.
So eventually, we'll be able to get rid of all of these direct
references to "the_repository" and properly assume that "r" is
always passed down.
But for now, I think we should let this stay for safety.
Jeff
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-19 12:31 ` Jeff Hostetler
@ 2022-09-19 16:42 ` Junio C Hamano
2022-09-19 17:08 ` Jeff Hostetler
0 siblings, 1 reply; 170+ messages in thread
From: Junio C Hamano @ 2022-09-19 16:42 UTC (permalink / raw)
To: Jeff Hostetler
Cc: Eric DeCosta via GitGitGadget, git, Eric Sunshine,
Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
Jeff Hostetler <git@jeffhostetler.com> writes:
> On 9/16/22 4:11 PM, Junio C Hamano wrote:
>> "Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
>>
>>> +const char *fsmonitor_ipc__get_path(struct repository *r)
>>> +{
>>> + static const char *ipc_path;
>>> + SHA_CTX sha1ctx;
>>> + char *sock_dir;
>>> + struct strbuf ipc_file = STRBUF_INIT;
>>> + unsigned char hash[SHA_DIGEST_LENGTH];
>>> +
>>> + if (ipc_path)
>>> + return ipc_path;
>>> +
>>> + if (!r)
>>> + r = the_repository;
>> I'd prefer not to see this "NULL means the_repository". It would be
>> a different story if the caller does not necessarily have a ready
>> access to the_repository, but it is a global, so the caller can pass
>> the_repository and be more explicit. Giving two ways to the caller
>> to express same thing is not a good idea.
>> Thanks.
>>
>
> To be fair, I added several "if (!r) r = the_repository;" statements
> to the original public FSMonitor routines. There were obscure cases
> where tests would sometimes randomly fail because "r" wasn't completely
> passed down via some hard to isolate call stack. Offlist, AEvar told me
> that he managed to isolate it and has a fix.
>
> So eventually, we'll be able to get rid of all of these direct
> references to "the_repository" and properly assume that "r" is
> always passed down.
>
> But for now, I think we should let this stay for safety.
I wouldn't call "sweeping a breakage under the rug" a "safety",
though. If the caller cannot decide which repository instance is
the right thing to pass, or the caller does not yet have a good one
to pass when making a call down the codepath, how can it be safer to
use the_repository that may or may not be the appropriate one than
noticing the problem by dying and stopping the spread of damage?
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-19 16:42 ` Junio C Hamano
@ 2022-09-19 17:08 ` Jeff Hostetler
2022-09-19 17:49 ` Junio C Hamano
0 siblings, 1 reply; 170+ messages in thread
From: Jeff Hostetler @ 2022-09-19 17:08 UTC (permalink / raw)
To: Junio C Hamano
Cc: Eric DeCosta via GitGitGadget, git, Eric Sunshine,
Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On 9/19/22 12:42 PM, Junio C Hamano wrote:
> Jeff Hostetler <git@jeffhostetler.com> writes:
>
>> On 9/16/22 4:11 PM, Junio C Hamano wrote:
>>> "Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
>>>
>>>> +const char *fsmonitor_ipc__get_path(struct repository *r)
>>>> +{
>>>> + static const char *ipc_path;
>>>> + SHA_CTX sha1ctx;
>>>> + char *sock_dir;
>>>> + struct strbuf ipc_file = STRBUF_INIT;
>>>> + unsigned char hash[SHA_DIGEST_LENGTH];
>>>> +
>>>> + if (ipc_path)
>>>> + return ipc_path;
>>>> +
>>>> + if (!r)
>>>> + r = the_repository;
>>> I'd prefer not to see this "NULL means the_repository". It would be
>>> a different story if the caller does not necessarily have a ready
>>> access to the_repository, but it is a global, so the caller can pass
>>> the_repository and be more explicit. Giving two ways to the caller
>>> to express same thing is not a good idea.
>>> Thanks.
>>>
>>
>> To be fair, I added several "if (!r) r = the_repository;" statements
>> to the original public FSMonitor routines. There were obscure cases
>> where tests would sometimes randomly fail because "r" wasn't completely
>> passed down via some hard to isolate call stack. Offlist, AEvar told me
>> that he managed to isolate it and has a fix.
>>
>> So eventually, we'll be able to get rid of all of these direct
>> references to "the_repository" and properly assume that "r" is
>> always passed down.
>>
>> But for now, I think we should let this stay for safety.
>
> I wouldn't call "sweeping a breakage under the rug" a "safety",
> though. If the caller cannot decide which repository instance is
> the right thing to pass, or the caller does not yet have a good one
> to pass when making a call down the codepath, how can it be safer to
> use the_repository that may or may not be the appropriate one than
> noticing the problem by dying and stopping the spread of damage?
>
Aren't we in the middle of a transition from always
using the global "the_repository" to a passed "r" variable?
We're getting closer to being able to hide the the global
symbol, but we're not there yet, right?
I'm thinking that at as long as the global exists, we are not
safe to have multiple "struct repository" instances, right?
All I'm saying is that there are obscure/edge code paths where
a valid "r" is not being passed down. Or, more likely, someone
has an "istate" that doesn't yet have "istate->repo" set at the
point of the call, so they might be passing "istate->repo", but
it is null.
Tracking down these nulls is important, but shouldn't it be
independent of this one?
Jeff
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-19 17:08 ` Jeff Hostetler
@ 2022-09-19 17:49 ` Junio C Hamano
2022-09-19 23:51 ` Eric DeCosta
0 siblings, 1 reply; 170+ messages in thread
From: Junio C Hamano @ 2022-09-19 17:49 UTC (permalink / raw)
To: Jeff Hostetler
Cc: Eric DeCosta via GitGitGadget, git, Eric Sunshine,
Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
Jeff Hostetler <git@jeffhostetler.com> writes:
> Aren't we in the middle of a transition from always
> using the global "the_repository" to a passed "r" variable?
> We're getting closer to being able to hide the the global
> symbol, but we're not there yet, right?
We may still have code that works ONLY on the_repository, but
letting a function take "r" and lettin it ignore is worse than
leaving it explicitly limited to the_repository only, no?
> I'm thinking that at as long as the global exists, we are not
> safe to have multiple "struct repository" instances, right?
By itself, Not at all. It is the code like I am criticizing that
makes it unsafe.
I do not mind adding
if (!r)
BUG(...);
at the place you have the "sweep it under the rug" band-aid, though.
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-19 17:49 ` Junio C Hamano
@ 2022-09-19 23:51 ` Eric DeCosta
2022-09-20 14:35 ` Jeff Hostetler
0 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta @ 2022-09-19 23:51 UTC (permalink / raw)
To: Junio C Hamano, Jeff Hostetler
Cc: Eric DeCosta via GitGitGadget, git, Eric Sunshine,
Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Junio C Hamano <gitster@pobox.com>
> Sent: Monday, September 19, 2022 1:49 PM
> To: Jeff Hostetler <git@jeffhostetler.com>
> Cc: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>;
> git@vger.kernel.org; Eric Sunshine <sunshine@sunshineco.com>; Torsten
> Bögershausen <tboegi@web.de>; Ævar Arnfjörð Bjarmason
> <avarab@gmail.com>; Ramsay Jones <ramsay@ramsayjones.plus.com>;
> Johannes Schindelin <Johannes.Schindelin@gmx.de>; Eric DeCosta
> <edecosta@mathworks.com>
> Subject: Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is
> remote
>
> Jeff Hostetler <git@jeffhostetler.com> writes:
>
> > Aren't we in the middle of a transition from always using the global
> > "the_repository" to a passed "r" variable?
> > We're getting closer to being able to hide the the global symbol, but
> > we're not there yet, right?
>
> We may still have code that works ONLY on the_repository, but letting a
> function take "r" and lettin it ignore is worse than leaving it explicitly limited
> to the_repository only, no?
>
> > I'm thinking that at as long as the global exists, we are not safe to
> > have multiple "struct repository" instances, right?
>
> By itself, Not at all. It is the code like I am criticizing that makes it unsafe.
>
> I do not mind adding
>
> if (!r)
> BUG(...);
>
> at the place you have the "sweep it under the rug" band-aid, though.
Appreciate all the insights and comments. Where are we landing with this? Very close to the finish line and I'd like to be able to push these changes over that line.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-19 23:51 ` Eric DeCosta
@ 2022-09-20 14:35 ` Jeff Hostetler
2022-09-20 15:49 ` Eric DeCosta
0 siblings, 1 reply; 170+ messages in thread
From: Jeff Hostetler @ 2022-09-20 14:35 UTC (permalink / raw)
To: Eric DeCosta, Junio C Hamano
Cc: Eric DeCosta via GitGitGadget, git, Eric Sunshine,
Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
On 9/19/22 7:51 PM, Eric DeCosta wrote:
>
>
>> -----Original Message-----
>> From: Junio C Hamano <gitster@pobox.com>
>> Sent: Monday, September 19, 2022 1:49 PM
>> To: Jeff Hostetler <git@jeffhostetler.com>
>> Cc: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>;
>> git@vger.kernel.org; Eric Sunshine <sunshine@sunshineco.com>; Torsten
>> Bögershausen <tboegi@web.de>; Ævar Arnfjörð Bjarmason
>> <avarab@gmail.com>; Ramsay Jones <ramsay@ramsayjones.plus.com>;
>> Johannes Schindelin <Johannes.Schindelin@gmx.de>; Eric DeCosta
>> <edecosta@mathworks.com>
>> Subject: Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is
>> remote
>>
>> Jeff Hostetler <git@jeffhostetler.com> writes:
>>
>>> Aren't we in the middle of a transition from always using the global
>>> "the_repository" to a passed "r" variable?
>>> We're getting closer to being able to hide the the global symbol, but
>>> we're not there yet, right?
>>
>> We may still have code that works ONLY on the_repository, but letting a
>> function take "r" and lettin it ignore is worse than leaving it explicitly limited
>> to the_repository only, no?
>>
>>> I'm thinking that at as long as the global exists, we are not safe to
>>> have multiple "struct repository" instances, right?
>>
>> By itself, Not at all. It is the code like I am criticizing that makes it unsafe.
>>
>> I do not mind adding
>>
>> if (!r)
>> BUG(...);
>>
>> at the place you have the "sweep it under the rug" band-aid, though.
>
> Appreciate all the insights and comments. Where are we landing with this? Very close to the finish line and I'd like to be able to push these changes over that line.
>
> -Eric
>
I'm OK doing it either way. Junio seems to prefer the BUG() version,
so let's go with that. That lets us make progress on getting rid of
direct references to "the_repository".
Jeff
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-20 14:35 ` Jeff Hostetler
@ 2022-09-20 15:49 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-20 15:49 UTC (permalink / raw)
To: Jeff Hostetler, Junio C Hamano
Cc: Eric DeCosta via GitGitGadget, git, Eric Sunshine,
Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Jeff Hostetler <git@jeffhostetler.com>
> Sent: Tuesday, September 20, 2022 10:36 AM
> To: Eric DeCosta <edecosta@mathworks.com>; Junio C Hamano
> <gitster@pobox.com>
> Cc: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>;
> git@vger.kernel.org; Eric Sunshine <sunshine@sunshineco.com>; Torsten
> Bögershausen <tboegi@web.de>; Ævar Arnfjörð Bjarmason
> <avarab@gmail.com>; Ramsay Jones <ramsay@ramsayjones.plus.com>;
> Johannes Schindelin <Johannes.Schindelin@gmx.de>
> Subject: Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is
> remote
>
>
>
> On 9/19/22 7:51 PM, Eric DeCosta wrote:
> >
> >
> >> -----Original Message-----
> >> From: Junio C Hamano <gitster@pobox.com>
> >> Sent: Monday, September 19, 2022 1:49 PM
> >> To: Jeff Hostetler <git@jeffhostetler.com>
> >> Cc: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>;
> >> git@vger.kernel.org; Eric Sunshine <sunshine@sunshineco.com>; Torsten
> >> Bögershausen <tboegi@web.de>; Ævar Arnfjörð Bjarmason
> >> <avarab@gmail.com>; Ramsay Jones <ramsay@ramsayjones.plus.com>;
> >> Johannes Schindelin <Johannes.Schindelin@gmx.de>; Eric DeCosta
> >> <edecosta@mathworks.com>
> >> Subject: Re: [PATCH v7 2/6] fsmonitor: relocate socket file if .git
> >> directory is remote
> >>
> >> Jeff Hostetler <git@jeffhostetler.com> writes:
> >>
> >>> Aren't we in the middle of a transition from always using the global
> >>> "the_repository" to a passed "r" variable?
> >>> We're getting closer to being able to hide the the global symbol,
> >>> but we're not there yet, right?
> >>
> >> We may still have code that works ONLY on the_repository, but letting
> >> a function take "r" and lettin it ignore is worse than leaving it
> >> explicitly limited to the_repository only, no?
> >>
> >>> I'm thinking that at as long as the global exists, we are not safe
> >>> to have multiple "struct repository" instances, right?
> >>
> >> By itself, Not at all. It is the code like I am criticizing that makes it unsafe.
> >>
> >> I do not mind adding
> >>
> >> if (!r)
> >> BUG(...);
> >>
> >> at the place you have the "sweep it under the rug" band-aid, though.
> >
> > Appreciate all the insights and comments. Where are we landing with this?
> Very close to the finish line and I'd like to be able to push these changes over
> that line.
> >
> > -Eric
> >
>
> I'm OK doing it either way. Junio seems to prefer the BUG() version, so let's
> go with that. That lets us make progress on getting rid of direct references to
> "the_repository".
>
> Jeff
Sounds like a plan!
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v7 3/6] fsmonitor: avoid socket location check if using hook
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
2022-09-16 19:53 ` [PATCH v7 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-16 19:53 ` [PATCH v7 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-16 19:53 ` Eric DeCosta via GitGitGadget
2022-09-16 19:53 ` [PATCH v7 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-16 19:53 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 681d8bf963e..40da2d3b533 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v7 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-16 19:53 ` [PATCH v7 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-16 19:53 ` Eric DeCosta via GitGitGadget
2022-09-16 19:53 ` [PATCH v7 5/6] " Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-16 19:53 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 ++++++++++
6 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..56fcd1c2baa 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ state.alias.alias = NULL;
+ state.alias.points_to = NULL;
+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
+ err = error(_("could not get worktree alias"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..179886bc15b 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -209,7 +210,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ path_k = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (!path_k)
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +241,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..13807f58e95 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,92 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR * dir;
+ int read;
+ int retval;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ retval = 0;
+ dir = opendir("/");
+ if (!dir)
+ return -1;
+
+ strbuf_init(&alias, 256);
+ 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));
+
+ 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) == 0)
+ && path[points_to.len] == '/') {
+ info->alias = strbuf_detach(&alias, NULL);
+ info->points_to = strbuf_detach(&points_to, NULL);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
+ path, info->alias, info->points_to);
+ retval = 0;
+ goto done;
+ }
+ } else if (errno != EINVAL) { /* Something other than not a link */
+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
+ retval = -1;
+ goto done;
+ }
+ }
+
+ done:
+ closedir(dir);
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ int len = info->alias ? strlen(info->alias) : 0;
+
+ if (!len)
+ return NULL;
+
+ if ((strncmp(info->alias, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
+ int ptr_len = strlen(info->points_to);
+ int rem_len = strlen(remainder);
+
+ strbuf_init(&tmp, ptr_len + rem_len);
+ strbuf_add(&tmp, info->points_to, ptr_len);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..50ef37e57bb 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,6 +1,14 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ char *alias;
+ char *points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
@@ -20,4 +28,32 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by set info.alias and
+ * info.points_to and is responsible for releasing it with `free(3)`
+ * when done.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it with `free(3)` when done.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v7 5/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-16 19:53 ` [PATCH v7 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-16 19:53 ` Eric DeCosta via GitGitGadget
2022-09-16 20:15 ` Junio C Hamano
2022-09-16 19:53 ` [PATCH v7 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
7 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-16 19:53 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
fsmonitor--daemon.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index e24838f9a86..98cbb430083 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -170,5 +170,8 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state,
*/
void fsmonitor_force_resync(struct fsmonitor_daemon_state *state);
+char *fsmonitor_resolve_alias(const char *path,
+ struct alias_info *alias);
+
#endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
#endif /* FSMONITOR_DAEMON_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v7 5/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-16 19:53 ` [PATCH v7 5/6] " Eric DeCosta via GitGitGadget
@ 2022-09-16 20:15 ` Junio C Hamano
0 siblings, 0 replies; 170+ messages in thread
From: Junio C Hamano @ 2022-09-16 20:15 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
"Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
> Starting with macOS 10.15 (Catalina), Apple introduced a new feature
> called 'firmlinks' in order to separate the boot volume into two
> volumes, one read-only and one writable but still present them to the
> user as a single volume. Along with this change, Apple removed the
> ...
> Therefore, in order to deal with synthetic firmlinks, the root directory
> is scanned and the first possible synthetic firmink that, when resolved,
> is a prefix of the worktree is used to map FSEvents paths to worktree
> paths.
The proposed log message for this step seems fairly similar to the
previous one.
> diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
> index e24838f9a86..98cbb430083 100644
> --- a/fsmonitor--daemon.h
> +++ b/fsmonitor--daemon.h
> @@ -170,5 +170,8 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state,
> */
> void fsmonitor_force_resync(struct fsmonitor_daemon_state *state);
>
> +char *fsmonitor_resolve_alias(const char *path,
> + struct alias_info *alias);
> +
After applying all the 6 steps, this function is declared here
without any implementation. Should we drop this step, I have to
wonder.
Thanks.
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v7 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-16 19:53 ` [PATCH v7 5/6] " Eric DeCosta via GitGitGadget
@ 2022-09-16 19:53 ` Eric DeCosta via GitGitGadget
2022-09-16 20:09 ` [PATCH v7 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Junio C Hamano
2022-09-17 1:12 ` [PATCH v8 0/5] " Eric DeCosta via GitGitGadget
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-16 19:53 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
system support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/git-fsmonitor--daemon.txt | 35 +++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..0adccd0eced 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -70,6 +70,41 @@ the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this my be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositores and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS).
+Usage of UDS requires the creation of a file which, by default, is created
+in the .git directory. If the fsmonitor daemon detects that the .git directory
+is on a network-mounted file system, it will create the UDS file in $HOME. If
+$HOME itself is on a network-mounted file system or if $HOME is not the desired
+location for the UDS file, 'fsmonitor.socketDir' may be set to any valid, local
+directory on a file system with proper support. Mac OS native file systems have
+the required support. File systems known to lack support include FAT32 and
+NTFS. Other file systems may or many not have the needed support; the fsmonitor
+daemon is not guaranteed to work with these file systems and such use is
+considered experimental.
+
+CONFIGURATION
+-------------
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+the fsmonitor daemon will pay attention to the following configuration
+variables:
+
+fsmonitor.allowRemote::
+ By default, the daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
+ this behavior.
+
+fsmonitor.socketDir::
+ This option is only used by the Mac OS implementation of the fsmonitor
+ daemon. If set, 'fsmonitor.socketDir' must be set to a valid, local
+ directory on a file system that can support Unix domain sockets (UDS).
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v7 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-16 19:53 ` [PATCH v7 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-16 20:09 ` Junio C Hamano
2022-09-17 1:12 ` [PATCH v8 0/5] " Eric DeCosta via GitGitGadget
7 siblings, 0 replies; 170+ messages in thread
From: Junio C Hamano @ 2022-09-16 20:09 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
"Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
> 5: 9c1f408ae6d ! 4: 3a9fe473cf4 fsmonitor: deal with synthetic firmlinks on macOS
> @@ fsmonitor--daemon.h: struct fsmonitor_daemon_state {
> };
>
> /*
> -@@ fsmonitor--daemon.h: void fsmonitor_publish(struct fsmonitor_daemon_state *state,
> - */
> - void fsmonitor_force_resync(struct fsmonitor_daemon_state *state);
> -
> -+char *fsmonitor_resolve_alias(const char *path,
> -+ struct alias_info *alias);
> -+
> - #endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
> - #endif /* FSMONITOR_DAEMON_H */
>
> ## fsmonitor-path-utils.h ##
> @@
> -: ----------- > 5: 4d00adb1deb fsmonitor: deal with synthetic firmlinks on macOS
"rebase -i" mistake or something?
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v8 0/5] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-16 19:53 ` [PATCH v7 " Eric DeCosta via GitGitGadget
` (6 preceding siblings ...)
2022-09-16 20:09 ` [PATCH v7 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Junio C Hamano
@ 2022-09-17 1:12 ` Eric DeCosta via GitGitGadget
2022-09-17 1:12 ` [PATCH v8 1/5] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (5 more replies)
7 siblings, 6 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-17 1:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
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 (5):
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: add documentation for allowRemote and socketDir options
Documentation/git-fsmonitor--daemon.txt | 35 +++++
Makefile | 2 +
builtin/fsmonitor--daemon.c | 11 +-
compat/fsmonitor/fsm-ipc-darwin.c | 46 ++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 ++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 132 +++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 145 +++++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 70 +++------
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 | 59 ++++++++
fsmonitor-settings.c | 58 +++++++-
fsmonitor-settings.h | 2 +-
17 files changed, 541 insertions(+), 237 deletions(-)
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: d3fa443f97e3a8d75b51341e2d5bac380b7422df
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v8
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v8
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v7:
1: 155a6890806 = 1: 155a6890806 fsmonitor: refactor filesystem checks to common interface
2: 075340bd2a7 ! 2: b5356497228 fsmonitor: relocate socket file if .git directory is remote
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+ if (ipc_path)
+ return ipc_path;
+
-+ if (!r)
-+ r = the_repository;
-+
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
3: 5518d2f3e03 = 3: 6719ca2b24d fsmonitor: avoid socket location check if using hook
4: 3a9fe473cf4 ! 4: d736cb8fa90 fsmonitor: deal with synthetic firmlinks on macOS
@@ Commit message
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
+ fsmonitor: deal with synthetic firmlinks on macOS
+
+ Starting with macOS 10.15 (Catalina), Apple introduced a new feature
+ called 'firmlinks' in order to separate the boot volume into two
+ volumes, one read-only and one writable but still present them to the
+ user as a single volume. Along with this change, Apple removed the
+ ability to create symlinks in the root directory and replaced them with
+ 'synthetic firmlinks'. See 'man synthetic.conf'
+
+ When FSEevents reports the path of changed files, if the path involves
+ a synthetic firmlink, the path is reported from the point of the
+ synthetic firmlink and not the real path. For example:
+
+ Real path:
+ /System/Volumes/Data/network/working/directory/foo.txt
+
+ Synthetic firmlink:
+ /network -> /System/Volumes/Data/network
+
+ FSEvents path:
+ /network/working/directory/foo.txt
+
+ This causes the FSEvents path to not match against the worktree
+ directory.
+
+ There are several ways in which synthetic firmlinks can be created:
+ they can be defined in /etc/synthetic.conf, the automounter can create
+ them, and there may be other means. Simply reading /etc/synthetic.conf
+ is insufficient. No matter what process creates synthetic firmlinks,
+ they all get created in the root directory.
+
+ Therefore, in order to deal with synthetic firmlinks, the root directory
+ is scanned and the first possible synthetic firmink that, when resolved,
+ is a prefix of the worktree is used to map FSEvents paths to worktree
+ paths.
+
+ Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
+
+ fsmonitor: deal with synthetic firmlinks on macOS
+
+ Starting with macOS 10.15 (Catalina), Apple introduced a new feature
+ called 'firmlinks' in order to separate the boot volume into two
+ volumes, one read-only and one writable but still present them to the
+ user as a single volume. Along with this change, Apple removed the
+ ability to create symlinks in the root directory and replaced them with
+ 'synthetic firmlinks'. See 'man synthetic.conf'
+
+ When FSEevents reports the path of changed files, if the path involves
+ a synthetic firmlink, the path is reported from the point of the
+ synthetic firmlink and not the real path. For example:
+
+ Real path:
+ /System/Volumes/Data/network/working/directory/foo.txt
+
+ Synthetic firmlink:
+ /network -> /System/Volumes/Data/network
+
+ FSEvents path:
+ /network/working/directory/foo.txt
+
+ This causes the FSEvents path to not match against the worktree
+ directory.
+
+ There are several ways in which synthetic firmlinks can be created:
+ they can be defined in /etc/synthetic.conf, the automounter can create
+ them, and there may be other means. Simply reading /etc/synthetic.conf
+ is insufficient. No matter what process creates synthetic firmlinks,
+ they all get created in the root directory.
+
+ Therefore, in order to deal with synthetic firmlinks, the root directory
+ is scanned and the first possible synthetic firmink that, when resolved,
+ is a prefix of the worktree is used to map FSEvents paths to worktree
+ paths.
+
+ Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
+
## builtin/fsmonitor--daemon.c ##
@@
#include "parse-options.h"
5: 4d00adb1deb < -: ----------- fsmonitor: deal with synthetic firmlinks on macOS
6: 260591f5820 = 5: ddf4e3e6442 fsmonitor: add documentation for allowRemote and socketDir options
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v8 1/5] fsmonitor: refactor filesystem checks to common interface
2022-09-17 1:12 ` [PATCH v8 0/5] " Eric DeCosta via GitGitGadget
@ 2022-09-17 1:12 ` Eric DeCosta via GitGitGadget
2022-09-17 1:12 ` [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
5 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-17 1:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index d9247ead45b..6e492a67547 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2237109b57f..b88494bf59b 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote
2022-09-17 1:12 ` [PATCH v8 0/5] " Eric DeCosta via GitGitGadget
2022-09-17 1:12 ` [PATCH v8 1/5] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-17 1:12 ` Eric DeCosta via GitGitGadget
2022-09-17 4:13 ` Eric Sunshine
2022-09-17 6:29 ` Eric Sunshine
2022-09-17 1:12 ` [PATCH v8 3/5] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
5 siblings, 2 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-17 1:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote file system, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 46 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 ++
fsmonitor-ipc.c | 18 +++++-----
fsmonitor-ipc.h | 4 ++-
8 files changed, 72 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index 6e492a67547..58bb9248471 100644
--- a/Makefile
+++ b/Makefile
@@ -2034,6 +2034,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..d6628185000
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,46 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
+ char *sock_dir;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (ipc_path)
+ return ipc_path;
+
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
+ return ipc_path;
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir)
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ else
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..3a3a46db209
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
\ No newline at end of file
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..681d8bf963e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index b88494bf59b..7e7b6b9a362 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote
2022-09-17 1:12 ` [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-17 4:13 ` Eric Sunshine
2022-09-19 16:50 ` Junio C Hamano
2022-09-17 6:29 ` Eric Sunshine
1 sibling, 1 reply; 170+ messages in thread
From: Eric Sunshine @ 2022-09-17 4:13 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: Git List, Jeff Hostetler, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On Fri, Sep 16, 2022 at 9:12 PM Eric DeCosta via GitGitGadget
<gitgitgadget@gmail.com> wrote:
> If the .git directory is on a remote file system, create the socket
> file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
> @@ -0,0 +1,9 @@
> +#include "config.h"
> +#include "fsmonitor-ipc.h"
> +
> +const char *fsmonitor_ipc__get_path(struct repository *r) {
> + static char *ret;
> + if (!ret)
> + ret = git_pathdup("fsmonitor--daemon.ipc");
> + return ret;
> +}
> \ No newline at end of file
This file probably wants a final line terminator.
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote
2022-09-17 4:13 ` Eric Sunshine
@ 2022-09-19 16:50 ` Junio C Hamano
0 siblings, 0 replies; 170+ messages in thread
From: Junio C Hamano @ 2022-09-19 16:50 UTC (permalink / raw)
To: Eric Sunshine
Cc: Eric DeCosta via GitGitGadget, Git List, Jeff Hostetler,
Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
Eric Sunshine <sunshine@sunshineco.com> writes:
> On Fri, Sep 16, 2022 at 9:12 PM Eric DeCosta via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
>> +}
>> \ No newline at end of file
>
> This file probably wants a final line terminator.
definitely ;-)
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote
2022-09-17 1:12 ` [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
2022-09-17 4:13 ` Eric Sunshine
@ 2022-09-17 6:29 ` Eric Sunshine
2022-09-17 16:29 ` Eric DeCosta
2022-09-19 16:58 ` Junio C Hamano
1 sibling, 2 replies; 170+ messages in thread
From: Eric Sunshine @ 2022-09-17 6:29 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: Git List, Jeff Hostetler, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On Fri, Sep 16, 2022 at 9:12 PM Eric DeCosta via GitGitGadget
<gitgitgadget@gmail.com> wrote:
> If the .git directory is on a remote file system, create the socket
> file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
> @@ -0,0 +1,46 @@
> +static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
> +
> +const char *fsmonitor_ipc__get_path(struct repository *r)
> +{
> + static const char *ipc_path;
> + SHA_CTX sha1ctx;
> + char *sock_dir;
> + struct strbuf ipc_file = STRBUF_INIT;
> + unsigned char hash[SHA_DIGEST_LENGTH];
> +
> + if (ipc_path)
> + return ipc_path;
> +
> + ipc_path = fsmonitor_ipc__get_default_path();
> +
> + /* By default the socket file is created in the .git directory */
> + if (fsmonitor__is_fs_remote(ipc_path) < 1)
> + return ipc_path;
> +
> + SHA1_Init(&sha1ctx);
> + SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
> + SHA1_Final(hash, &sha1ctx);
> +
> + repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
> +
> + /* Create the socket file in either socketDir or $HOME */
> + if (sock_dir && *sock_dir)
> + strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
> + sock_dir, hash_to_hex(hash));
> + else
> + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
A couple comments...
In my mind, the directory specified by `fsmonitor.socketdir` is likely
to be dedicated to this purpose (i.e. housing Git administrative
junk). As such, it feels somewhat odd for the socket file to be
hidden; I would instead expect the socket name to be non-hidden (say,
"git-fsmonitor-daemon-{hash}.ipc") rather than hidden
(".git-fsmonitor-*"). The directory specified by `fsmonitor.socketdir`
may or may not be hidden (i.e. start with a dot), but that's the
user's decision. For the $HOME case, it almost feels cleaner to create
a hidden directory (say, "$HOME/.git-fsmonitor") in which to house the
socket files ("git-fsmonitor-daemon-{hash}.ipc"). Anyhow, this comment
is quite subjective; perhaps not actionable.
What happens if either $HOME or `fsmonitor.socketdir` are
network-mounted? Should this code be checking for that case? If they
are network-mounted, should it error out? At minimum, I would think a
warning is warranted in order to save users the headache of wondering
why fsmonitor isn't working correctly.
> + ipc_path = interpolate_path(ipc_file.buf, 1);
> + if (!ipc_path)
> + die(_("Invalid path: %s"), ipc_file.buf);
> +
> + strbuf_release(&ipc_file);
`sock_dir` is being leaked, isn't it?
> + return ipc_path;
> +}
> diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
> @@ -0,0 +1,9 @@
> +const char *fsmonitor_ipc__get_path(struct repository *r) {
> + static char *ret;
> + if (!ret)
> + ret = git_pathdup("fsmonitor--daemon.ipc");
> + return ret;
> +}
> \ No newline at end of file
Mentioned already.
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote
2022-09-17 6:29 ` Eric Sunshine
@ 2022-09-17 16:29 ` Eric DeCosta
2022-09-19 16:58 ` Junio C Hamano
1 sibling, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-17 16:29 UTC (permalink / raw)
To: Eric Sunshine, Eric DeCosta via GitGitGadget
Cc: Git List, Jeff Hostetler, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Eric Sunshine <sunshine@sunshineco.com>
> Sent: Saturday, September 17, 2022 2:30 AM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Cc: Git List <git@vger.kernel.org>; Jeff Hostetler <git@jeffhostetler.com>;
> Torsten Bögershausen <tboegi@web.de>; Ævar Arnfjörð Bjarmason
> <avarab@gmail.com>; Ramsay Jones <ramsay@ramsayjones.plus.com>;
> Johannes Schindelin <Johannes.Schindelin@gmx.de>; Eric DeCosta
> <edecosta@mathworks.com>
> Subject: Re: [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is
> remote
>
> On Fri, Sep 16, 2022 at 9:12 PM Eric DeCosta via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
> > If the .git directory is on a remote file system, create the socket
> > file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
> >
> > Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> > ---
> > diff --git a/compat/fsmonitor/fsm-ipc-darwin.c
> > b/compat/fsmonitor/fsm-ipc-darwin.c
> > @@ -0,0 +1,46 @@
> > +static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path,
> > +"fsmonitor--daemon.ipc")
> > +
> > +const char *fsmonitor_ipc__get_path(struct repository *r) {
> > + static const char *ipc_path;
> > + SHA_CTX sha1ctx;
> > + char *sock_dir;
> > + struct strbuf ipc_file = STRBUF_INIT;
> > + unsigned char hash[SHA_DIGEST_LENGTH];
> > +
> > + if (ipc_path)
> > + return ipc_path;
> > +
> > + ipc_path = fsmonitor_ipc__get_default_path();
> > +
> > + /* By default the socket file is created in the .git directory */
> > + if (fsmonitor__is_fs_remote(ipc_path) < 1)
> > + return ipc_path;
> > +
> > + SHA1_Init(&sha1ctx);
> > + SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
> > + SHA1_Final(hash, &sha1ctx);
> > +
> > + repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
> > +
> > + /* Create the socket file in either socketDir or $HOME */
> > + if (sock_dir && *sock_dir)
> > + strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
> > + sock_dir, hash_to_hex(hash));
> > + else
> > + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s",
> > + hash_to_hex(hash));
>
> A couple comments...
>
> In my mind, the directory specified by `fsmonitor.socketdir` is likely to be
> dedicated to this purpose (i.e. housing Git administrative junk). As such, it
> feels somewhat odd for the socket file to be hidden; I would instead expect
> the socket name to be non-hidden (say,
> "git-fsmonitor-daemon-{hash}.ipc") rather than hidden (".git-fsmonitor-*").
> The directory specified by `fsmonitor.socketdir` may or may not be hidden
> (i.e. start with a dot), but that's the user's decision. For the $HOME case, it
> almost feels cleaner to create a hidden directory (say, "$HOME/.git-
> fsmonitor") in which to house the socket files ("git-fsmonitor-daemon-
> {hash}.ipc"). Anyhow, this comment is quite subjective; perhaps not
> actionable.
> What happens if either $HOME or `fsmonitor.socketdir` are network-
> mounted? Should this code be checking for that case? If they are network-
> mounted, should it error out? At minimum, I would think a warning is
> warranted in order to save users the headache of wondering why fsmonitor
> isn't working correctly.
>
Ultimately, the UDS file location is checked by check_uds_volume in fsm-settings-darwin as part of the overall settings checks; it will error-out there if the path is on the network.
> > + ipc_path = interpolate_path(ipc_file.buf, 1);
> > + if (!ipc_path)
> > + die(_("Invalid path: %s"), ipc_file.buf);
> > +
> > + strbuf_release(&ipc_file);
>
> `sock_dir` is being leaked, isn't it?
>
Sure is, thanks.
> > + return ipc_path;
> > +}
> > diff --git a/compat/fsmonitor/fsm-ipc-win32.c
> > b/compat/fsmonitor/fsm-ipc-win32.c
> > @@ -0,0 +1,9 @@
> > +const char *fsmonitor_ipc__get_path(struct repository *r) {
> > + static char *ret;
> > + if (!ret)
> > + ret = git_pathdup("fsmonitor--daemon.ipc");
> > + return ret;
> > +}
> > \ No newline at end of file
>
> Mentioned already.
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote
2022-09-17 6:29 ` Eric Sunshine
2022-09-17 16:29 ` Eric DeCosta
@ 2022-09-19 16:58 ` Junio C Hamano
1 sibling, 0 replies; 170+ messages in thread
From: Junio C Hamano @ 2022-09-19 16:58 UTC (permalink / raw)
To: Eric Sunshine
Cc: Eric DeCosta via GitGitGadget, Git List, Jeff Hostetler,
Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
Eric Sunshine <sunshine@sunshineco.com> writes:
> A couple comments...
>
> In my mind, the directory specified by `fsmonitor.socketdir` is likely
> to be dedicated to this purpose (i.e. housing Git administrative
> junk). As such, it feels somewhat odd for the socket file to be
> hidden; I would instead expect the socket name to be non-hidden (say,
> "git-fsmonitor-daemon-{hash}.ipc") rather than hidden
> (".git-fsmonitor-*"). The directory specified by `fsmonitor.socketdir`
> may or may not be hidden (i.e. start with a dot), but that's the
> user's decision. For the $HOME case, it almost feels cleaner to create
> a hidden directory (say, "$HOME/.git-fsmonitor") in which to house the
> socket files ("git-fsmonitor-daemon-{hash}.ipc"). Anyhow, this comment
> is quite subjective; perhaps not actionable.
Yeah, dot-prefixed files are appropriate if they are to be placed at
the top of some tree without the user having any say in how that
tree is chosen (e.g. the working tree or $HOME). If the user has
the power to specify the location, the equation changes.
> What happens if either $HOME or `fsmonitor.socketdir` are
> network-mounted? Should this code be checking for that case? If they
> are network-mounted, should it error out? At minimum, I would think a
> warning is warranted in order to save users the headache of wondering
> why fsmonitor isn't working correctly.
That's a good point. If one default position (e.g. repository) is
checked if it is usable and can be rejected if it isn't, the
fallback position should at least satisfy the same "is it usable?"
criteria.
Thanks.
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v8 3/5] fsmonitor: avoid socket location check if using hook
2022-09-17 1:12 ` [PATCH v8 0/5] " Eric DeCosta via GitGitGadget
2022-09-17 1:12 ` [PATCH v8 1/5] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-17 1:12 ` [PATCH v8 2/5] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-17 1:12 ` Eric DeCosta via GitGitGadget
2022-09-17 1:12 ` [PATCH v8 4/5] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
5 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-17 1:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 681d8bf963e..40da2d3b533 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v8 4/5] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-17 1:12 ` [PATCH v8 0/5] " Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-17 1:12 ` [PATCH v8 3/5] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-17 1:12 ` Eric DeCosta via GitGitGadget
2022-09-17 1:12 ` [PATCH v8 5/5] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
5 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-17 1:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
fsmonitor: deal with synthetic firmlinks on macOS
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
fsmonitor: deal with synthetic firmlinks on macOS
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 ++++++++++
6 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..56fcd1c2baa 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ state.alias.alias = NULL;
+ state.alias.points_to = NULL;
+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
+ err = error(_("could not get worktree alias"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..179886bc15b 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -209,7 +210,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ path_k = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (!path_k)
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +241,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..13807f58e95 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,92 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR * dir;
+ int read;
+ int retval;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ retval = 0;
+ dir = opendir("/");
+ if (!dir)
+ return -1;
+
+ strbuf_init(&alias, 256);
+ 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));
+
+ 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) == 0)
+ && path[points_to.len] == '/') {
+ info->alias = strbuf_detach(&alias, NULL);
+ info->points_to = strbuf_detach(&points_to, NULL);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
+ path, info->alias, info->points_to);
+ retval = 0;
+ goto done;
+ }
+ } else if (errno != EINVAL) { /* Something other than not a link */
+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
+ retval = -1;
+ goto done;
+ }
+ }
+
+ done:
+ closedir(dir);
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ int len = info->alias ? strlen(info->alias) : 0;
+
+ if (!len)
+ return NULL;
+
+ if ((strncmp(info->alias, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
+ int ptr_len = strlen(info->points_to);
+ int rem_len = strlen(remainder);
+
+ strbuf_init(&tmp, ptr_len + rem_len);
+ strbuf_add(&tmp, info->points_to, ptr_len);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..50ef37e57bb 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,6 +1,14 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ char *alias;
+ char *points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
@@ -20,4 +28,32 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by set info.alias and
+ * info.points_to and is responsible for releasing it with `free(3)`
+ * when done.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it with `free(3)` when done.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v8 5/5] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-17 1:12 ` [PATCH v8 0/5] " Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-17 1:12 ` [PATCH v8 4/5] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-17 1:12 ` Eric DeCosta via GitGitGadget
2022-09-17 6:08 ` Eric Sunshine
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
5 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-17 1:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
system support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/git-fsmonitor--daemon.txt | 35 +++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..0adccd0eced 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -70,6 +70,41 @@ the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this my be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositores and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS).
+Usage of UDS requires the creation of a file which, by default, is created
+in the .git directory. If the fsmonitor daemon detects that the .git directory
+is on a network-mounted file system, it will create the UDS file in $HOME. If
+$HOME itself is on a network-mounted file system or if $HOME is not the desired
+location for the UDS file, 'fsmonitor.socketDir' may be set to any valid, local
+directory on a file system with proper support. Mac OS native file systems have
+the required support. File systems known to lack support include FAT32 and
+NTFS. Other file systems may or many not have the needed support; the fsmonitor
+daemon is not guaranteed to work with these file systems and such use is
+considered experimental.
+
+CONFIGURATION
+-------------
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+the fsmonitor daemon will pay attention to the following configuration
+variables:
+
+fsmonitor.allowRemote::
+ By default, the daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
+ this behavior.
+
+fsmonitor.socketDir::
+ This option is only used by the Mac OS implementation of the fsmonitor
+ daemon. If set, 'fsmonitor.socketDir' must be set to a valid, local
+ directory on a file system that can support Unix domain sockets (UDS).
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v8 5/5] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-17 1:12 ` [PATCH v8 5/5] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-17 6:08 ` Eric Sunshine
2022-09-19 23:55 ` Eric DeCosta
0 siblings, 1 reply; 170+ messages in thread
From: Eric Sunshine @ 2022-09-17 6:08 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: Git List, Jeff Hostetler, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On Fri, Sep 16, 2022 at 9:12 PM Eric DeCosta via GitGitGadget
<gitgitgadget@gmail.com> wrote:
> Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
> Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
> system support for 'fsmonitor.socketDir'.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
> @@ -70,6 +70,41 @@ the change (as happening against the super repo). However, the client
> +By default, the fsmonitor daemon refuses to work against network-mounted
> +repositories; this my be overridden by setting `fsmonitor.allowRemote` to
> +`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
> +correctly with all network-mounted repositores and such use is considered
> +experimental.
s/repositores/repositories/
> +On Mac OS, the inter-process communication (IPC) between various Git
> +commands and the fsmonitor daemon is done via a Unix domain socket (UDS).
> +Usage of UDS requires the creation of a file which, by default, is created
> +in the .git directory. If the fsmonitor daemon detects that the .git directory
Typesetting: s/.git/`.git`/g
> +is on a network-mounted file system, it will create the UDS file in $HOME. If
There's a gap in the explanation as to _why_ fsmonitor won't use the
.git directory for this file when on a network-mounted filesystem and
instead chooses $HOME. For the reader who is not well-versed in Unix
sockets/filesystems, it may be difficult to understand the logic
behind this. This gap is somewhat filled in a few sentences later, but
it makes for potentially confusing reading until then.
Should the reader know the name of the socket file or at least the
templated form of the name? The first question which popped into my
head upon reading this was whether it was going to pollute my home
directory with non-hidden files. If this had mentioned something along
the lines of "creation of a file named `.git-fsmonitor-*`" or
"creation of a hidden file" then I would have understood immediately
that the file would have been hidden.
> +$HOME itself is on a network-mounted file system or if $HOME is not the desired
To be consistent with formatting elsewhere in the Git documentation,
let's typeset this as `$HOME` (with backticks).
Aside: The spelling "filesystem" appears almost five times as often as
"file system" in Git documentation, however, this particular file
already uses "file system" and does so consistently, so it makes sense
to follow suit as you do here. Changing to use "filesystem" instead,
if such a task is desirable, is outside the scope of this patch
series.
> +location for the UDS file, 'fsmonitor.socketDir' may be set to any valid, local
For consistency, let's use backticks here, as well: `fsmonitor.socketDir`
> +directory on a file system with proper support. Mac OS native file systems have
Together with the above comment about a gap in the explanation, I
found myself scratching my head about what "proper support" meant
(when pretending to read this as a person not particularly familiar
with Unix sockets or filesystems).
Also, although this explains how to work around the case when $HOME is
itself network-mounted, what happens if $HOME is network-mounted and
the user does not set `fsmonitor.socketDir`? Does it error out? Does
it simply misbehave in some way? Should it error out? (I would think
"yes".)
> +the required support. File systems known to lack support include FAT32 and
> +NTFS. Other file systems may or many not have the needed support; the fsmonitor
s/many/may/
> +daemon is not guaranteed to work with these file systems and such use is
> +considered experimental.
Taking the above comments into account, here's my attempt at a rewrite:
On Mac OS, the inter-process communication (IPC) between various
Git commands and the fsmonitor daemon occurs via a Unix domain
socket (UDS) -- a special type of file -- which is supported by
the native Mac OS filesystems but not by network-mounted
filesystems, NTFS or FAT32. Other file systems may or many not
have the needed support; the fsmonitor daemon is not guaranteed to
work with these file systems and such use is considered
experimental.
By default, the socket is created in the `.git` directory,
however, if the `.git` directory is on a network-mounted file
system, it will instead be created at `$HOME/.git-fsmonitor-*`
unless `$HOME` itself is on a network-mounted file system, in
which case you must set the configuration variable
`fsmonitor.socketDir` to the path of a directory on a Mac OS
native filesystem in which to create the socket file.
> +CONFIGURATION
> +-------------
> +When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
> +the fsmonitor daemon will pay attention to the following configuration
> +variables:
We probably want a blank line after the header underline and before
this paragraph.
> +fsmonitor.allowRemote::
> + By default, the daemon refuses to work against network-mounted
> + repositories. Setting `fsmonitor.allowRemote` to `true` overrides
> + this behavior.
> +
> +fsmonitor.socketDir::
> + This option is only used by the Mac OS implementation of the fsmonitor
> + daemon. If set, 'fsmonitor.socketDir' must be set to a valid, local
> + directory on a file system that can support Unix domain sockets (UDS).
Typeset with backticks: `fsmonitor.socketDir`
The word "valid" seems unnecessary. A possible rewrite:
This Mac OS-specific option, if set, specifies the directory in
which to create the Unix domain socket used for communication
between fsmonitor and various Git commands. The directory must
reside on a native Mac OS filesystem as discussed above.
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v8 5/5] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-17 6:08 ` Eric Sunshine
@ 2022-09-19 23:55 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-19 23:55 UTC (permalink / raw)
To: Eric Sunshine, Eric DeCosta via GitGitGadget
Cc: Git List, Jeff Hostetler, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Eric Sunshine <sunshine@sunshineco.com>
> Sent: Saturday, September 17, 2022 2:09 AM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Cc: Git List <git@vger.kernel.org>; Jeff Hostetler <git@jeffhostetler.com>;
> Torsten Bögershausen <tboegi@web.de>; Ævar Arnfjörð Bjarmason
> <avarab@gmail.com>; Ramsay Jones <ramsay@ramsayjones.plus.com>;
> Johannes Schindelin <Johannes.Schindelin@gmx.de>; Eric DeCosta
> <edecosta@mathworks.com>
> Subject: Re: [PATCH v8 5/5] fsmonitor: add documentation for allowRemote
> and socketDir options
>
> On Fri, Sep 16, 2022 at 9:12 PM Eric DeCosta via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
> > Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
> > Call-out experimental nature of 'fsmonitor.allowRemote' and limited
> > file system support for 'fsmonitor.socketDir'.
> >
> > Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> > ---
> > diff --git a/Documentation/git-fsmonitor--daemon.txt
> > b/Documentation/git-fsmonitor--daemon.txt
> > @@ -70,6 +70,41 @@ the change (as happening against the super repo).
> > However, the client
> > +By default, the fsmonitor daemon refuses to work against
> > +network-mounted repositories; this my be overridden by setting
> > +`fsmonitor.allowRemote` to `true`. Note, however, that the fsmonitor
> > +daemon is not guaranteed to work correctly with all network-mounted
> > +repositores and such use is considered experimental.
>
> s/repositores/repositories/
>
> > +On Mac OS, the inter-process communication (IPC) between various Git
> > +commands and the fsmonitor daemon is done via a Unix domain socket
> (UDS).
> > +Usage of UDS requires the creation of a file which, by default, is
> > +created in the .git directory. If the fsmonitor daemon detects that
> > +the .git directory
>
> Typesetting: s/.git/`.git`/g
>
> > +is on a network-mounted file system, it will create the UDS file in
> > +$HOME. If
>
> There's a gap in the explanation as to _why_ fsmonitor won't use the .git
> directory for this file when on a network-mounted filesystem and instead
> chooses $HOME. For the reader who is not well-versed in Unix
> sockets/filesystems, it may be difficult to understand the logic behind this.
> This gap is somewhat filled in a few sentences later, but it makes for
> potentially confusing reading until then.
>
> Should the reader know the name of the socket file or at least the templated
> form of the name? The first question which popped into my head upon
> reading this was whether it was going to pollute my home directory with
> non-hidden files. If this had mentioned something along the lines of
> "creation of a file named `.git-fsmonitor-*`" or "creation of a hidden file"
> then I would have understood immediately that the file would have been
> hidden.
>
> > +$HOME itself is on a network-mounted file system or if $HOME is not
> > +the desired
>
> To be consistent with formatting elsewhere in the Git documentation, let's
> typeset this as `$HOME` (with backticks).
>
> Aside: The spelling "filesystem" appears almost five times as often as "file
> system" in Git documentation, however, this particular file already uses "file
> system" and does so consistently, so it makes sense to follow suit as you do
> here. Changing to use "filesystem" instead, if such a task is desirable, is
> outside the scope of this patch series.
>
> > +location for the UDS file, 'fsmonitor.socketDir' may be set to any
> > +valid, local
>
> For consistency, let's use backticks here, as well: `fsmonitor.socketDir`
>
> > +directory on a file system with proper support. Mac OS native file
> > +systems have
>
> Together with the above comment about a gap in the explanation, I found
> myself scratching my head about what "proper support" meant (when
> pretending to read this as a person not particularly familiar with Unix sockets
> or filesystems).
>
> Also, although this explains how to work around the case when $HOME is
> itself network-mounted, what happens if $HOME is network-mounted and
> the user does not set `fsmonitor.socketDir`? Does it error out? Does it simply
> misbehave in some way? Should it error out? (I would think
> "yes".)
>
> > +the required support. File systems known to lack support include
> > +FAT32 and NTFS. Other file systems may or many not have the needed
> > +support; the fsmonitor
>
> s/many/may/
>
> > +daemon is not guaranteed to work with these file systems and such use
> > +is considered experimental.
>
> Taking the above comments into account, here's my attempt at a rewrite:
>
> On Mac OS, the inter-process communication (IPC) between various
> Git commands and the fsmonitor daemon occurs via a Unix domain
> socket (UDS) -- a special type of file -- which is supported by
> the native Mac OS filesystems but not by network-mounted
> filesystems, NTFS or FAT32. Other file systems may or many not
> have the needed support; the fsmonitor daemon is not guaranteed to
> work with these file systems and such use is considered
> experimental.
>
> By default, the socket is created in the `.git` directory,
> however, if the `.git` directory is on a network-mounted file
> system, it will instead be created at `$HOME/.git-fsmonitor-*`
> unless `$HOME` itself is on a network-mounted file system, in
> which case you must set the configuration variable
> `fsmonitor.socketDir` to the path of a directory on a Mac OS
> native filesystem in which to create the socket file.
>
> > +CONFIGURATION
> > +-------------
> > +When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
> > +the fsmonitor daemon will pay attention to the following
> > +configuration
> > +variables:
>
> We probably want a blank line after the header underline and before this
> paragraph.
>
> > +fsmonitor.allowRemote::
> > + By default, the daemon refuses to work against network-mounted
> > + repositories. Setting `fsmonitor.allowRemote` to `true` overrides
> > + this behavior.
> > +
> > +fsmonitor.socketDir::
> > + This option is only used by the Mac OS implementation of the
> fsmonitor
> > + daemon. If set, 'fsmonitor.socketDir' must be set to a valid, local
> > + directory on a file system that can support Unix domain sockets (UDS).
>
> Typeset with backticks: `fsmonitor.socketDir`
>
> The word "valid" seems unnecessary. A possible rewrite:
>
> This Mac OS-specific option, if set, specifies the directory in
> which to create the Unix domain socket used for communication
> between fsmonitor and various Git commands. The directory must
> reside on a native Mac OS filesystem as discussed above.
The way you've re-written things is so much clearer! Much appreciated.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-17 1:12 ` [PATCH v8 0/5] " Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-17 1:12 ` [PATCH v8 5/5] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-19 19:37 ` Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (6 more replies)
5 siblings, 7 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-19 19:37 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
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/git-fsmonitor--daemon.txt | 48 ++++++-
Makefile | 2 +
builtin/fsmonitor--daemon.c | 11 +-
compat/fsmonitor/fsm-ipc-darwin.c | 48 +++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 ++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 132 +++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 145 +++++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 70 +++------
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 | 59 ++++++++
fsmonitor-settings.c | 60 +++++++-
fsmonitor-settings.h | 2 +-
fsmonitor.c | 4 +
18 files changed, 559 insertions(+), 240 deletions(-)
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: d3fa443f97e3a8d75b51341e2d5bac380b7422df
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v9
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v9
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v8:
1: 155a6890806 = 1: 155a6890806 fsmonitor: refactor filesystem checks to common interface
2: b5356497228 ! 2: 68709d788d5 fsmonitor: relocate socket file if .git directory is remote
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
-+ if (sock_dir && *sock_dir)
++ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
-+ else
++ free(sock_dir);
++ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
++ }
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
3: 6719ca2b24d = 3: 6ddd922917a fsmonitor: avoid socket location check if using hook
4: d736cb8fa90 ! 4: 73afd9f3122 fsmonitor: deal with synthetic firmlinks on macOS
@@ Commit message
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
- fsmonitor: deal with synthetic firmlinks on macOS
-
- Starting with macOS 10.15 (Catalina), Apple introduced a new feature
- called 'firmlinks' in order to separate the boot volume into two
- volumes, one read-only and one writable but still present them to the
- user as a single volume. Along with this change, Apple removed the
- ability to create symlinks in the root directory and replaced them with
- 'synthetic firmlinks'. See 'man synthetic.conf'
-
- When FSEevents reports the path of changed files, if the path involves
- a synthetic firmlink, the path is reported from the point of the
- synthetic firmlink and not the real path. For example:
-
- Real path:
- /System/Volumes/Data/network/working/directory/foo.txt
-
- Synthetic firmlink:
- /network -> /System/Volumes/Data/network
-
- FSEvents path:
- /network/working/directory/foo.txt
-
- This causes the FSEvents path to not match against the worktree
- directory.
-
- There are several ways in which synthetic firmlinks can be created:
- they can be defined in /etc/synthetic.conf, the automounter can create
- them, and there may be other means. Simply reading /etc/synthetic.conf
- is insufficient. No matter what process creates synthetic firmlinks,
- they all get created in the root directory.
-
- Therefore, in order to deal with synthetic firmlinks, the root directory
- is scanned and the first possible synthetic firmink that, when resolved,
- is a prefix of the worktree is used to map FSEvents paths to worktree
- paths.
-
- Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
-
- fsmonitor: deal with synthetic firmlinks on macOS
-
- Starting with macOS 10.15 (Catalina), Apple introduced a new feature
- called 'firmlinks' in order to separate the boot volume into two
- volumes, one read-only and one writable but still present them to the
- user as a single volume. Along with this change, Apple removed the
- ability to create symlinks in the root directory and replaced them with
- 'synthetic firmlinks'. See 'man synthetic.conf'
-
- When FSEevents reports the path of changed files, if the path involves
- a synthetic firmlink, the path is reported from the point of the
- synthetic firmlink and not the real path. For example:
-
- Real path:
- /System/Volumes/Data/network/working/directory/foo.txt
-
- Synthetic firmlink:
- /network -> /System/Volumes/Data/network
-
- FSEvents path:
- /network/working/directory/foo.txt
-
- This causes the FSEvents path to not match against the worktree
- directory.
-
- There are several ways in which synthetic firmlinks can be created:
- they can be defined in /etc/synthetic.conf, the automounter can create
- them, and there may be other means. Simply reading /etc/synthetic.conf
- is insufficient. No matter what process creates synthetic firmlinks,
- they all get created in the root directory.
-
- Therefore, in order to deal with synthetic firmlinks, the root directory
- is scanned and the first possible synthetic firmink that, when resolved,
- is a prefix of the worktree is used to map FSEvents paths to worktree
- paths.
-
- Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
-
## builtin/fsmonitor--daemon.c ##
@@
#include "parse-options.h"
-: ----------- > 5: 02afeaa01be fsmonitor: check for compatability before communicating with fsmonitor
5: ddf4e3e6442 ! 6: 0e8ea28acc1 fsmonitor: add documentation for allowRemote and socketDir options
@@ Commit message
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
## Documentation/git-fsmonitor--daemon.txt ##
-@@ Documentation/git-fsmonitor--daemon.txt: the change (as happening against the super repo). However, the client
+@@ Documentation/git-fsmonitor--daemon.txt: git-fsmonitor{litdd}daemon(1)
+
+ NAME
+ ----
+-git-fsmonitor--daemon - A Built-in File System Monitor
++git-fsmonitor--daemon - A Built-in Filesystem Monitor
+
+ SYNOPSIS
+ --------
+@@ Documentation/git-fsmonitor--daemon.txt: DESCRIPTION
+ -----------
+
+ A daemon to watch the working directory for file and directory
+-changes using platform-specific file system notification facilities.
++changes using platform-specific filesystem notification facilities.
+
+ This daemon communicates directly with commands like `git status`
+ using the link:technical/api-simple-ipc.html[simple IPC] interface
+@@ Documentation/git-fsmonitor--daemon.txt: CAVEATS
+ -------
+
+ The fsmonitor daemon does not currently know about submodules and does
+-not know to filter out file system events that happen within a
++not know to filter out filesystem events that happen within a
+ submodule. If fsmonitor daemon is watching a super repo and a file is
+ modified within the working directory of a submodule, it will report
+ the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
-+repositories; this my be overridden by setting `fsmonitor.allowRemote` to
++repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
-+correctly with all network-mounted repositores and such use is considered
++correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
-+commands and the fsmonitor daemon is done via a Unix domain socket (UDS).
-+Usage of UDS requires the creation of a file which, by default, is created
-+in the .git directory. If the fsmonitor daemon detects that the .git directory
-+is on a network-mounted file system, it will create the UDS file in $HOME. If
-+$HOME itself is on a network-mounted file system or if $HOME is not the desired
-+location for the UDS file, 'fsmonitor.socketDir' may be set to any valid, local
-+directory on a file system with proper support. Mac OS native file systems have
-+the required support. File systems known to lack support include FAT32 and
-+NTFS. Other file systems may or many not have the needed support; the fsmonitor
-+daemon is not guaranteed to work with these file systems and such use is
-+considered experimental.
++commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
++special type of file -- which is supported by native Mac OS filesystems,
++but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
++may or may not have the needed support; the fsmonitor daemon is not guaranteed
++to work with these filesystems and such use is considered experimental.
++
++By default, the socket is created in the `.git` directory, however, if the
++`.git` directory is on a network-mounted filesystem, it will be instead be
++created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
++network-mounted filesystem in which case you must set the configuration
++variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
++filesystem in which to create the socket file.
++
++If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
++is on a native Mac OS file filesystem the fsmonitor daemon will report an
++error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
++
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+the fsmonitor daemon will pay attention to the following configuration
+variables:
+
-+fsmonitor.allowRemote::
++`fsmonitor.allowRemote`::
+ By default, the daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
+ this behavior.
+
-+fsmonitor.socketDir::
-+ This option is only used by the Mac OS implementation of the fsmonitor
-+ daemon. If set, 'fsmonitor.socketDir' must be set to a valid, local
-+ directory on a file system that can support Unix domain sockets (UDS).
++`fsmonitor.socketDir`::
++ This Mac OS-specific option, if set, specifies the directory in
++ which to create the Unix domain socket used for communication
++ between fsmonitor and various Git commands. The directory must
++ reside on a native Mac OS filesystem as discussed above.
+
GIT
---
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v9 1/6] fsmonitor: refactor filesystem checks to common interface
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
@ 2022-09-19 19:37 ` Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-19 19:37 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index d9247ead45b..6e492a67547 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2237109b57f..b88494bf59b 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v9 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-19 19:37 ` Eric DeCosta via GitGitGadget
2022-09-19 19:57 ` Eric Sunshine
2022-09-19 19:37 ` [PATCH v9 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
6 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-19 19:37 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote file system, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 48 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 ++
fsmonitor-ipc.c | 18 +++++-----
fsmonitor-ipc.h | 4 ++-
8 files changed, 74 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index 6e492a67547..58bb9248471 100644
--- a/Makefile
+++ b/Makefile
@@ -2034,6 +2034,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..d48d67690ee
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,48 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
+ char *sock_dir;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (ipc_path)
+ return ipc_path;
+
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
+ return ipc_path;
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ free(sock_dir);
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..3a3a46db209
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
\ No newline at end of file
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..681d8bf963e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index b88494bf59b..7e7b6b9a362 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v9 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-19 19:37 ` [PATCH v9 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-19 19:57 ` Eric Sunshine
0 siblings, 0 replies; 170+ messages in thread
From: Eric Sunshine @ 2022-09-19 19:57 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: Git List, Jeff Hostetler, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On Mon, Sep 19, 2022 at 3:38 PM Eric DeCosta via GitGitGadget
<gitgitgadget@gmail.com> wrote:
> If the .git directory is on a remote file system, create the socket
> file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
> @@ -0,0 +1,48 @@
> +const char *fsmonitor_ipc__get_path(struct repository *r)
> +{
> + char *sock_dir;
> +
> + repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
> +
> + /* Create the socket file in either socketDir or $HOME */
> + if (sock_dir && *sock_dir) {
> + strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
> + sock_dir, hash_to_hex(hash));
> + free(sock_dir);
> + } else {
> + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
> + }
This is still leaking `sock_dir`, isn't it, if
repo_config_get_string() returns it as a zero-length string?
Probably want to move free() below the entire conditional.
> diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
> @@ -0,0 +1,9 @@
> +#include "config.h"
> +#include "fsmonitor-ipc.h"
> +
> +const char *fsmonitor_ipc__get_path(struct repository *r) {
> + static char *ret;
> + if (!ret)
> + ret = git_pathdup("fsmonitor--daemon.ipc");
> + return ret;
> +}
> \ No newline at end of file
Still an incomplete line.
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v9 3/6] fsmonitor: avoid socket location check if using hook
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-19 19:37 ` Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-19 19:37 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 681d8bf963e..40da2d3b533 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v9 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-19 19:37 ` [PATCH v9 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-19 19:37 ` Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-19 19:37 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 ++++++++++
6 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..56fcd1c2baa 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ state.alias.alias = NULL;
+ state.alias.points_to = NULL;
+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
+ err = error(_("could not get worktree alias"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..179886bc15b 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -209,7 +210,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ path_k = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (!path_k)
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +241,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..13807f58e95 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,92 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR * dir;
+ int read;
+ int retval;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ retval = 0;
+ dir = opendir("/");
+ if (!dir)
+ return -1;
+
+ strbuf_init(&alias, 256);
+ 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));
+
+ 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) == 0)
+ && path[points_to.len] == '/') {
+ info->alias = strbuf_detach(&alias, NULL);
+ info->points_to = strbuf_detach(&points_to, NULL);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
+ path, info->alias, info->points_to);
+ retval = 0;
+ goto done;
+ }
+ } else if (errno != EINVAL) { /* Something other than not a link */
+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
+ retval = -1;
+ goto done;
+ }
+ }
+
+ done:
+ closedir(dir);
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ int len = info->alias ? strlen(info->alias) : 0;
+
+ if (!len)
+ return NULL;
+
+ if ((strncmp(info->alias, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
+ int ptr_len = strlen(info->points_to);
+ int rem_len = strlen(remainder);
+
+ strbuf_init(&tmp, ptr_len + rem_len);
+ strbuf_add(&tmp, info->points_to, ptr_len);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..50ef37e57bb 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,6 +1,14 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ char *alias;
+ char *points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
@@ -20,4 +28,32 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by set info.alias and
+ * info.points_to and is responsible for releasing it with `free(3)`
+ * when done.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it with `free(3)` when done.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v9 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-19 19:37 ` [PATCH v9 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-19 19:37 ` Eric DeCosta via GitGitGadget
2022-09-19 19:37 ` [PATCH v9 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-19 19:37 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If fsmonitor is not in a compatible state, die with an appropriate error
messge.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
fsmonitor-settings.c | 2 ++
fsmonitor.c | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 531a1b6f956..aaa204e0352 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -247,6 +247,8 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
{
struct strbuf msg = STRBUF_INIT;
+ strbuf_add(&msg, "fsmonitor: ", strlen("fsmonitor: "));
+
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
case FSMONITOR_REASON_OK:
diff --git a/fsmonitor.c b/fsmonitor.c
index 57d6a483bee..43d580132fb 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -305,6 +305,10 @@ void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (reason > FSMONITOR_REASON_OK)
+ die("%s", fsm_settings__get_incompatible_msg(r, reason));
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v9 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-19 19:37 ` [PATCH v9 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-09-19 19:37 ` Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-19 19:37 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
system support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/git-fsmonitor--daemon.txt | 48 +++++++++++++++++++++++--
1 file changed, 45 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..6ad3e518ae0 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
NAME
----
-git-fsmonitor--daemon - A Built-in File System Monitor
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
SYNOPSIS
--------
@@ -17,7 +17,7 @@ DESCRIPTION
-----------
A daemon to watch the working directory for file and directory
-changes using platform-specific file system notification facilities.
+changes using platform-specific filesystem notification facilities.
This daemon communicates directly with commands like `git status`
using the link:technical/api-simple-ipc.html[simple IPC] interface
@@ -63,13 +63,55 @@ CAVEATS
-------
The fsmonitor daemon does not currently know about submodules and does
-not know to filter out file system events that happen within a
+not know to filter out filesystem events that happen within a
submodule. If fsmonitor daemon is watching a super repo and a file is
modified within the working directory of a submodule, it will report
the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory, however, if the
+`.git` directory is on a network-mounted filesystem, it will be instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+the fsmonitor daemon will pay attention to the following configuration
+variables:
+
+`fsmonitor.allowRemote`::
+ By default, the daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
+ this behavior.
+
+`fsmonitor.socketDir`::
+ This Mac OS-specific option, if set, specifies the directory in
+ which to create the Unix domain socket used for communication
+ between fsmonitor and various Git commands. The directory must
+ reside on a native Mac OS filesystem as discussed above.
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-19 19:37 ` [PATCH v9 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-19 19:37 ` [PATCH v9 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-20 20:33 ` Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (6 more replies)
6 siblings, 7 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-20 20:33 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
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/git-fsmonitor--daemon.txt | 48 ++++++-
Makefile | 2 +
builtin/fsmonitor--daemon.c | 11 +-
compat/fsmonitor/fsm-ipc-darwin.c | 51 +++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 ++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
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 | 59 ++++++++
fsmonitor-settings.c | 68 ++++++++-
fsmonitor-settings.h | 4 +-
fsmonitor.c | 4 +
18 files changed, 569 insertions(+), 245 deletions(-)
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: d3fa443f97e3a8d75b51341e2d5bac380b7422df
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v10
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v10
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v9:
1: 155a6890806 = 1: 155a6890806 fsmonitor: refactor filesystem checks to common interface
2: 68709d788d5 ! 2: dbe113abb87 fsmonitor: relocate socket file if .git directory is remote
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
-+ char *sock_dir;
++ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
++ if (!r)
++ BUG("No repository passed into fsmonitor_ipc__get_path");
++
+ if (ipc_path)
+ return ipc_path;
+
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
-+ free(sock_dir);
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
++ free(sock_dir);
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
@@ compat/fsmonitor/fsm-ipc-win32.c (new)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
- \ No newline at end of file
## compat/fsmonitor/fsm-settings-darwin.c ##
@@
3: 6ddd922917a = 3: 86c15299ae8 fsmonitor: avoid socket location check if using hook
4: 73afd9f3122 = 4: 4f6c98cf834 fsmonitor: deal with synthetic firmlinks on macOS
5: 02afeaa01be ! 5: 8f6c1fbacbf fsmonitor: check for compatability before communicating with fsmonitor
@@ Commit message
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
+ ## compat/fsmonitor/fsm-settings-darwin.c ##
+@@ compat/fsmonitor/fsm-settings-darwin.c: static enum fsmonitor_reason check_uds_volume(struct repository *r)
+ strbuf_release(&path);
+
+ if (fs.is_remote)
+- return FSMONITOR_REASON_REMOTE;
++ return FSMONITOR_REASON_NOSOCKETS;
+
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
+ return FSMONITOR_REASON_NOSOCKETS;
+
## fsmonitor-settings.c ##
-@@ fsmonitor-settings.c: char *fsm_settings__get_incompatible_msg(const struct repository *r,
+@@
+ #include "cache.h"
+ #include "config.h"
+ #include "repository.h"
++#include "fsmonitor-ipc.h"
+ #include "fsmonitor-settings.h"
+ #include "fsmonitor-path-utils.h"
+
+@@ fsmonitor-settings.c: enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
+ return r->settings.fsmonitor->reason;
+ }
+
+-char *fsm_settings__get_incompatible_msg(const struct repository *r,
++char *fsm_settings__get_incompatible_msg(struct repository *r,
+ enum fsmonitor_reason reason)
{
struct strbuf msg = STRBUF_INIT;
++ const char *socket_dir;
-+ strbuf_add(&msg, "fsmonitor: ", strlen("fsmonitor: "));
-+
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
- case FSMONITOR_REASON_OK:
+@@ fsmonitor-settings.c: char *fsm_settings__get_incompatible_msg(const struct repository *r,
+ goto done;
+
+ case FSMONITOR_REASON_NOSOCKETS:
++ socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
+ strbuf_addf(&msg,
+- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
+- r->worktree);
++ _("socket directory '%s' is incompatible with fsmonitor due"),
++ socket_dir);
++ strbuf_add(&msg, _(" to lack of Unix sockets support"), 32);
+ goto done;
+ }
+
+
+ ## fsmonitor-settings.h ##
+@@ fsmonitor-settings.h: enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
+ const char *fsm_settings__get_hook_path(struct repository *r);
+
+ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
+-char *fsm_settings__get_incompatible_msg(const struct repository *r,
++char *fsm_settings__get_incompatible_msg(struct repository *r,
+ enum fsmonitor_reason reason);
+
+ struct fsmonitor_settings;
## fsmonitor.c ##
@@ fsmonitor.c: void refresh_fsmonitor(struct index_state *istate)
6: 0e8ea28acc1 = 6: d7c25bf96c6 fsmonitor: add documentation for allowRemote and socketDir options
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v10 1/6] fsmonitor: refactor filesystem checks to common interface
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
@ 2022-09-20 20:33 ` Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-20 20:33 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index d9247ead45b..6e492a67547 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2237109b57f..b88494bf59b 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v10 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-20 20:33 ` Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-20 20:33 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote file system, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 51 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-ipc.c | 18 ++++-----
fsmonitor-ipc.h | 4 +-
8 files changed, 77 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index 6e492a67547..58bb9248471 100644
--- a/Makefile
+++ b/Makefile
@@ -2034,6 +2034,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..0f551e5e572
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,51 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (!r)
+ BUG("No repository passed into fsmonitor_ipc__get_path");
+
+ if (ipc_path)
+ return ipc_path;
+
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
+ return ipc_path;
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
+ free(sock_dir);
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..e08c505c148
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..681d8bf963e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index b88494bf59b..7e7b6b9a362 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v10 3/6] fsmonitor: avoid socket location check if using hook
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-20 20:33 ` Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-20 20:33 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 681d8bf963e..40da2d3b533 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v10 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-20 20:33 ` [PATCH v10 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-20 20:33 ` Eric DeCosta via GitGitGadget
2022-09-20 20:33 ` [PATCH v10 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-20 20:33 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 6 +-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 ++++++++++
6 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..56fcd1c2baa 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ state.alias.alias = NULL;
+ state.alias.points_to = NULL;
+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
+ err = error(_("could not get worktree alias"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..179886bc15b 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -209,7 +210,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ path_k = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (!path_k)
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +241,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..13807f58e95 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,92 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR * dir;
+ int read;
+ int retval;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ retval = 0;
+ dir = opendir("/");
+ if (!dir)
+ return -1;
+
+ strbuf_init(&alias, 256);
+ 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));
+
+ 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) == 0)
+ && path[points_to.len] == '/') {
+ info->alias = strbuf_detach(&alias, NULL);
+ info->points_to = strbuf_detach(&points_to, NULL);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
+ path, info->alias, info->points_to);
+ retval = 0;
+ goto done;
+ }
+ } else if (errno != EINVAL) { /* Something other than not a link */
+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
+ retval = -1;
+ goto done;
+ }
+ }
+
+ done:
+ closedir(dir);
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ int len = info->alias ? strlen(info->alias) : 0;
+
+ if (!len)
+ return NULL;
+
+ if ((strncmp(info->alias, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
+ int ptr_len = strlen(info->points_to);
+ int rem_len = strlen(remainder);
+
+ strbuf_init(&tmp, ptr_len + rem_len);
+ strbuf_add(&tmp, info->points_to, ptr_len);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..50ef37e57bb 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,6 +1,14 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ char *alias;
+ char *points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
@@ -20,4 +28,32 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by set info.alias and
+ * info.points_to and is responsible for releasing it with `free(3)`
+ * when done.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it with `free(3)` when done.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v10 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-20 20:33 ` [PATCH v10 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-20 20:33 ` Eric DeCosta via GitGitGadget
2022-09-21 11:22 ` Jeff Hostetler
2022-09-20 20:33 ` [PATCH v10 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-20 20:33 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If fsmonitor is not in a compatible state, die with an appropriate error
messge.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
fsmonitor-settings.c | 10 +++++++---
fsmonitor-settings.h | 2 +-
fsmonitor.c | 4 ++++
4 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 40da2d3b533..44233125df8 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -38,7 +38,7 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
strbuf_release(&path);
if (fs.is_remote)
- return FSMONITOR_REASON_REMOTE;
+ return FSMONITOR_REASON_NOSOCKETS;
if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 531a1b6f956..24480b9806d 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
+#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
#include "fsmonitor-path-utils.h"
@@ -242,10 +243,11 @@ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
return r->settings.fsmonitor->reason;
}
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason)
{
struct strbuf msg = STRBUF_INIT;
+ const char *socket_dir;
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
@@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
goto done;
case FSMONITOR_REASON_NOSOCKETS:
+ socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
strbuf_addf(&msg,
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
+ _("socket directory '%s' is incompatible with fsmonitor due"),
+ socket_dir);
+ strbuf_add(&msg, _(" to lack of Unix sockets support"), 32);
goto done;
}
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index 0721617b95a..ab02e3995ee 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
const char *fsm_settings__get_hook_path(struct repository *r);
enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason);
struct fsmonitor_settings;
diff --git a/fsmonitor.c b/fsmonitor.c
index 57d6a483bee..43d580132fb 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -305,6 +305,10 @@ void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (reason > FSMONITOR_REASON_OK)
+ die("%s", fsm_settings__get_incompatible_msg(r, reason));
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v10 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-20 20:33 ` [PATCH v10 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-09-21 11:22 ` Jeff Hostetler
2022-09-21 13:03 ` Eric DeCosta
0 siblings, 1 reply; 170+ messages in thread
From: Jeff Hostetler @ 2022-09-21 11:22 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget, git
Cc: Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
On 9/20/22 4:33 PM, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
>
> If fsmonitor is not in a compatible state, die with an appropriate error
> messge.
[...]
> diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
> index 531a1b6f956..24480b9806d 100644
> --- a/fsmonitor-settings.c
> +++ b/fsmonitor-settings.c
[...]
> +char *fsm_settings__get_incompatible_msg(struct repository *r,
> enum fsmonitor_reason reason)
> {
> struct strbuf msg = STRBUF_INIT;
> + const char *socket_dir;
>
> switch (reason) {
> case FSMONITOR_REASON_UNTESTED:
> @@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
> goto done;
>
> case FSMONITOR_REASON_NOSOCKETS:
> + socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
> strbuf_addf(&msg,
> - _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
> - r->worktree);
> + _("socket directory '%s' is incompatible with fsmonitor due"),
> + socket_dir);
> + strbuf_add(&msg, _(" to lack of Unix sockets support"), 32);
> goto done;
I don't think we should split the error message between two
calls to strbuf_add(). I realize that this was probably done
because of line length concerns. But this makes assumptions
on language word order during translations.
Instead, we can use C string literal joining before passing
it to the translation macro. Something like:
strbuf_addf(&msg,
_("socket directory '%s' is incompatible with "
"fsmonitor due to lack of Unix sockets support"),
socket_dir);
[...]
> diff --git a/fsmonitor.c b/fsmonitor.c
> index 57d6a483bee..43d580132fb 100644
> --- a/fsmonitor.c
> +++ b/fsmonitor.c
> @@ -305,6 +305,10 @@ void refresh_fsmonitor(struct index_state *istate)
> int is_trivial = 0;
> struct repository *r = istate->repo ? istate->repo : the_repository;
> enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
> + enum fsmonitor_reason reason = fsm_settings__get_reason(r);
> +
> + if (reason > FSMONITOR_REASON_OK)
> + die("%s", fsm_settings__get_incompatible_msg(r, reason));
We don't want to call die() here. Maybe just silently return
without doing anything or issue a warning() and return. (But
I'm favoring a silent return here.)
From the clients' (`git status`, `git diff`, etc.) point of view,
they just want a speed-up, if possible, but we shouldn't kill them;
we should just let them do the normal scan that would have done
if the feature were turned off.
Jeff
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v10 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-21 11:22 ` Jeff Hostetler
@ 2022-09-21 13:03 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-21 13:03 UTC (permalink / raw)
To: Jeff Hostetler, Eric DeCosta via GitGitGadget, git
Cc: Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Jeff Hostetler <git@jeffhostetler.com>
> Sent: Wednesday, September 21, 2022 7:22 AM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>;
> git@vger.kernel.org
> Cc: Eric Sunshine <sunshine@sunshineco.com>; Torsten Bögershausen
> <tboegi@web.de>; Ævar Arnfjörð Bjarmason <avarab@gmail.com>; Ramsay
> Jones <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v10 5/6] fsmonitor: check for compatability before
> communicating with fsmonitor
>
>
>
> On 9/20/22 4:33 PM, Eric DeCosta via GitGitGadget wrote:
> > From: Eric DeCosta <edecosta@mathworks.com>
> >
> > If fsmonitor is not in a compatible state, die with an appropriate
> > error messge.
> [...]
> > diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c index
> > 531a1b6f956..24480b9806d 100644
> > --- a/fsmonitor-settings.c
> > +++ b/fsmonitor-settings.c
> [...]
> > +char *fsm_settings__get_incompatible_msg(struct repository *r,
> > enum fsmonitor_reason reason)
> > {
> > struct strbuf msg = STRBUF_INIT;
> > + const char *socket_dir;
> >
> > switch (reason) {
> > case FSMONITOR_REASON_UNTESTED:
> > @@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const
> struct repository *r,
> > goto done;
> >
> > case FSMONITOR_REASON_NOSOCKETS:
> > + socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
> > strbuf_addf(&msg,
> > - _("repository '%s' is incompatible with fsmonitor
> due to lack of Unix sockets"),
> > - r->worktree);
> > + _("socket directory '%s' is incompatible with
> fsmonitor due"),
> > + socket_dir);
> > + strbuf_add(&msg, _(" to lack of Unix sockets support"), 32);
> > goto done;
>
> I don't think we should split the error message between two calls to
> strbuf_add(). I realize that this was probably done because of line length
> concerns. But this makes assumptions on language word order during
> translations.
>
> Instead, we can use C string literal joining before passing it to the translation
> macro. Something like:
>
> strbuf_addf(&msg,
> _("socket directory '%s' is incompatible with "
> "fsmonitor due to lack of Unix sockets support"),
> socket_dir);
>
> [...]
> > diff --git a/fsmonitor.c b/fsmonitor.c index 57d6a483bee..43d580132fb
> > 100644f
> > --- a/fsmonitor.c
> > +++ b/fsmonitor.c
> > @@ -305,6 +305,10 @@ void refresh_fsmonitor(struct index_state *istate)
> > int is_trivial = 0;
> > struct repository *r = istate->repo ? istate->repo : the_repository;
> > enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
> > + enum fsmonitor_reason reason = fsm_settings__get_reason(r);
> > +
> > + if (reason > FSMONITOR_REASON_OK)
> > + die("%s", fsm_settings__get_incompatible_msg(r, reason));
>
> We don't want to call die() here. Maybe just silently return without doing
> anything or issue a warning() and return. (But I'm favoring a silent return
> here.)
>
> From the clients' (`git status`, `git diff`, etc.) point of view, they just want a
> speed-up, if possible, but we shouldn't kill them; we should just let them do
> the normal scan that would have done if the feature were turned off.
>
> Jeff
If we just silently return then fsmonitor is in a perpetual incompatible state and the user gets no benefit from fsmonitor (in fact it could be worse as fsmonitor will attempt to spawn over and over again). I would think that it would be better to at least inform the user so that they can update fsmonitor's settings and have a more pleasant experience going forward.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v10 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-20 20:33 ` [PATCH v10 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-09-20 20:33 ` Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-20 20:33 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
system support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/git-fsmonitor--daemon.txt | 48 +++++++++++++++++++++++--
1 file changed, 45 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..6ad3e518ae0 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
NAME
----
-git-fsmonitor--daemon - A Built-in File System Monitor
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
SYNOPSIS
--------
@@ -17,7 +17,7 @@ DESCRIPTION
-----------
A daemon to watch the working directory for file and directory
-changes using platform-specific file system notification facilities.
+changes using platform-specific filesystem notification facilities.
This daemon communicates directly with commands like `git status`
using the link:technical/api-simple-ipc.html[simple IPC] interface
@@ -63,13 +63,55 @@ CAVEATS
-------
The fsmonitor daemon does not currently know about submodules and does
-not know to filter out file system events that happen within a
+not know to filter out filesystem events that happen within a
submodule. If fsmonitor daemon is watching a super repo and a file is
modified within the working directory of a submodule, it will report
the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory, however, if the
+`.git` directory is on a network-mounted filesystem, it will be instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+the fsmonitor daemon will pay attention to the following configuration
+variables:
+
+`fsmonitor.allowRemote`::
+ By default, the daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
+ this behavior.
+
+`fsmonitor.socketDir`::
+ This Mac OS-specific option, if set, specifies the directory in
+ which to create the Unix domain socket used for communication
+ between fsmonitor and various Git commands. The directory must
+ reside on a native Mac OS filesystem as discussed above.
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-20 20:33 ` [PATCH v10 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-20 20:33 ` [PATCH v10 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-21 22:18 ` Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (6 more replies)
6 siblings, 7 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-21 22:18 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
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/git-fsmonitor--daemon.txt | 48 ++++++-
Makefile | 2 +
builtin/fsmonitor--daemon.c | 11 +-
compat/fsmonitor/fsm-ipc-darwin.c | 51 +++++++
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 | 59 ++++++++
fsmonitor-settings.c | 68 ++++++++-
fsmonitor-settings.h | 4 +-
fsmonitor.c | 4 +
18 files changed, 576 insertions(+), 246 deletions(-)
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: d3fa443f97e3a8d75b51341e2d5bac380b7422df
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v11
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v11
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v10:
1: 155a6890806 = 1: 155a6890806 fsmonitor: refactor filesystem checks to common interface
2: dbe113abb87 = 2: dbe113abb87 fsmonitor: relocate socket file if .git directory is remote
3: 86c15299ae8 = 3: 86c15299ae8 fsmonitor: avoid socket location check if using hook
4: 4f6c98cf834 ! 4: 1a516fd9214 fsmonitor: deal with synthetic firmlinks on macOS
@@ compat/fsmonitor/fsm-listen-darwin.c
struct fsm_listen_data
{
+@@ compat/fsmonitor/fsm-listen-darwin.c: static void fsevent_callback(ConstFSEventStreamRef streamRef,
+ struct string_list cookie_list = STRING_LIST_INIT_DUP;
+ const char *path_k;
+ const char *slash;
+- int k;
++ char *resolved = NULL;
+ struct strbuf tmp = STRBUF_INIT;
++ int k;
+
+ /*
+ * Build a list of all filesystem changes into a private/local
@@ compat/fsmonitor/fsm-listen-darwin.c: static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
-+ path_k = fsmonitor__resolve_alias(paths[k], &state->alias);
-+ if (!path_k)
++ free(resolved);
++ resolved = fsmonitor__resolve_alias(paths[k], &state->alias);
++ if (resolved)
++ path_k = resolved;
++ else
+ path_k = paths[k];
/*
@@ compat/fsmonitor/fsm-listen-darwin.c: static void fsevent_callback(ConstFSEventS
/*
* We assume that any events that we received
+@@ compat/fsmonitor/fsm-listen-darwin.c: static void fsevent_callback(ConstFSEventStreamRef streamRef,
+ }
+ }
+
++ free(resolved);
+ fsmonitor_publish(state, batch, &cookie_list);
+ string_list_clear(&cookie_list, 0);
+ strbuf_release(&tmp);
+ return;
+
+ force_shutdown:
++ free(resolved);
+ fsmonitor_batch__free_list(batch);
+ string_list_clear(&cookie_list, 0);
+
## compat/fsmonitor/fsm-path-utils-darwin.c ##
@@
5: 8f6c1fbacbf ! 5: e0fe05dabef fsmonitor: check for compatability before communicating with fsmonitor
@@ fsmonitor-settings.c: char *fsm_settings__get_incompatible_msg(const struct repo
strbuf_addf(&msg,
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
-+ _("socket directory '%s' is incompatible with fsmonitor due"),
++ _("socket directory '%s' is incompatible with fsmonitor due"
++ " to lack of Unix sockets support"),
+ socket_dir);
-+ strbuf_add(&msg, _(" to lack of Unix sockets support"), 32);
goto done;
}
@@ fsmonitor.c: void refresh_fsmonitor(struct index_state *istate)
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (reason > FSMONITOR_REASON_OK)
-+ die("%s", fsm_settings__get_incompatible_msg(r, reason));
++ warning("%s", fsm_settings__get_incompatible_msg(r, reason));
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
6: d7c25bf96c6 = 6: 3200b505988 fsmonitor: add documentation for allowRemote and socketDir options
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v11 1/6] fsmonitor: refactor filesystem checks to common interface
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
@ 2022-09-21 22:18 ` Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-21 22:18 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index d9247ead45b..6e492a67547 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 2237109b57f..b88494bf59b 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v11 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-21 22:18 ` Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-21 22:18 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote file system, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 51 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-ipc.c | 18 ++++-----
fsmonitor-ipc.h | 4 +-
8 files changed, 77 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index 6e492a67547..58bb9248471 100644
--- a/Makefile
+++ b/Makefile
@@ -2034,6 +2034,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..0f551e5e572
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,51 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path;
+ SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (!r)
+ BUG("No repository passed into fsmonitor_ipc__get_path");
+
+ if (ipc_path)
+ return ipc_path;
+
+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
+ return ipc_path;
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
+ free(sock_dir);
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..e08c505c148
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..681d8bf963e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index b88494bf59b..7e7b6b9a362 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v11 3/6] fsmonitor: avoid socket location check if using hook
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-21 22:18 ` Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-21 22:18 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 681d8bf963e..40da2d3b533 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v11 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-21 22:18 ` [PATCH v11 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-21 22:18 ` Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-21 22:18 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 14 +++-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 ++++++++++
6 files changed, 168 insertions(+), 2 deletions(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..56fcd1c2baa 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ state.alias.alias = NULL;
+ state.alias.points_to = NULL;
+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
+ err = error(_("could not get worktree alias"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..daeee4e465c 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -198,8 +199,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
struct string_list cookie_list = STRING_LIST_INIT_DUP;
const char *path_k;
const char *slash;
- int k;
+ char *resolved = NULL;
struct strbuf tmp = STRBUF_INIT;
+ int k;
/*
* Build a list of all filesystem changes into a private/local
@@ -209,7 +211,12 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ free(resolved);
+ resolved = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (resolved)
+ path_k = resolved;
+ else
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +245,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
@@ -360,12 +368,14 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
}
}
+ free(resolved);
fsmonitor_publish(state, batch, &cookie_list);
string_list_clear(&cookie_list, 0);
strbuf_release(&tmp);
return;
force_shutdown:
+ free(resolved);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..13807f58e95 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,92 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR * dir;
+ int read;
+ int retval;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ retval = 0;
+ dir = opendir("/");
+ if (!dir)
+ return -1;
+
+ strbuf_init(&alias, 256);
+ 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));
+
+ 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) == 0)
+ && path[points_to.len] == '/') {
+ info->alias = strbuf_detach(&alias, NULL);
+ info->points_to = strbuf_detach(&points_to, NULL);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
+ path, info->alias, info->points_to);
+ retval = 0;
+ goto done;
+ }
+ } else if (errno != EINVAL) { /* Something other than not a link */
+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
+ retval = -1;
+ goto done;
+ }
+ }
+
+ done:
+ closedir(dir);
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ int len = info->alias ? strlen(info->alias) : 0;
+
+ if (!len)
+ return NULL;
+
+ if ((strncmp(info->alias, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
+ int ptr_len = strlen(info->points_to);
+ int rem_len = strlen(remainder);
+
+ strbuf_init(&tmp, ptr_len + rem_len);
+ strbuf_add(&tmp, info->points_to, ptr_len);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..50ef37e57bb 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,6 +1,14 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ char *alias;
+ char *points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
@@ -20,4 +28,32 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by set info.alias and
+ * info.points_to and is responsible for releasing it with `free(3)`
+ * when done.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it with `free(3)` when done.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v11 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-21 22:18 ` [PATCH v11 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-21 22:18 ` Eric DeCosta via GitGitGadget
2022-09-21 22:18 ` [PATCH v11 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-21 22:18 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If fsmonitor is not in a compatible state, die with an appropriate error
messge.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
fsmonitor-settings.c | 10 +++++++---
fsmonitor-settings.h | 2 +-
fsmonitor.c | 4 ++++
4 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 40da2d3b533..44233125df8 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -38,7 +38,7 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
strbuf_release(&path);
if (fs.is_remote)
- return FSMONITOR_REASON_REMOTE;
+ return FSMONITOR_REASON_NOSOCKETS;
if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 531a1b6f956..8592a4d9bad 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
+#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
#include "fsmonitor-path-utils.h"
@@ -242,10 +243,11 @@ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
return r->settings.fsmonitor->reason;
}
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason)
{
struct strbuf msg = STRBUF_INIT;
+ const char *socket_dir;
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
@@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
goto done;
case FSMONITOR_REASON_NOSOCKETS:
+ socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
strbuf_addf(&msg,
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
+ _("socket directory '%s' is incompatible with fsmonitor due"
+ " to lack of Unix sockets support"),
+ socket_dir);
goto done;
}
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index 0721617b95a..ab02e3995ee 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
const char *fsm_settings__get_hook_path(struct repository *r);
enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason);
struct fsmonitor_settings;
diff --git a/fsmonitor.c b/fsmonitor.c
index 57d6a483bee..1a86b9789a9 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -305,6 +305,10 @@ void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (reason > FSMONITOR_REASON_OK)
+ warning("%s", fsm_settings__get_incompatible_msg(r, reason));
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v11 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-21 22:18 ` [PATCH v11 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-09-21 22:18 ` Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-21 22:18 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
system support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/git-fsmonitor--daemon.txt | 48 +++++++++++++++++++++++--
1 file changed, 45 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..6ad3e518ae0 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
NAME
----
-git-fsmonitor--daemon - A Built-in File System Monitor
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
SYNOPSIS
--------
@@ -17,7 +17,7 @@ DESCRIPTION
-----------
A daemon to watch the working directory for file and directory
-changes using platform-specific file system notification facilities.
+changes using platform-specific filesystem notification facilities.
This daemon communicates directly with commands like `git status`
using the link:technical/api-simple-ipc.html[simple IPC] interface
@@ -63,13 +63,55 @@ CAVEATS
-------
The fsmonitor daemon does not currently know about submodules and does
-not know to filter out file system events that happen within a
+not know to filter out filesystem events that happen within a
submodule. If fsmonitor daemon is watching a super repo and a file is
modified within the working directory of a submodule, it will report
the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory, however, if the
+`.git` directory is on a network-mounted filesystem, it will be instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+the fsmonitor daemon will pay attention to the following configuration
+variables:
+
+`fsmonitor.allowRemote`::
+ By default, the daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
+ this behavior.
+
+`fsmonitor.socketDir`::
+ This Mac OS-specific option, if set, specifies the directory in
+ which to create the Unix domain socket used for communication
+ between fsmonitor and various Git commands. The directory must
+ reside on a native Mac OS filesystem as discussed above.
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-21 22:18 ` [PATCH v11 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-21 22:18 ` [PATCH v11 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-24 19:46 ` Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (7 more replies)
6 siblings, 8 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-24 19:46 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
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/git-fsmonitor--daemon.txt | 48 ++++++-
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 | 59 ++++++++
fsmonitor-settings.c | 68 ++++++++-
fsmonitor-settings.h | 4 +-
fsmonitor.c | 7 +
18 files changed, 580 insertions(+), 246 deletions(-)
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: 4b79ee4b0cd1130ba8907029cdc5f6a1632aca26
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v12
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v12
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v11:
1: 155a6890806 = 1: 5958dab0163 fsmonitor: refactor filesystem checks to common interface
2: dbe113abb87 ! 2: 20220b08edb fsmonitor: relocate socket file if .git directory is remote
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
-+ static const char *ipc_path;
++ static const char *ipc_path = NULL;
+ SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
@@ compat/fsmonitor/fsm-ipc-darwin.c (new)
+ if (ipc_path)
+ return ipc_path;
+
-+ ipc_path = fsmonitor_ipc__get_default_path();
+
+ /* By default the socket file is created in the .git directory */
-+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
++ if (fsmonitor__is_fs_remote(r->gitdir) < 1) {
++ ipc_path = fsmonitor_ipc__get_default_path();
+ return ipc_path;
++ }
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
3: 86c15299ae8 = 3: e9921550a67 fsmonitor: avoid socket location check if using hook
4: 1a516fd9214 = 4: 6efdc6ed74e fsmonitor: deal with synthetic firmlinks on macOS
5: e0fe05dabef ! 5: 421d77775dc fsmonitor: check for compatability before communicating with fsmonitor
@@ fsmonitor-settings.h: enum fsmonitor_mode fsm_settings__get_mode(struct reposito
struct fsmonitor_settings;
## fsmonitor.c ##
+@@ fsmonitor.c: static int fsmonitor_force_update_threshold = 100;
+
+ void refresh_fsmonitor(struct index_state *istate)
+ {
++ static int warn_once = 0;
+ struct strbuf query_result = STRBUF_INIT;
+ int query_success = 0, hook_version = -1;
+ size_t bol = 0; /* beginning of line */
@@ fsmonitor.c: void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
-+ if (reason > FSMONITOR_REASON_OK)
++ if (!warn_once && reason > FSMONITOR_REASON_OK) {
++ warn_once = 1;
+ warning("%s", fsm_settings__get_incompatible_msg(r, reason));
++ }
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
6: 3200b505988 = 6: b375b0ac798 fsmonitor: add documentation for allowRemote and socketDir options
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v12 1/6] fsmonitor: refactor filesystem checks to common interface
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
@ 2022-09-24 19:46 ` Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (6 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-24 19:46 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index cac3452edb9..ffab427ea5b 100644
--- a/Makefile
+++ b/Makefile
@@ -2044,6 +2044,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index ea2a531be87..5482a04b3ce 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v12 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-24 19:46 ` Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-24 19:46 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote file system, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 52 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-ipc.c | 18 ++++-----
fsmonitor-ipc.h | 4 +-
8 files changed, 78 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index ffab427ea5b..feb675a6959 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..ce843d63348
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,52 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path = NULL;
+ SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (!r)
+ BUG("No repository passed into fsmonitor_ipc__get_path");
+
+ if (ipc_path)
+ return ipc_path;
+
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(r->gitdir) < 1) {
+ ipc_path = fsmonitor_ipc__get_default_path();
+ return ipc_path;
+ }
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
+ free(sock_dir);
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..e08c505c148
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..681d8bf963e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 5482a04b3ce..787738e6fa3 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v12 3/6] fsmonitor: avoid socket location check if using hook
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-24 19:46 ` Eric DeCosta via GitGitGadget
2022-09-24 19:46 ` [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-24 19:46 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 681d8bf963e..40da2d3b533 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-24 19:46 ` [PATCH v12 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-24 19:46 ` Eric DeCosta via GitGitGadget
2022-09-26 15:16 ` Ævar Arnfjörð Bjarmason
2022-09-26 15:27 ` Ævar Arnfjörð Bjarmason
2022-09-24 19:46 ` [PATCH v12 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
7 siblings, 2 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-24 19:46 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 14 +++-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 ++++++++++
6 files changed, 168 insertions(+), 2 deletions(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..56fcd1c2baa 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ state.alias.alias = NULL;
+ state.alias.points_to = NULL;
+ if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
+ err = error(_("could not get worktree alias"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..daeee4e465c 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -198,8 +199,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
struct string_list cookie_list = STRING_LIST_INIT_DUP;
const char *path_k;
const char *slash;
- int k;
+ char *resolved = NULL;
struct strbuf tmp = STRBUF_INIT;
+ int k;
/*
* Build a list of all filesystem changes into a private/local
@@ -209,7 +211,12 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ free(resolved);
+ resolved = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (resolved)
+ path_k = resolved;
+ else
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +245,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
@@ -360,12 +368,14 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
}
}
+ free(resolved);
fsmonitor_publish(state, batch, &cookie_list);
string_list_clear(&cookie_list, 0);
strbuf_release(&tmp);
return;
force_shutdown:
+ free(resolved);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..13807f58e95 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,92 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR * dir;
+ int read;
+ int retval;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ retval = 0;
+ dir = opendir("/");
+ if (!dir)
+ return -1;
+
+ strbuf_init(&alias, 256);
+ 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));
+
+ 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) == 0)
+ && path[points_to.len] == '/') {
+ info->alias = strbuf_detach(&alias, NULL);
+ info->points_to = strbuf_detach(&points_to, NULL);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
+ path, info->alias, info->points_to);
+ retval = 0;
+ goto done;
+ }
+ } else if (errno != EINVAL) { /* Something other than not a link */
+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
+ retval = -1;
+ goto done;
+ }
+ }
+
+ done:
+ closedir(dir);
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ int len = info->alias ? strlen(info->alias) : 0;
+
+ if (!len)
+ return NULL;
+
+ if ((strncmp(info->alias, path, len) == 0)
+ && path[len] == '/') {
+ struct strbuf tmp;
+ const char *remainder = path + len;
+ int ptr_len = strlen(info->points_to);
+ int rem_len = strlen(remainder);
+
+ strbuf_init(&tmp, ptr_len + rem_len);
+ strbuf_add(&tmp, info->points_to, ptr_len);
+ strbuf_add(&tmp, remainder, rem_len);
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..50ef37e57bb 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,6 +1,14 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ char *alias;
+ char *points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
@@ -20,4 +28,32 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by set info.alias and
+ * info.points_to and is responsible for releasing it with `free(3)`
+ * when done.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it with `free(3)` when done.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-24 19:46 ` [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-26 15:16 ` Ævar Arnfjörð Bjarmason
2022-09-27 1:53 ` Eric DeCosta
2022-09-26 15:27 ` Ævar Arnfjörð Bjarmason
1 sibling, 1 reply; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-09-26 15:16 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Sat, Sep 24 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
> [...]
> + state.alias.alias = NULL;
> + state.alias.points_to = NULL;
> + if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
> + err = error(_("could not get worktree alias"));
> + goto done;
> + }
As we can see here this is in the one-off setup code...
> +int fsmonitor__get_alias(const char *path, struct alias_info *info)
> +{
> + DIR * dir;
> + int read;
> + int retval;
> + struct dirent *de;
> + struct strbuf alias;
> + struct strbuf points_to;
...more of a code clarity comment than anything, else, but...
> +
> + retval = 0;
> + dir = opendir("/");
> + if (!dir)
> + return -1;
> +
> + strbuf_init(&alias, 256);
> + strbuf_init(&points_to, MAXPATHLEN);
...can't we just use the STRBUF_INIT macro here instead? most paths are
nowhere near MAXPATHLEN, but more importantly we try to avoid these
sorts of memory micro-managements except for hot codepaths.
In this case it's just the one-off setup of fsmonitor, isn't it? So just
using the default allocation pattern seems worthwhile, and will save
e.g. anyone grepping for MAXPATHLEN looking for bugs (the MAXPATHLEN is
sometimes not the actual maximum pathlen).
> +
> + while ((de = readdir(dir)) != NULL) {
> + strbuf_reset(&alias);
> + strbuf_addch(&alias, '/');
> + strbuf_add(&alias, de->d_name, strlen(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) == 0)
We usually do (!strcmp()), not strcmp() == 0, ditto strncmp. See
CodingGuidelines.
> + done:
Nit: labels shouldn't be indented.
> + closedir(dir);
We checked the opendir() return value, why not closedir() too?
> + if ((strncmp(info->alias, path, len) == 0)
ditto !foo() v.s. foo() == 0.
> + && path[len] == '/') {
> + struct strbuf tmp;
> + const char *remainder = path + len;
> + int ptr_len = strlen(info->points_to);
> + int rem_len = strlen(remainder);
Make these s/int/size_t/.
> +
> + strbuf_init(&tmp, ptr_len + rem_len);
And use st_add() here instead of " + ". I don't think it'll overflow,
but it's good to guard overflows out of habit...
> + strbuf_add(&tmp, info->points_to, ptr_len);
Earlier you constructed a strbuf, and then strbuf_detached() it into
this new "struct alias_info" you made. And now we're having to strlen()
that to get the lenght that we knew earlier?
Can't we just make the member a "struct strbuf" instead? Maybe not, I
have not reviewed that aspect carefully...
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-26 15:16 ` Ævar Arnfjörð Bjarmason
@ 2022-09-27 1:53 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-27 1:53 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason, Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin
> -----Original Message-----
> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> Sent: Monday, September 26, 2022 11:16 AM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Cc: git@vger.kernel.org; Jeff Hostetler <git@jeffhostetler.com>; Eric Sunshine
> <sunshine@sunshineco.com>; Torsten Bögershausen <tboegi@web.de>;
> Ramsay Jones <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on
> macOS
>
>
> On Sat, Sep 24 2022, Eric DeCosta via GitGitGadget wrote:
>
> > From: Eric DeCosta <edecosta@mathworks.com> [...]
> > + state.alias.alias = NULL;
> > + state.alias.points_to = NULL;
> > + if (fsmonitor__get_alias(state.path_worktree_watch.buf,
> &state.alias)) {
> > + err = error(_("could not get worktree alias"));
> > + goto done;
> > + }
>
> As we can see here this is in the one-off setup code...
>
> > +int fsmonitor__get_alias(const char *path, struct alias_info *info) {
> > + DIR * dir;
> > + int read;
> > + int retval;
> > + struct dirent *de;
> > + struct strbuf alias;
> > + struct strbuf points_to;
>
> ...more of a code clarity comment than anything, else, but...
>
> > +
> > + retval = 0;
> > + dir = opendir("/");
> > + if (!dir)
> > + return -1;
> > +
> > + strbuf_init(&alias, 256);
> > + strbuf_init(&points_to, MAXPATHLEN);
>
>
> ...can't we just use the STRBUF_INIT macro here instead? most paths are
> nowhere near MAXPATHLEN, but more importantly we try to avoid these
> sorts of memory micro-managements except for hot codepaths.
>
> In this case it's just the one-off setup of fsmonitor, isn't it? So just using the
> default allocation pattern seems worthwhile, and will save e.g. anyone
> grepping for MAXPATHLEN looking for bugs (the MAXPATHLEN is sometimes
> not the actual maximum pathlen).
>
OK, makes sense.
> > +
> > + while ((de = readdir(dir)) != NULL) {
> > + strbuf_reset(&alias);
> > + strbuf_addch(&alias, '/');
> > + strbuf_add(&alias, de->d_name, strlen(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) == 0)
>
> We usually do (!strcmp()), not strcmp() == 0, ditto strncmp. See
> CodingGuidelines.
> > + done:
>
Fixed.
> Nit: labels shouldn't be indented.
>
Fixed
> > + closedir(dir);
>
> We checked the opendir() return value, why not closedir() too?
>
OK, will do.
> > + if ((strncmp(info->alias, path, len) == 0)
>
> ditto !foo() v.s. foo() == 0.
>
> > + && path[len] == '/') {
> > + struct strbuf tmp;
> > + const char *remainder = path + len;
> > + int ptr_len = strlen(info->points_to);
> > + int rem_len = strlen(remainder);
>
> Make these s/int/size_t/.
>
> > +
> > + strbuf_init(&tmp, ptr_len + rem_len);
>
> And use st_add() here instead of " + ". I don't think it'll overflow, but it's good
> to guard overflows out of habit...
>
Sure, just strbuf_add(). Then I don't need ptr_len or rem_len either.
> > + strbuf_add(&tmp, info->points_to, ptr_len);
>
> Earlier you constructed a strbuf, and then strbuf_detached() it into this new
> "struct alias_info" you made. And now we're having to strlen() that to get the
> lenght that we knew earlier?
>
> Can't we just make the member a "struct strbuf" instead? Maybe not, I have
> not reviewed that aspect carefully...
>
Certainly could do that.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-24 19:46 ` [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
2022-09-26 15:16 ` Ævar Arnfjörð Bjarmason
@ 2022-09-26 15:27 ` Ævar Arnfjörð Bjarmason
1 sibling, 0 replies; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-09-26 15:27 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Sat, Sep 24 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
..one aspect I missed...
> + state.alias.alias = NULL;
> + state.alias.points_to = NULL;
> + if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
> + err = error(_("could not get worktree alias"));
> + goto done;
Okey, it errored and we call error() to say it didn't work, good so far,
but...
> +int fsmonitor__get_alias(const char *path, struct alias_info *info)
> +{
> + DIR * dir;
> + int read;
> + int retval;
...we could just...
> + struct dirent *de;
> + struct strbuf alias;
> + struct strbuf points_to;
> +
> + retval = 0;
...have initialized that above if we do it unconditionally, but more on
this below...
> + dir = opendir("/");
> + if (!dir)
> + return -1;
Here in the actual implementation, which looking at the end-state we
*only* end up calling from that one caller we could have called
error_errno() to get a better message, but didn't.
I think much better would be to skip that above entirely, or keep it you
want two errors, but then just have the more meaningful error_errno()
here, where we're closer to the error, and can report a better one.
Of course we might sometimes have a good error, and sometimes a bad one,
but...(continued below)
> +
> + strbuf_init(&alias, 256);
> + 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));
> +
> + read = readlink(alias.buf, points_to.buf, MAXPATHLEN);
I think a:
if (!read)
BUG("got 0 from readlink?");
Or something would be a good paranoia addition, as you're technically
relying on...
> + if (read > 0) {
> + strbuf_setlen(&points_to, read);
> + if ((strncmp(points_to.buf, path, points_to.len) == 0)
> + && path[points_to.len] == '/') {
> + info->alias = strbuf_detach(&alias, NULL);
> + info->points_to = strbuf_detach(&points_to, NULL);
> + trace_printf_key(&trace_fsmonitor,
> + "Found alias for '%s' : '%s' -> '%s'",
> + path, info->alias, info->points_to);
> + retval = 0;
> + goto done;
> + }
> + } else if (errno != EINVAL) { /* Something other than not a link */
...the possibility that we return 0 but a stale errno happens to be set,
I don't think it'll happen in practice and that it always returned -1 if
we get here, but being strict with calling syscalls is generally good.
> + trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
(continued from above)..here we see the only codepath that sets retval
!= 0,
> + retval = -1;
Here we could have just called error_errno() instead.
> + * The caller owns the storage that the returned string occupies and
> + * is responsible for releasing it with `free(3)` when done.
nit: we could just put a full stop after "it" and skip the
rest. I.e. trust that the reader knows that allocated memory is freed
with free().
> + */
> +char *fsmonitor__resolve_alias(const char *path,
> + const struct alias_info *info);
> +
> +
nit: extra whitespace at end of file.
> #endif
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v12 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-24 19:46 ` [PATCH v12 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-24 19:46 ` Eric DeCosta via GitGitGadget
2022-09-25 14:00 ` Eric DeCosta
2022-09-26 15:23 ` Ævar Arnfjörð Bjarmason
2022-09-24 19:46 ` [PATCH v12 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
7 siblings, 2 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-24 19:46 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If fsmonitor is not in a compatible state, die with an appropriate error
messge.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
fsmonitor-settings.c | 10 +++++++---
fsmonitor-settings.h | 2 +-
fsmonitor.c | 7 +++++++
4 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 40da2d3b533..44233125df8 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -38,7 +38,7 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
strbuf_release(&path);
if (fs.is_remote)
- return FSMONITOR_REASON_REMOTE;
+ return FSMONITOR_REASON_NOSOCKETS;
if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 531a1b6f956..8592a4d9bad 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
+#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
#include "fsmonitor-path-utils.h"
@@ -242,10 +243,11 @@ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
return r->settings.fsmonitor->reason;
}
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason)
{
struct strbuf msg = STRBUF_INIT;
+ const char *socket_dir;
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
@@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
goto done;
case FSMONITOR_REASON_NOSOCKETS:
+ socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
strbuf_addf(&msg,
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
+ _("socket directory '%s' is incompatible with fsmonitor due"
+ " to lack of Unix sockets support"),
+ socket_dir);
goto done;
}
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index 0721617b95a..ab02e3995ee 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
const char *fsm_settings__get_hook_path(struct repository *r);
enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason);
struct fsmonitor_settings;
diff --git a/fsmonitor.c b/fsmonitor.c
index 57d6a483bee..540736b39fd 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -295,6 +295,7 @@ static int fsmonitor_force_update_threshold = 100;
void refresh_fsmonitor(struct index_state *istate)
{
+ static int warn_once = 0;
struct strbuf query_result = STRBUF_INIT;
int query_success = 0, hook_version = -1;
size_t bol = 0; /* beginning of line */
@@ -305,6 +306,12 @@ void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (!warn_once && reason > FSMONITOR_REASON_OK) {
+ warn_once = 1;
+ warning("%s", fsm_settings__get_incompatible_msg(r, reason));
+ }
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* RE: [PATCH v12 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-24 19:46 ` [PATCH v12 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-09-25 14:00 ` Eric DeCosta
2022-09-26 15:23 ` Ævar Arnfjörð Bjarmason
1 sibling, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-25 14:00 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget, git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Sent: Saturday, September 24, 2022 3:46 PM
> To: git@vger.kernel.org
> Cc: Jeff Hostetler <git@jeffhostetler.com>; Eric Sunshine
> <sunshine@sunshineco.com>; Torsten Bögershausen <tboegi@web.de>;
> Ævar Arnfjörð Bjarmason <avarab@gmail.com>; Ramsay Jones
> <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>;
> Eric DeCosta <edecosta@mathworks.com>
> Subject: [PATCH v12 5/6] fsmonitor: check for compatability before
> communicating with fsmonitor
>
> From: Eric DeCosta <edecosta@mathworks.com>
>
> If fsmonitor is not in a compatible state, die with an appropriate error
> messge.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
Grr. Should be "warn with an appropriate error message".
-Eric
> compat/fsmonitor/fsm-settings-darwin.c | 2 +-
> fsmonitor-settings.c | 10 +++++++---
> fsmonitor-settings.h | 2 +-
> fsmonitor.c | 7 +++++++
> 4 files changed, 16 insertions(+), 5 deletions(-)
>
> diff --git a/compat/fsmonitor/fsm-settings-darwin.c
> b/compat/fsmonitor/fsm-settings-darwin.c
> index 40da2d3b533..44233125df8 100644
> --- a/compat/fsmonitor/fsm-settings-darwin.c
> +++ b/compat/fsmonitor/fsm-settings-darwin.c
> @@ -38,7 +38,7 @@ static enum fsmonitor_reason
> check_uds_volume(struct repository *r)
> strbuf_release(&path);
>
> if (fs.is_remote)
> - return FSMONITOR_REASON_REMOTE;
> + return FSMONITOR_REASON_NOSOCKETS;
>
> if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
> return FSMONITOR_REASON_NOSOCKETS;
> diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c index
> 531a1b6f956..8592a4d9bad 100644
> --- a/fsmonitor-settings.c
> +++ b/fsmonitor-settings.c
> @@ -1,6 +1,7 @@
> #include "cache.h"
> #include "config.h"
> #include "repository.h"
> +#include "fsmonitor-ipc.h"
> #include "fsmonitor-settings.h"
> #include "fsmonitor-path-utils.h"
>
> @@ -242,10 +243,11 @@ enum fsmonitor_reason
> fsm_settings__get_reason(struct repository *r)
> return r->settings.fsmonitor->reason;
> }
>
> -char *fsm_settings__get_incompatible_msg(const struct repository *r,
> +char *fsm_settings__get_incompatible_msg(struct repository *r,
> enum fsmonitor_reason reason)
> {
> struct strbuf msg = STRBUF_INIT;
> + const char *socket_dir;
>
> switch (reason) {
> case FSMONITOR_REASON_UNTESTED:
> @@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const
> struct repository *r,
> goto done;
>
> case FSMONITOR_REASON_NOSOCKETS:
> + socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
> strbuf_addf(&msg,
> - _("repository '%s' is incompatible with fsmonitor
> due to lack of Unix sockets"),
> - r->worktree);
> + _("socket directory '%s' is incompatible with
> fsmonitor due"
> + " to lack of Unix sockets support"),
> + socket_dir);
> goto done;
> }
>
> diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h index
> 0721617b95a..ab02e3995ee 100644
> --- a/fsmonitor-settings.h
> +++ b/fsmonitor-settings.h
> @@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct
> repository *r); const char *fsm_settings__get_hook_path(struct repository
> *r);
>
> enum fsmonitor_reason fsm_settings__get_reason(struct repository *r); -
> char *fsm_settings__get_incompatible_msg(const struct repository *r,
> +char *fsm_settings__get_incompatible_msg(struct repository *r,
> enum fsmonitor_reason reason);
>
> struct fsmonitor_settings;
> diff --git a/fsmonitor.c b/fsmonitor.c
> index 57d6a483bee..540736b39fd 100644
> --- a/fsmonitor.c
> +++ b/fsmonitor.c
> @@ -295,6 +295,7 @@ static int fsmonitor_force_update_threshold = 100;
>
> void refresh_fsmonitor(struct index_state *istate) {
> + static int warn_once = 0;
> struct strbuf query_result = STRBUF_INIT;
> int query_success = 0, hook_version = -1;
> size_t bol = 0; /* beginning of line */ @@ -305,6 +306,12 @@ void
> refresh_fsmonitor(struct index_state *istate)
> int is_trivial = 0;
> struct repository *r = istate->repo ? istate->repo : the_repository;
> enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
> + enum fsmonitor_reason reason = fsm_settings__get_reason(r);
> +
> + if (!warn_once && reason > FSMONITOR_REASON_OK) {
> + warn_once = 1;
> + warning("%s", fsm_settings__get_incompatible_msg(r,
> reason));
> + }
>
> if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
> istate->fsmonitor_has_run_once)
> --
> gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v12 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-24 19:46 ` [PATCH v12 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
2022-09-25 14:00 ` Eric DeCosta
@ 2022-09-26 15:23 ` Ævar Arnfjörð Bjarmason
2022-09-27 1:25 ` Eric DeCosta
1 sibling, 1 reply; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-09-26 15:23 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Sat, Sep 24 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
> [...]
> @@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
> goto done;
>
> case FSMONITOR_REASON_NOSOCKETS:
> + socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
> strbuf_addf(&msg,
> - _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
> - r->worktree);
> + _("socket directory '%s' is incompatible with fsmonitor due"
> + " to lack of Unix sockets support"),
> + socket_dir);
Could do with less "while at it" here. We are:
* Wrapping the string, making the functional change(s) harder to spot.
* replacing r->worktree with socket_dir
* Adding " support" to the end of the string, and replacing "repository" with "socket directory"
AFAICT the continuation of the string isn't indented in the way we
usually do, i.e. to align with the opening ".
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v12 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-26 15:23 ` Ævar Arnfjörð Bjarmason
@ 2022-09-27 1:25 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-27 1:25 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason, Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin
> -----Original Message-----
> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> Sent: Monday, September 26, 2022 11:24 AM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Cc: git@vger.kernel.org; Jeff Hostetler <git@jeffhostetler.com>; Eric Sunshine
> <sunshine@sunshineco.com>; Torsten Bögershausen <tboegi@web.de>;
> Ramsay Jones <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v12 5/6] fsmonitor: check for compatability before
> communicating with fsmonitor
>
>
> On Sat, Sep 24 2022, Eric DeCosta via GitGitGadget wrote:
>
> > From: Eric DeCosta <edecosta@mathworks.com> [...] @@ -281,9 +283,11
> @@
> > char *fsm_settings__get_incompatible_msg(const struct repository *r,
> > goto done;
> >
> > case FSMONITOR_REASON_NOSOCKETS:
> > + socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
> > strbuf_addf(&msg,
> > - _("repository '%s' is incompatible with fsmonitor
> due to lack of Unix sockets"),
> > - r->worktree);
> > + _("socket directory '%s' is incompatible with
> fsmonitor due"
> > + " to lack of Unix sockets support"),
> > + socket_dir);
>
> Could do with less "while at it" here. We are:
>
> * Wrapping the string, making the functional change(s) harder to spot.
> * replacing r->worktree with socket_dir
> * Adding " support" to the end of the string, and replacing "repository" with
> "socket directory"
>
> AFAICT the continuation of the string isn't indented in the way we usually do,
> i.e. to align with the opening ".
The string, when properly indented, exceeds an 80 character line length. I'll fix the indentation, but I don't think there's a much better alternative to the wrapping.
The worktree could be in a perfectly fine location whereas the socket_dir may not . Crafting the error message the way I did reflects where the problem is rather than reporting a potentially misleading error about the repository.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v12 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-24 19:46 ` [PATCH v12 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-09-24 19:46 ` Eric DeCosta via GitGitGadget
2022-09-26 15:11 ` Ævar Arnfjörð Bjarmason
2022-09-25 14:18 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
7 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-24 19:46 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
system support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/git-fsmonitor--daemon.txt | 48 +++++++++++++++++++++++--
1 file changed, 45 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..6ad3e518ae0 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
NAME
----
-git-fsmonitor--daemon - A Built-in File System Monitor
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
SYNOPSIS
--------
@@ -17,7 +17,7 @@ DESCRIPTION
-----------
A daemon to watch the working directory for file and directory
-changes using platform-specific file system notification facilities.
+changes using platform-specific filesystem notification facilities.
This daemon communicates directly with commands like `git status`
using the link:technical/api-simple-ipc.html[simple IPC] interface
@@ -63,13 +63,55 @@ CAVEATS
-------
The fsmonitor daemon does not currently know about submodules and does
-not know to filter out file system events that happen within a
+not know to filter out filesystem events that happen within a
submodule. If fsmonitor daemon is watching a super repo and a file is
modified within the working directory of a submodule, it will report
the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory, however, if the
+`.git` directory is on a network-mounted filesystem, it will be instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+the fsmonitor daemon will pay attention to the following configuration
+variables:
+
+`fsmonitor.allowRemote`::
+ By default, the daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
+ this behavior.
+
+`fsmonitor.socketDir`::
+ This Mac OS-specific option, if set, specifies the directory in
+ which to create the Unix domain socket used for communication
+ between fsmonitor and various Git commands. The directory must
+ reside on a native Mac OS filesystem as discussed above.
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v12 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-24 19:46 ` [PATCH v12 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-26 15:11 ` Ævar Arnfjörð Bjarmason
2022-09-27 2:16 ` Eric Sunshine
0 siblings, 1 reply; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-09-26 15:11 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Sat, Sep 24 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
>
> Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
> Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
> system support for 'fsmonitor.socketDir'.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> Documentation/git-fsmonitor--daemon.txt | 48 +++++++++++++++++++++++--
> 1 file changed, 45 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
> index cc142fb8612..6ad3e518ae0 100644
> --- a/Documentation/git-fsmonitor--daemon.txt
> +++ b/Documentation/git-fsmonitor--daemon.txt
> @@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
>
> NAME
> ----
> -git-fsmonitor--daemon - A Built-in File System Monitor
> +git-fsmonitor--daemon - A Built-in Filesystem Monitor
We have ~400 uses of "filesystem" in-tree, but ~100 for "file system". I
don't mind the change per-se, but this looks like an odd "while at it"
change.
Skmming your series your 1/6 even uses "file system" in the commit message :)
> A daemon to watch the working directory for file and directory
> -changes using platform-specific file system notification facilities.
> +changes using platform-specific filesystem notification facilities.
More while-at-it...
>
> This daemon communicates directly with commands like `git status`
> using the link:technical/api-simple-ipc.html[simple IPC] interface
> @@ -63,13 +63,55 @@ CAVEATS
> -------
>
> The fsmonitor daemon does not currently know about submodules and does
> -not know to filter out file system events that happen within a
> +not know to filter out filesystem events that happen within a
...and here...
> submodule. If fsmonitor daemon is watching a super repo and a file is
> modified within the working directory of a submodule, it will report
> the change (as happening against the super repo). However, the client
> will properly ignore these extra events, so performance may be affected
> but it will not cause an incorrect result.
But here we get to the real meat of this change...
> +By default, the fsmonitor daemon refuses to work against network-mounted
> +repositories; this may be overridden by setting `fsmonitor.allowRemote` to
> +`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
> +correctly with all network-mounted repositories and such use is considered
> +experimental.
> +
> +On Mac OS, the inter-process communication (IPC) between various Git
> +commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
> +special type of file -- which is supported by native Mac OS filesystems,
> +but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
> +may or may not have the needed support; the fsmonitor daemon is not guaranteed
> +to work with these filesystems and such use is considered experimental.
> +
> +By default, the socket is created in the `.git` directory, however, if the
> +`.git` directory is on a network-mounted filesystem, it will be instead be
> +created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
> +network-mounted filesystem in which case you must set the configuration
> +variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
> +filesystem in which to create the socket file.
> +
> +If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
> +is on a native Mac OS file filesystem the fsmonitor daemon will report an
> +error that will cause the daemon and the currently running command to exit.
From skimming this looks reasonable.
> +CONFIGURATION
> +-------------
> +
> +When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
> +the fsmonitor daemon will pay attention to the following configuration
> +variables:
> +
> +`fsmonitor.allowRemote`::
> + By default, the daemon refuses to work against network-mounted
> + repositories. Setting `fsmonitor.allowRemote` to `true` overrides
> + this behavior.
> +
> +`fsmonitor.socketDir`::
> + This Mac OS-specific option, if set, specifies the directory in
> + which to create the Unix domain socket used for communication
> + between fsmonitor and various Git commands. The directory must
> + reside on a native Mac OS filesystem as discussed above.
> +
But here we should instead create Documentation/config/fsmonitor.txt,
and include it here. See my recent 7a54d740451 (Merge branch
'ab/dedup-config-and-command-docs', 2022-09-14) which made it so for
many commands.
By doing it like this "git config" is no longer the canonical reference
for all config, which it mostly was pre-7a54d740451, then was again
post-7a54d740451, and now we'd have this exception...
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v12 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-26 15:11 ` Ævar Arnfjörð Bjarmason
@ 2022-09-27 2:16 ` Eric Sunshine
2022-09-27 4:03 ` Eric DeCosta
0 siblings, 1 reply; 170+ messages in thread
From: Eric Sunshine @ 2022-09-27 2:16 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: Eric DeCosta via GitGitGadget, Git List, Jeff Hostetler,
Torsten Bögershausen, Ramsay Jones, Johannes Schindelin,
Eric DeCosta
On Mon, Sep 26, 2022 at 11:15 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
> On Sat, Sep 24 2022, Eric DeCosta via GitGitGadget wrote:
> > Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
> > Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
> > system support for 'fsmonitor.socketDir'.
> >
> > Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> > ---
> > -git-fsmonitor--daemon - A Built-in File System Monitor
> > +git-fsmonitor--daemon - A Built-in Filesystem Monitor
>
> We have ~400 uses of "filesystem" in-tree, but ~100 for "file system". I
> don't mind the change per-se, but this looks like an odd "while at it"
> change.
>
> > A daemon to watch the working directory for file and directory
> > -changes using platform-specific file system notification facilities.
> > +changes using platform-specific filesystem notification facilities.
>
> More while-at-it...
These changes may have been in response to my review[1], though I did
say that such a change was outside the scope of this series. Perhaps I
need to choose my wording more carefully?
[1]: https://lore.kernel.org/git/CAPig+cQ5SMw+0Cwtw47LQM59-mQjJaOPe_LTybAC2j=3F9OywA@mail.gmail.com/
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v12 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-27 2:16 ` Eric Sunshine
@ 2022-09-27 4:03 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-27 4:03 UTC (permalink / raw)
To: Eric Sunshine, Ævar Arnfjörð Bjarmason
Cc: Eric DeCosta via GitGitGadget, Git List, Jeff Hostetler,
Torsten Bögershausen, Ramsay Jones, Johannes Schindelin
> -----Original Message-----
> From: Eric Sunshine <sunshine@sunshineco.com>
> Sent: Monday, September 26, 2022 10:16 PM
> To: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> Cc: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>; Git List
> <git@vger.kernel.org>; Jeff Hostetler <git@jeffhostetler.com>; Torsten
> Bögershausen <tboegi@web.de>; Ramsay Jones
> <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v12 6/6] fsmonitor: add documentation for allowRemote
> and socketDir options
>
> On Mon, Sep 26, 2022 at 11:15 AM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
> > On Sat, Sep 24 2022, Eric DeCosta via GitGitGadget wrote:
> > > Add documentation for 'fsmonitor.allowRemote' and
> 'fsmonitor.socketDir'.
> > > Call-out experimental nature of 'fsmonitor.allowRemote' and limited
> > > file system support for 'fsmonitor.socketDir'.
> > >
> > > Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> > > ---
> > > -git-fsmonitor--daemon - A Built-in File System Monitor
> > > +git-fsmonitor--daemon - A Built-in Filesystem Monitor
> >
> > We have ~400 uses of "filesystem" in-tree, but ~100 for "file system".
> > I don't mind the change per-se, but this looks like an odd "while at it"
> > change.
> >
> > > A daemon to watch the working directory for file and directory
> > > -changes using platform-specific file system notification facilities.
> > > +changes using platform-specific filesystem notification facilities.
> >
> > More while-at-it...
>
> These changes may have been in response to my review[1], though I did say
> that such a change was outside the scope of this series. Perhaps I need to
> choose my wording more carefully?
>
> [1]: https://lore.kernel.org/git/CAPig+cQ5SMw+0Cwtw47LQM59-
> mQjJaOPe_LTybAC2j=3F9OywA@mail.gmail.com/ <https://protect-
> us.mimecast.com/s/STwOCG6A7DIYgAqYc7Wdth?domain=lore.kernel.org>
>
Your wording was fine. Next time I'll know better and leave it for another patch set.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-24 19:46 ` [PATCH v12 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-25 14:18 ` Eric DeCosta
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
7 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-09-25 14:18 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget, git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Sent: Saturday, September 24, 2022 3:46 PM
> To: git@vger.kernel.org
> Cc: Jeff Hostetler <git@jeffhostetler.com>; Eric Sunshine
> <sunshine@sunshineco.com>; Torsten Bögershausen <tboegi@web.de>;
> Ævar Arnfjörð Bjarmason <avarab@gmail.com>; Ramsay Jones
> <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against
> network-mounted repos
>
> 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.
>
> 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
>
Any further thoughts? If not I think this patch set is good to merge.
-Eric
> Documentation/git-fsmonitor--daemon.txt | 48 ++++++- 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 | 59
> ++++++++ fsmonitor-settings.c | 68 ++++++++- fsmonitor-settings.h | 4 +-
> fsmonitor.c | 7 +
> 18 files changed, 580 insertions(+), 246 deletions(-) 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: 4b79ee4b0cd1130ba8907029cdc5f6a1632aca26
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-
> 1326%2Fedecosta-mw%2Ffsmonitor_macos-v12 <https://protect-
> us.mimecast.com/s/8B-_CDkx7zSvvOYvhZsW8c?domain=github.com>
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git <https://protect-
> us.mimecast.com/s/G1p4CERy7Ah99649sZioql?domain=github.com> pr-
> 1326/edecosta-mw/fsmonitor_macos-v12
> Pull-Request: https://github.com/gitgitgadget/git/pull/1326 <https://protect-
> us.mimecast.com/s/tTa3CG6A7DIYYL3Ys0on8b?domain=github.com>
>
> Range-diff vs v11:
>
> 1: 155a6890806 = 1: 5958dab0163 fsmonitor: refactor filesystem checks to
> common interface
> 2: dbe113abb87 ! 2: 20220b08edb fsmonitor: relocate socket file if .git
> directory is remote @@ compat/fsmonitor/fsm-ipc-darwin.c (new)
> +
> +const char *fsmonitor_ipc__get_path(struct repository *r) {
> -+ static const char *ipc_path;
> ++ static const char *ipc_path = NULL;
> + SHA_CTX sha1ctx;
> + char *sock_dir = NULL;
> + struct strbuf ipc_file = STRBUF_INIT;
> @@ compat/fsmonitor/fsm-ipc-darwin.c (new)
> + if (ipc_path)
> + return ipc_path;
> +
> -+ ipc_path = fsmonitor_ipc__get_default_path();
> +
> + /* By default the socket file is created in the .git directory */
> -+ if (fsmonitor__is_fs_remote(ipc_path) < 1)
> ++ if (fsmonitor__is_fs_remote(r->gitdir) < 1) { ipc_path =
> ++ fsmonitor_ipc__get_default_path();
> + return ipc_path;
> ++ }
> +
> + SHA1_Init(&sha1ctx);
> + SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
> 3: 86c15299ae8 = 3: e9921550a67 fsmonitor: avoid socket location check if
> using hook
> 4: 1a516fd9214 = 4: 6efdc6ed74e fsmonitor: deal with synthetic firmlinks on
> macOS
> 5: e0fe05dabef ! 5: 421d77775dc fsmonitor: check for compatability before
> communicating with fsmonitor @@ fsmonitor-settings.h: enum
> fsmonitor_mode fsm_settings__get_mode(struct reposito struct
> fsmonitor_settings;
>
> ## fsmonitor.c ##
> +@@ fsmonitor.c: static int fsmonitor_force_update_threshold = 100;
> +
> + void refresh_fsmonitor(struct index_state *istate) {
> ++ static int warn_once = 0;
> + struct strbuf query_result = STRBUF_INIT; int query_success = 0,
> + hook_version = -1; size_t bol = 0; /* beginning of line */
> @@ fsmonitor.c: void refresh_fsmonitor(struct index_state *istate) int
> is_trivial = 0; struct repository *r = istate->repo ? istate->repo :
> the_repository; enum fsmonitor_mode fsm_mode =
> fsm_settings__get_mode(r);
> + enum fsmonitor_reason reason = fsm_settings__get_reason(r);
> +
> -+ if (reason > FSMONITOR_REASON_OK)
> ++ if (!warn_once && reason > FSMONITOR_REASON_OK) { warn_once = 1;
> + warning("%s", fsm_settings__get_incompatible_msg(r, reason));
> ++ }
>
> if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
> istate->fsmonitor_has_run_once)
> 6: 3200b505988 = 6: b375b0ac798 fsmonitor: add documentation for
> allowRemote and socketDir options
>
> --
> gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v13 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-24 19:46 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (6 preceding siblings ...)
2022-09-25 14:18 ` [PATCH v12 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta
@ 2022-09-27 20:57 ` Eric DeCosta via GitGitGadget
2022-09-27 20:57 ` [PATCH v13 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (6 more replies)
7 siblings, 7 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-27 20:57 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
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 | 13 +-
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 | 133 ++++++++++++++++
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, 583 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-v13
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v13
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v12:
1: 5958dab0163 = 1: 0b9b64428c5 fsmonitor: refactor filesystem checks to common interface
2: 20220b08edb ! 2: 680d4c83f99 fsmonitor: relocate socket file if .git directory is remote
@@ Metadata
## Commit message ##
fsmonitor: relocate socket file if .git directory is remote
- If the .git directory is on a remote file system, create the socket
+ If the .git directory is on a remote filesystem, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
3: e9921550a67 = 3: 7987d0c1f33 fsmonitor: avoid socket location check if using hook
4: 6efdc6ed74e ! 4: 324eb5acd85 fsmonitor: deal with synthetic firmlinks on macOS
@@ builtin/fsmonitor--daemon.c: static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
-+ state.alias.alias = NULL;
-+ state.alias.points_to = NULL;
++ 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"));
+ goto done;
@@ builtin/fsmonitor--daemon.c: static int fsmonitor_run_daemon(void)
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
+@@ builtin/fsmonitor--daemon.c: done:
+ strbuf_release(&state.path_gitdir_watch);
+ strbuf_release(&state.path_cookie_prefix);
+ strbuf_release(&state.path_ipc);
++ strbuf_release(&state.alias.alias);
++ strbuf_release(&state.alias.points_to);
+
+ return err;
+ }
## compat/fsmonitor/fsm-listen-darwin.c ##
@@
@@ 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;
++ DIR *dir;
+ int read;
-+ int retval;
++ int retval = -1;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
-+ retval = 0;
+ dir = opendir("/");
-+ if (!dir)
++ if (!dir) {
++ error_errno("opendir('/') failed");
+ return -1;
++ }
+
+ 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) {
@@ compat/fsmonitor/fsm-path-utils-darwin.c: int fsmonitor__is_fs_remote(const char
+ 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) == 0)
++ if ((!strncmp(points_to.buf, path, points_to.len))
+ && path[points_to.len] == '/') {
-+ info->alias = strbuf_detach(&alias, NULL);
-+ info->points_to = strbuf_detach(&points_to, NULL);
++ 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, info->points_to);
++ 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 */
-+ trace_printf_key(&trace_fsmonitor, "Error %s", strerror(errno));
-+ retval = -1;
++ error_errno("readlink('%s') failed", alias.buf);
+ goto done;
+ }
+ }
++ retval = 0; /* no alias */
+
-+ done:
-+ closedir(dir);
++done:
++ if (closedir(dir) < 0)
++ warning_errno("closedir('/') failed");
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
@@ compat/fsmonitor/fsm-path-utils-darwin.c: int fsmonitor__is_fs_remote(const char
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
-+ int len = info->alias ? strlen(info->alias) : 0;
-+
-+ if (!len)
++ if (!info->alias.len)
+ return NULL;
+
-+ if ((strncmp(info->alias, path, len) == 0)
-+ && path[len] == '/') {
-+ struct strbuf tmp;
-+ const char *remainder = path + len;
-+ int ptr_len = strlen(info->points_to);
-+ int rem_len = strlen(remainder);
++ if ((!strncmp(info->alias.buf, path, info->alias.len))
++ && path[info->alias.len] == '/') {
++ struct strbuf tmp = STRBUF_INIT;
++ const char *remainder = path + info->alias.len;
+
-+ strbuf_init(&tmp, ptr_len + rem_len);
-+ strbuf_add(&tmp, info->points_to, ptr_len);
-+ strbuf_add(&tmp, remainder, rem_len);
++ strbuf_addbuf(&tmp, &info->points_to);
++ strbuf_add(&tmp, remainder, strlen(remainder));
+ return strbuf_detach(&tmp, NULL);
+ }
+
@@ fsmonitor-path-utils.h
+
+struct alias_info
+{
-+ char *alias;
-+ char *points_to;
++ struct strbuf alias;
++ struct strbuf points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
+ };
+
+ /*
+- * Get some basic filesystem informtion for the given path
++ * Get some basic filesystem information for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
@@ fsmonitor-path-utils.h: int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
@@ fsmonitor-path-utils.h: int fsmonitor__get_fs_info(const char *path, struct fs_i
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
-+ * The caller owns the storage that is occupied by set info.alias and
-+ * info.points_to and is responsible for releasing it with `free(3)`
-+ * when done.
++ * The caller owns the storage that is occupied by info.alias and
++ * info.points_to and is responsible for releasing it.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
@@ fsmonitor-path-utils.h: int fsmonitor__get_fs_info(const char *path, struct fs_i
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
-+ * is responsible for releasing it with `free(3)` when done.
++ * is responsible for releasing it.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
-+
+
#endif
5: 421d77775dc ! 5: b1ea378dff7 fsmonitor: check for compatability before communicating with fsmonitor
@@ Metadata
## Commit message ##
fsmonitor: check for compatability before communicating with fsmonitor
- If fsmonitor is not in a compatible state, die with an appropriate error
- messge.
+ If fsmonitor is not in a compatible state, warn with an appropriate message.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
@@ fsmonitor-settings.c: char *fsm_settings__get_incompatible_msg(const struct repo
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
+ _("socket directory '%s' is incompatible with fsmonitor due"
-+ " to lack of Unix sockets support"),
++ " to lack of Unix sockets support"),
+ socket_dir);
goto done;
}
6: b375b0ac798 ! 6: 04f607b1f21 fsmonitor: add documentation for allowRemote and socketDir options
@@ Commit message
fsmonitor: add documentation for allowRemote and socketDir options
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
- Call-out experimental nature of 'fsmonitor.allowRemote' and limited file
- system support for 'fsmonitor.socketDir'.
+ Call-out experimental nature of 'fsmonitor.allowRemote' and limited
+ filesystem support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
+ ## Documentation/config.txt ##
+@@ Documentation/config.txt: include::config/filter.txt[]
+
+ include::config/fsck.txt[]
+
++include::config/fsmonitor--daemon.txt[]
++
+ include::config/gc.txt[]
+
+ include::config/gitcvs.txt[]
+
+ ## Documentation/config/fsmonitor--daemon.txt (new) ##
+@@
++fsmonitor.allowRemote::
++ By default, the fsmonitor daemon refuses to work against network-mounted
++ repositories. Setting `fsmonitor.allowRemote` to `true` overrides this
++ behavior. Only respected when `core.fsmonitor` is set to `true`.
++
++fsmonitor.socketDir::
++ This Mac OS-specific option, if set, specifies the directory in
++ which to create the Unix domain socket used for communication
++ between the fsmonitor daemon and various Git commands. The directory must
++ reside on a native Mac OS filesystem. Only respected when `core.fsmonitor`
++ is set to `true`.
+
## Documentation/git-fsmonitor--daemon.txt ##
@@ Documentation/git-fsmonitor--daemon.txt: git-fsmonitor{litdd}daemon(1)
@@ Documentation/git-fsmonitor--daemon.txt: CAVEATS
+CONFIGURATION
+-------------
+
-+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
-+the fsmonitor daemon will pay attention to the following configuration
-+variables:
++include::includes/cmd-config-section-all.txt[]
+
-+`fsmonitor.allowRemote`::
-+ By default, the daemon refuses to work against network-mounted
-+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides
-+ this behavior.
-+
-+`fsmonitor.socketDir`::
-+ This Mac OS-specific option, if set, specifies the directory in
-+ which to create the Unix domain socket used for communication
-+ between fsmonitor and various Git commands. The directory must
-+ reside on a native Mac OS filesystem as discussed above.
++include::config/fsmonitor--daemon.txt[]
+
GIT
---
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v13 1/6] fsmonitor: refactor filesystem checks to common interface
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
@ 2022-09-27 20:57 ` Eric DeCosta via GitGitGadget
2022-09-27 20:57 ` [PATCH v13 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-27 20:57 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index cac3452edb9..ffab427ea5b 100644
--- a/Makefile
+++ b/Makefile
@@ -2044,6 +2044,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index ea2a531be87..5482a04b3ce 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v13 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
2022-09-27 20:57 ` [PATCH v13 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-27 20:57 ` Eric DeCosta via GitGitGadget
2022-09-27 20:57 ` [PATCH v13 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-27 20:57 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote filesystem, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 52 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-ipc.c | 18 ++++-----
fsmonitor-ipc.h | 4 +-
8 files changed, 78 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index ffab427ea5b..feb675a6959 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..ce843d63348
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,52 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path = NULL;
+ SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (!r)
+ BUG("No repository passed into fsmonitor_ipc__get_path");
+
+ if (ipc_path)
+ return ipc_path;
+
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(r->gitdir) < 1) {
+ ipc_path = fsmonitor_ipc__get_default_path();
+ return ipc_path;
+ }
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
+ free(sock_dir);
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..e08c505c148
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..681d8bf963e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 5482a04b3ce..787738e6fa3 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v13 3/6] fsmonitor: avoid socket location check if using hook
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
2022-09-27 20:57 ` [PATCH v13 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-27 20:57 ` [PATCH v13 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-27 20:57 ` Eric DeCosta via GitGitGadget
2022-09-27 20:57 ` [PATCH v13 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-27 20:57 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 681d8bf963e..40da2d3b533 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v13 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-27 20:57 ` [PATCH v13 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-27 20:57 ` Eric DeCosta via GitGitGadget
2022-09-28 5:55 ` Ævar Arnfjörð Bjarmason
2022-09-27 20:57 ` [PATCH v13 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
6 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-27 20:57 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 10 +++
compat/fsmonitor/fsm-listen-darwin.c | 14 +++-
compat/fsmonitor/fsm-path-utils-darwin.c | 93 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 ++++++++-
6 files changed, 170 insertions(+), 3 deletions(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..d5056a97a06 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,13 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ 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"));
+ goto done;
+ }
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
@@ -1391,6 +1399,8 @@ done:
strbuf_release(&state.path_gitdir_watch);
strbuf_release(&state.path_cookie_prefix);
strbuf_release(&state.path_ipc);
+ strbuf_release(&state.alias.alias);
+ strbuf_release(&state.alias.points_to);
return err;
}
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..daeee4e465c 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -198,8 +199,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
struct string_list cookie_list = STRING_LIST_INIT_DUP;
const char *path_k;
const char *slash;
- int k;
+ char *resolved = NULL;
struct strbuf tmp = STRBUF_INIT;
+ int k;
/*
* Build a list of all filesystem changes into a private/local
@@ -209,7 +211,12 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ free(resolved);
+ resolved = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (resolved)
+ path_k = resolved;
+ else
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +245,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
@@ -360,12 +368,14 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
}
}
+ free(resolved);
fsmonitor_publish(state, batch, &cookie_list);
string_list_clear(&cookie_list, 0);
strbuf_release(&tmp);
return;
force_shutdown:
+ free(resolved);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..931c9318572 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,93 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR *dir;
+ int read;
+ int retval = -1;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to;
+
+ dir = opendir("/");
+ if (!dir) {
+ error_errno("opendir('/') failed");
+ return -1;
+ }
+
+ 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));
+
+ 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);
+ goto done;
+ }
+ }
+ retval = 0; /* no alias */
+
+done:
+ if (closedir(dir) < 0)
+ warning_errno("closedir('/') failed");
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ if (!info->alias.len)
+ return NULL;
+
+ if ((!strncmp(info->alias.buf, path, info->alias.len))
+ && path[info->alias.len] == '/') {
+ struct strbuf tmp = STRBUF_INIT;
+ const char *remainder = path + info->alias.len;
+
+ strbuf_addbuf(&tmp, &info->points_to);
+ strbuf_add(&tmp, remainder, strlen(remainder));
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..2624798d2c7 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,13 +1,21 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ struct strbuf alias;
+ struct strbuf points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
};
/*
- * Get some basic filesystem informtion for the given path
+ * Get some basic filesystem information for the given path
*
* Returns -1 on error, zero otherwise.
*/
@@ -20,4 +28,30 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by info.alias and
+ * info.points_to and is responsible for releasing it.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v13 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-27 20:57 ` [PATCH v13 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-28 5:55 ` Ævar Arnfjörð Bjarmason
0 siblings, 0 replies; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2022-09-28 5:55 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Tue, Sep 27 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
>
> + if (fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)) {
> + err = error(_("could not get worktree alias"));
We could keep this, but if we'd error() in the function itself we'd just
emit two error() lines when one would do.
> + dir = opendir("/");
We should have a:
const char *const dir = "/";
So we can pass it to this..
> + if (!dir) {
> + error_errno("opendir('/') failed");
...and as a parameter to a _()-translated string. That way the next
translation doesn't need to translate opendir('/home') or whatever.
> + return -1;
Just skip the braces and do "return error_errno()", these functions return -1 for thath reason.
> + strbuf_init(&alias, 256);
>
> + /* no way of knowing what the link will resolve to, so MAXPATHLEN */
> + strbuf_init(&points_to, MAXPATHLEN);
Still need manual memory juggling? Ok.
> +
> + 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", de->d_name);
Or rather:
strbuf_addf(&alias, "%s%s", root_dir, de->d_name);
If you split that "/" into a variable?
> +
> + 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);
> + goto done;
> + }
> + }
> + retval = 0; /* no alias */
> +
> +done:
> + if (closedir(dir) < 0)
> + warning_errno("closedir('/') failed");
Why not return an error for this? If you can't close the dir that
usually means the write or similar didn't work.
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v13 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-27 20:57 ` [PATCH v13 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-27 20:57 ` Eric DeCosta via GitGitGadget
2022-09-27 20:57 ` [PATCH v13 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-27 20:57 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If fsmonitor is not in a compatible state, warn with an appropriate message.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
fsmonitor-settings.c | 10 +++++++---
fsmonitor-settings.h | 2 +-
fsmonitor.c | 7 +++++++
4 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 40da2d3b533..44233125df8 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -38,7 +38,7 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
strbuf_release(&path);
if (fs.is_remote)
- return FSMONITOR_REASON_REMOTE;
+ return FSMONITOR_REASON_NOSOCKETS;
if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 531a1b6f956..ee63a97dc51 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
+#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
#include "fsmonitor-path-utils.h"
@@ -242,10 +243,11 @@ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
return r->settings.fsmonitor->reason;
}
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason)
{
struct strbuf msg = STRBUF_INIT;
+ const char *socket_dir;
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
@@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
goto done;
case FSMONITOR_REASON_NOSOCKETS:
+ socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
strbuf_addf(&msg,
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
+ _("socket directory '%s' is incompatible with fsmonitor due"
+ " to lack of Unix sockets support"),
+ socket_dir);
goto done;
}
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index 0721617b95a..ab02e3995ee 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
const char *fsm_settings__get_hook_path(struct repository *r);
enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason);
struct fsmonitor_settings;
diff --git a/fsmonitor.c b/fsmonitor.c
index 57d6a483bee..540736b39fd 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -295,6 +295,7 @@ static int fsmonitor_force_update_threshold = 100;
void refresh_fsmonitor(struct index_state *istate)
{
+ static int warn_once = 0;
struct strbuf query_result = STRBUF_INIT;
int query_success = 0, hook_version = -1;
size_t bol = 0; /* beginning of line */
@@ -305,6 +306,12 @@ void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (!warn_once && reason > FSMONITOR_REASON_OK) {
+ warn_once = 1;
+ warning("%s", fsm_settings__get_incompatible_msg(r, reason));
+ }
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v13 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-27 20:57 ` [PATCH v13 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-09-27 20:57 ` Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-27 20:57 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited
filesystem support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/config.txt | 2 ++
Documentation/config/fsmonitor--daemon.txt | 11 +++++++
Documentation/git-fsmonitor--daemon.txt | 37 ++++++++++++++++++++--
3 files changed, 47 insertions(+), 3 deletions(-)
create mode 100644 Documentation/config/fsmonitor--daemon.txt
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5b5b9765699..1e205831656 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -423,6 +423,8 @@ include::config/filter.txt[]
include::config/fsck.txt[]
+include::config/fsmonitor--daemon.txt[]
+
include::config/gc.txt[]
include::config/gitcvs.txt[]
diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.txt
new file mode 100644
index 00000000000..c225c6c9e74
--- /dev/null
+++ b/Documentation/config/fsmonitor--daemon.txt
@@ -0,0 +1,11 @@
+fsmonitor.allowRemote::
+ By default, the fsmonitor daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides this
+ behavior. Only respected when `core.fsmonitor` is set to `true`.
+
+fsmonitor.socketDir::
+ This Mac OS-specific option, if set, specifies the directory in
+ which to create the Unix domain socket used for communication
+ between the fsmonitor daemon and various Git commands. The directory must
+ reside on a native Mac OS filesystem. Only respected when `core.fsmonitor`
+ is set to `true`.
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..8238eadb0e1 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
NAME
----
-git-fsmonitor--daemon - A Built-in File System Monitor
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
SYNOPSIS
--------
@@ -17,7 +17,7 @@ DESCRIPTION
-----------
A daemon to watch the working directory for file and directory
-changes using platform-specific file system notification facilities.
+changes using platform-specific filesystem notification facilities.
This daemon communicates directly with commands like `git status`
using the link:technical/api-simple-ipc.html[simple IPC] interface
@@ -63,13 +63,44 @@ CAVEATS
-------
The fsmonitor daemon does not currently know about submodules and does
-not know to filter out file system events that happen within a
+not know to filter out filesystem events that happen within a
submodule. If fsmonitor daemon is watching a super repo and a file is
modified within the working directory of a submodule, it will report
the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory, however, if the
+`.git` directory is on a network-mounted filesystem, it will be instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fsmonitor--daemon.txt[]
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-27 20:57 ` [PATCH v13 " Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-27 20:57 ` [PATCH v13 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-09-28 20:12 ` Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (6 more replies)
6 siblings, 7 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-28 20:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v14 1/6] fsmonitor: refactor filesystem checks to common interface
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
@ 2022-09-28 20:12 ` Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-28 20:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 40 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 62 +++-----
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 23 +++
fsmonitor-settings.c | 50 +++++++
8 files changed, 263 insertions(+), 215 deletions(-)
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
diff --git a/Makefile b/Makefile
index cac3452edb9..ffab427ea5b 100644
--- a/Makefile
+++ b/Makefile
@@ -2044,6 +2044,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..067cbe6990a
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,40 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = fs.f_fstypename;
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..dba3ced6bb7 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,40 +16,34 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
+ if (fs.is_remote)
return FSMONITOR_REASON_REMOTE;
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (!strcmp(fs.typename, "ntfs"))
return FSMONITOR_REASON_NOSOCKETS;
return FSMONITOR_REASON_OK;
@@ -81,7 +53,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index ea2a531be87..5482a04b3ce 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..e48592887e7
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,23 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v14 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-09-28 20:12 ` Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-28 20:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote filesystem, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 52 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-ipc.c | 18 ++++-----
fsmonitor-ipc.h | 4 +-
8 files changed, 78 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index ffab427ea5b..feb675a6959 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..ce843d63348
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,52 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path = NULL;
+ SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (!r)
+ BUG("No repository passed into fsmonitor_ipc__get_path");
+
+ if (ipc_path)
+ return ipc_path;
+
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(r->gitdir) < 1) {
+ ipc_path = fsmonitor_ipc__get_default_path();
+ return ipc_path;
+ }
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
+ free(sock_dir);
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..e08c505c148
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index dba3ced6bb7..681d8bf963e 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 5482a04b3ce..787738e6fa3 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v14 3/6] fsmonitor: avoid socket location check if using hook
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-09-28 20:12 ` Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-28 20:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 681d8bf963e..40da2d3b533 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -49,13 +49,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v14 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-09-28 20:12 ` [PATCH v14 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-09-28 20:12 ` Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-28 20:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 14 +++-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 +++++++++-
6 files changed, 167 insertions(+), 3 deletions(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..7a4cb78c7dd 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,11 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ strbuf_init(&state.alias.alias, 0);
+ strbuf_init(&state.alias.points_to, 0);
+ if ((err = fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)))
+ goto done;
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
@@ -1391,6 +1397,8 @@ done:
strbuf_release(&state.path_gitdir_watch);
strbuf_release(&state.path_cookie_prefix);
strbuf_release(&state.path_ipc);
+ strbuf_release(&state.alias.alias);
+ strbuf_release(&state.alias.points_to);
return err;
}
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..daeee4e465c 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -198,8 +199,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
struct string_list cookie_list = STRING_LIST_INIT_DUP;
const char *path_k;
const char *slash;
- int k;
+ char *resolved = NULL;
struct strbuf tmp = STRBUF_INIT;
+ int k;
/*
* Build a list of all filesystem changes into a private/local
@@ -209,7 +211,12 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ free(resolved);
+ resolved = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (resolved)
+ path_k = resolved;
+ else
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +245,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
@@ -360,12 +368,14 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
}
}
+ free(resolved);
fsmonitor_publish(state, batch, &cookie_list);
string_list_clear(&cookie_list, 0);
strbuf_release(&tmp);
return;
force_shutdown:
+ free(resolved);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index 067cbe6990a..fc12fd831ec 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -38,3 +41,92 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR *dir;
+ int retval = -1;
+ const char *const root = "/";
+ struct stat st;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to = STRBUF_INIT;
+
+ dir = opendir(root);
+ if (!dir)
+ return error_errno(_("opendir('%s') failed"), root);
+
+ strbuf_init(&alias, 256);
+
+ while ((de = readdir(dir)) != NULL) {
+ strbuf_reset(&alias);
+ strbuf_addf(&alias, "%s%s", root, de->d_name);
+
+ 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:
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ if (closedir(dir) < 0)
+ return error_errno(_("closedir('%s') failed"), root);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ if (!info->alias.len)
+ return NULL;
+
+ if ((!strncmp(info->alias.buf, path, info->alias.len))
+ && path[info->alias.len] == '/') {
+ struct strbuf tmp = STRBUF_INIT;
+ const char *remainder = path + info->alias.len;
+
+ strbuf_addbuf(&tmp, &info->points_to);
+ strbuf_add(&tmp, remainder, strlen(remainder));
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index e48592887e7..2624798d2c7 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,13 +1,21 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ struct strbuf alias;
+ struct strbuf points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
};
/*
- * Get some basic filesystem informtion for the given path
+ * Get some basic filesystem information for the given path
*
* Returns -1 on error, zero otherwise.
*/
@@ -20,4 +28,30 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by info.alias and
+ * info.points_to and is responsible for releasing it.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v14 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-09-28 20:12 ` [PATCH v14 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-09-28 20:12 ` Eric DeCosta via GitGitGadget
2022-09-28 20:12 ` [PATCH v14 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-28 20:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If fsmonitor is not in a compatible state, warn with an appropriate message.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
fsmonitor-settings.c | 10 +++++++---
fsmonitor-settings.h | 2 +-
fsmonitor.c | 7 +++++++
4 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 40da2d3b533..44233125df8 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -38,7 +38,7 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
strbuf_release(&path);
if (fs.is_remote)
- return FSMONITOR_REASON_REMOTE;
+ return FSMONITOR_REASON_NOSOCKETS;
if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
return FSMONITOR_REASON_NOSOCKETS;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 531a1b6f956..ee63a97dc51 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
+#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
#include "fsmonitor-path-utils.h"
@@ -242,10 +243,11 @@ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
return r->settings.fsmonitor->reason;
}
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason)
{
struct strbuf msg = STRBUF_INIT;
+ const char *socket_dir;
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
@@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
goto done;
case FSMONITOR_REASON_NOSOCKETS:
+ socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
strbuf_addf(&msg,
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
+ _("socket directory '%s' is incompatible with fsmonitor due"
+ " to lack of Unix sockets support"),
+ socket_dir);
goto done;
}
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index 0721617b95a..ab02e3995ee 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
const char *fsm_settings__get_hook_path(struct repository *r);
enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason);
struct fsmonitor_settings;
diff --git a/fsmonitor.c b/fsmonitor.c
index 57d6a483bee..540736b39fd 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -295,6 +295,7 @@ static int fsmonitor_force_update_threshold = 100;
void refresh_fsmonitor(struct index_state *istate)
{
+ static int warn_once = 0;
struct strbuf query_result = STRBUF_INIT;
int query_success = 0, hook_version = -1;
size_t bol = 0; /* beginning of line */
@@ -305,6 +306,12 @@ void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (!warn_once && reason > FSMONITOR_REASON_OK) {
+ warn_once = 1;
+ warning("%s", fsm_settings__get_incompatible_msg(r, reason));
+ }
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v14 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-09-28 20:12 ` [PATCH v14 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-09-28 20:12 ` Eric DeCosta via GitGitGadget
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-09-28 20:12 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited
filesystem support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/config.txt | 2 ++
Documentation/config/fsmonitor--daemon.txt | 11 +++++++
Documentation/git-fsmonitor--daemon.txt | 37 ++++++++++++++++++++--
3 files changed, 47 insertions(+), 3 deletions(-)
create mode 100644 Documentation/config/fsmonitor--daemon.txt
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5b5b9765699..1e205831656 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -423,6 +423,8 @@ include::config/filter.txt[]
include::config/fsck.txt[]
+include::config/fsmonitor--daemon.txt[]
+
include::config/gc.txt[]
include::config/gitcvs.txt[]
diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.txt
new file mode 100644
index 00000000000..c225c6c9e74
--- /dev/null
+++ b/Documentation/config/fsmonitor--daemon.txt
@@ -0,0 +1,11 @@
+fsmonitor.allowRemote::
+ By default, the fsmonitor daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides this
+ behavior. Only respected when `core.fsmonitor` is set to `true`.
+
+fsmonitor.socketDir::
+ This Mac OS-specific option, if set, specifies the directory in
+ which to create the Unix domain socket used for communication
+ between the fsmonitor daemon and various Git commands. The directory must
+ reside on a native Mac OS filesystem. Only respected when `core.fsmonitor`
+ is set to `true`.
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..8238eadb0e1 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
NAME
----
-git-fsmonitor--daemon - A Built-in File System Monitor
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
SYNOPSIS
--------
@@ -17,7 +17,7 @@ DESCRIPTION
-----------
A daemon to watch the working directory for file and directory
-changes using platform-specific file system notification facilities.
+changes using platform-specific filesystem notification facilities.
This daemon communicates directly with commands like `git status`
using the link:technical/api-simple-ipc.html[simple IPC] interface
@@ -63,13 +63,44 @@ CAVEATS
-------
The fsmonitor daemon does not currently know about submodules and does
-not know to filter out file system events that happen within a
+not know to filter out filesystem events that happen within a
submodule. If fsmonitor daemon is watching a super repo and a file is
modified within the working directory of a submodule, it will report
the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory, however, if the
+`.git` directory is on a network-mounted filesystem, it will be instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fsmonitor--daemon.txt[]
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-09-28 20:12 ` [PATCH v14 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-09-28 20:12 ` [PATCH v14 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-10-04 17:32 ` Eric DeCosta via GitGitGadget
2022-10-04 17:32 ` [PATCH v15 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
` (6 more replies)
6 siblings, 7 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-10-04 17:32 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
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.
v15 differs from v14:
* fix memory leak
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 | 135 ++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 145 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 77 +++------
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 | 60 +++++++
fsmonitor-settings.c | 68 +++++++-
fsmonitor-settings.h | 4 +-
fsmonitor.c | 7 +
20 files changed, 588 insertions(+), 249 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: 3dcec76d9df911ed8321007b1d197c1a206dc164
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1326%2Fedecosta-mw%2Ffsmonitor_macos-v15
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1326/edecosta-mw/fsmonitor_macos-v15
Pull-Request: https://github.com/gitgitgadget/git/pull/1326
Range-diff vs v14:
1: 0b9b64428c5 ! 1: ec49a74086d fsmonitor: refactor filesystem checks to common interface
@@ compat/fsmonitor/fsm-path-utils-darwin.c (new)
+ else
+ fs_info->is_remote = 0;
+
-+ fs_info->typename = fs.f_fstypename;
++ fs_info->typename = xstrdup(fs.f_fstypename);
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
@@ compat/fsmonitor/fsm-path-utils-darwin.c (new)
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
++
++ free(fs.typename);
++
+ return fs.is_remote;
+}
@@ compat/fsmonitor/fsm-settings-darwin.c
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
-+ strbuf_release(&path);
-
+-
- if (!(fs.f_flags & MNT_LOCAL))
-+ if (fs.is_remote)
- return FSMONITOR_REASON_REMOTE;
+- return FSMONITOR_REASON_REMOTE;
++ strbuf_release(&path);
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
-+ if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
- return FSMONITOR_REASON_NOSOCKETS;
-
+- return FSMONITOR_REASON_NOSOCKETS;
+-
- if (!strcmp(fs.f_fstypename, "ntfs"))
-+ if (!strcmp(fs.typename, "ntfs"))
++ if (fs.is_remote ||
++ !strcmp(fs.typename, "msdos") ||
++ !strcmp(fs.typename, "ntfs")) {
++ free(fs.typename);
return FSMONITOR_REASON_NOSOCKETS;
++ }
++ free(fs.typename);
return FSMONITOR_REASON_OK;
+ }
+
@@ compat/fsmonitor/fsm-settings-darwin.c: enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ fsmonitor-path-utils.h (new)
+/*
+ * Get some basic filesystem informtion for the given path
+ *
++ * The caller owns the storage that is occupied by fs_info and
++ * is responsible for releasing it.
++ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
2: 680d4c83f99 = 2: 7bf1cdfe3b2 fsmonitor: relocate socket file if .git directory is remote
3: 7987d0c1f33 = 3: c5e8b6cfe5d fsmonitor: avoid socket location check if using hook
4: 241043b7c15 ! 4: 863063aefee fsmonitor: deal with synthetic firmlinks on macOS
@@ compat/fsmonitor/fsm-path-utils-darwin.c
#include <sys/mount.h>
@@ compat/fsmonitor/fsm-path-utils-darwin.c: int fsmonitor__is_fs_remote(const char *path)
- return -1;
+
return fs.is_remote;
}
+
@@ fsmonitor-path-utils.h
- * Get some basic filesystem informtion for the given path
+ * Get some basic filesystem information for the given path
*
- * Returns -1 on error, zero otherwise.
- */
+ * The caller owns the storage that is occupied by fs_info and
+ * is responsible for releasing it.
@@ fsmonitor-path-utils.h: int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
5: d906debba5e ! 5: fa974bfd5ef fsmonitor: check for compatability before communicating with fsmonitor
@@ Commit message
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
- ## compat/fsmonitor/fsm-settings-darwin.c ##
-@@ compat/fsmonitor/fsm-settings-darwin.c: static enum fsmonitor_reason check_uds_volume(struct repository *r)
- strbuf_release(&path);
-
- if (fs.is_remote)
-- return FSMONITOR_REASON_REMOTE;
-+ return FSMONITOR_REASON_NOSOCKETS;
-
- if (!strcmp(fs.typename, "msdos")) /* aka FAT32 */
- return FSMONITOR_REASON_NOSOCKETS;
-
## fsmonitor-settings.c ##
@@
#include "cache.h"
6: ed14fbd009e = 6: af7309745f7 fsmonitor: add documentation for allowRemote and socketDir options
--
gitgitgadget
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v15 1/6] fsmonitor: refactor filesystem checks to common interface
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
@ 2022-10-04 17:32 ` Eric DeCosta via GitGitGadget
2023-01-30 9:37 ` Ævar Arnfjörð Bjarmason
2022-10-04 17:32 ` [PATCH v15 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
` (5 subsequent siblings)
6 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-10-04 17:32 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Provide a common interface for getting basic filesystem information
including filesystem type and whether the filesystem is remote.
Refactor existing code for getting basic filesystem info and detecting
remote file systems to the new interface.
Refactor filesystem checks to leverage new interface. For macOS,
error-out if the Unix Domain socket (UDS) file is on a remote
filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
compat/fsmonitor/fsm-path-utils-darwin.c | 43 ++++++
compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
compat/fsmonitor/fsm-settings-darwin.c | 69 +++------
compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-path-utils.h | 26 ++++
fsmonitor-settings.c | 50 +++++++
8 files changed, 272 insertions(+), 219 deletions(-)
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
diff --git a/Makefile b/Makefile
index cac3452edb9..ffab427ea5b 100644
--- a/Makefile
+++ b/Makefile
@@ -2044,6 +2044,7 @@ endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 00000000000..d46d7f13538
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,43 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = xstrdup(fs.f_fstypename);
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+
+ free(fs.typename);
+
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 00000000000..a90b8f7925b
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,128 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f31..699f0b272e6 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,42 +16,35 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path();
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
-
- if (!(fs.f_flags & MNT_LOCAL))
- return FSMONITOR_REASON_REMOTE;
+ strbuf_release(&path);
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
- return FSMONITOR_REASON_NOSOCKETS;
-
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (fs.is_remote ||
+ !strcmp(fs.typename, "msdos") ||
+ !strcmp(fs.typename, "ntfs")) {
+ free(fs.typename);
return FSMONITOR_REASON_NOSOCKETS;
+ }
+ free(fs.typename);
return FSMONITOR_REASON_OK;
}
@@ -81,7 +52,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
+ reason = check_uds_volume(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f7..d88b06ae610 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index ea2a531be87..5482a04b3ce 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 00000000000..41edf5b934f
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,26 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem informtion for the given path
+ *
+ * The caller owns the storage that is occupied by fs_info and
+ * is responsible for releasing it.
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e92..d288cbad479 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,6 +14,52 @@ struct fsmonitor_settings {
char *hook_path;
};
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
if (!r->worktree) {
@@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
reason = fsm_os__incompatible(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v15 1/6] fsmonitor: refactor filesystem checks to common interface
2022-10-04 17:32 ` [PATCH v15 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2023-01-30 9:37 ` Ævar Arnfjörð Bjarmason
0 siblings, 0 replies; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2023-01-30 9:37 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Tue, Oct 04 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
>
> Provide a common interface for getting basic filesystem information
> including filesystem type and whether the filesystem is remote.
>
> Refactor existing code for getting basic filesystem info and detecting
> remote file systems to the new interface.
>
> Refactor filesystem checks to leverage new interface. For macOS,
> error-out if the Unix Domain socket (UDS) file is on a remote
> filesystem.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> Makefile | 1 +
> compat/fsmonitor/fsm-path-utils-darwin.c | 43 ++++++
> compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++
> compat/fsmonitor/fsm-settings-darwin.c | 69 +++------
> compat/fsmonitor/fsm-settings-win32.c | 172 +----------------------
> contrib/buildsystems/CMakeLists.txt | 2 +
> fsmonitor-path-utils.h | 26 ++++
> fsmonitor-settings.c | 50 +++++++
> 8 files changed, 272 insertions(+), 219 deletions(-)
> 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
>
> diff --git a/Makefile b/Makefile
> index cac3452edb9..ffab427ea5b 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -2044,6 +2044,7 @@ endif
> ifdef FSMONITOR_OS_SETTINGS
> COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
> COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
> + COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
> endif
>
> ifeq ($(TCLTK_PATH),)
> diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
> new file mode 100644
> index 00000000000..d46d7f13538
> --- /dev/null
> +++ b/compat/fsmonitor/fsm-path-utils-darwin.c
> @@ -0,0 +1,43 @@
> +#include "fsmonitor.h"
> +#include "fsmonitor-path-utils.h"
> +#include <sys/param.h>
> +#include <sys/mount.h>
> +
> +int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
> +{
> + struct statfs fs;
Should have a \n here after variable decls.
> + if (statfs(path, &fs) == -1) {
> + int saved_errno = errno;
> + trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
> + path, strerror(saved_errno));
> + errno = saved_errno;
> + return -1;
> + }
> +
> + trace_printf_key(&trace_fsmonitor,
> + "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
> + path, fs.f_type, fs.f_flags, fs.f_fstypename);
> +
> + if (!(fs.f_flags & MNT_LOCAL))
> + fs_info->is_remote = 1;
> + else
> + fs_info->is_remote = 0;
Instead:
fs_info->is_remote = !(fs.f_flags & MNT_LOCAL)
?
> +int fsmonitor__is_fs_remote(const char *path)
> +{
> + struct fs_info fs;
Same style issue as above.
> + if (fsmonitor__get_fs_info(path, &fs))
> + return -1;
> +
> + free(fs.typename);
Can we get a "free_fs_info()" function or something instead, this is one
of N codepaths where we now peek into that struct. If we ever add
another field that needs malloc'ing altering all callers will be
painful.
> + if (xutftowcs_path(wpath, path) < 0) {
> + return -1;
> + }
Maybe drop the braces here as this code is being modified-while-moved
anyway?
> +
> + /*
> + * GetDriveTypeW() requires a final slash. We assume that the
> + * worktree pathname points to an actual directory.
> + */
> + wlen = wcslen(wpath);
> + if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
> + wpath[wlen++] = L'\\';
> + wpath[wlen] = 0;
> + }
> +
> + /*
> + * Normalize the path. If nothing else, this converts forward
> + * slashes to backslashes. This is essential to get GetDriveTypeW()
> + * correctly handle some UNC "\\server\share\..." paths.
> + */
> + if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
> + return -1;
> + }
Here you have added needless braces while moving this, let's not do
that.
> +
> + driveType = GetDriveTypeW(wfullpath);
> + trace_printf_key(&trace_fsmonitor,
> + "DriveType '%s' L'%ls' (%u)",
> + path, wfullpath, driveType);
> +
> + if (driveType == DRIVE_REMOTE) {
> + fs_info->is_remote = 1;
> + if (check_remote_protocol(wfullpath) < 0)
> + return -1;
Maybe this code should be more careful not to modify the passed-in
struct if we're returning an error?
I.e. do this "return -1" before assigning "is_remote = 1"?
> + } else {
> + fs_info->is_remote = 0;
> + }
Maybe just at the start: "struct fs_info = { 0 }" and skip this "else" ?
> +
> + trace_printf_key(&trace_fsmonitor,
> + "'%s' is_remote: %d",
> + path, fs_info->is_remote);
> +
> + return 0;
> +}
> +
> +int fsmonitor__is_fs_remote(const char *path)
> +{
> + struct fs_info fs;
> + if (fsmonitor__get_fs_info(path, &fs))
> + return -1;
> + return fs.is_remote;
I find this and the resulting "switch/case" caller rather un-idiomatic,
i.e. you end up checking 1/0/default.
Why not in your check_remote() instead:
int is_remote;
if (fsmonitor__check_fs_remote(r->worktree, &is_remote))
return FSMONITOR_REASON_ERROR;
else if (!is_remote)
return FSMONITOR_REASON_OK;
...
Where the "..." is the "repo_config_get_bool()" etc. code I suggest
below.
I.e. having an "is" function return non-boolean is somewhat confusing,
better to write to a variable (which the config API you're using does).
> +#ifdef HAVE_FSMONITOR_OS_SETTINGS
> +static enum fsmonitor_reason check_remote(struct repository *r)
> +{
> + int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
Let's not init this to -1, and instead...
> + int is_remote = fsmonitor__is_fs_remote(r->worktree);
> +
> + switch (is_remote) {
> + case 0:
The usual coding style is to not indent the "case" further than the
"switch".
> + return FSMONITOR_REASON_OK;
> + case 1:
> + repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
> + if (allow_remote < 1)
...continued from above: We can scope this variable to this case
statement, as "case 1: { int v; ... }", but furthermore you don't need
to init it to -1 and check this -1 case if you just check the return
value of repo_config_get_bool(), which IMO is also more obvious:
int v;
if (!repo...(..., &v))
return v ? FSMONITOR_REASON_OK : FSMONITOR_REASON_REMOTE:
else
return FSMONITOR_REASON_REMOTE;
I.e. you clearly separate the cases where it's un-init'd by checking the
return value.
Maybe better (but would result in more churn later if you ever want to
change the default):
int v;
return !repo...(..., &v) && v ? FSMONITOR_REASON_OK :
FSMONITOR_REASON_REMOTE:
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v15 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-10-04 17:32 ` [PATCH v15 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
@ 2022-10-04 17:32 ` Eric DeCosta via GitGitGadget
2023-01-30 9:58 ` Ævar Arnfjörð Bjarmason
2022-10-04 17:32 ` [PATCH v15 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
` (4 subsequent siblings)
6 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-10-04 17:32 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If the .git directory is on a remote filesystem, create the socket
file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Makefile | 1 +
builtin/fsmonitor--daemon.c | 3 +-
compat/fsmonitor/fsm-ipc-darwin.c | 52 ++++++++++++++++++++++++++
compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
compat/fsmonitor/fsm-settings-darwin.c | 2 +-
contrib/buildsystems/CMakeLists.txt | 2 +
fsmonitor-ipc.c | 18 ++++-----
fsmonitor-ipc.h | 4 +-
8 files changed, 78 insertions(+), 13 deletions(-)
create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
diff --git a/Makefile b/Makefile
index ffab427ea5b..feb675a6959 100644
--- a/Makefile
+++ b/Makefile
@@ -2039,6 +2039,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b37..0123fc33ed2 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 00000000000..ce843d63348
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,52 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path = NULL;
+ SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+
+ if (!r)
+ BUG("No repository passed into fsmonitor_ipc__get_path");
+
+ if (ipc_path)
+ return ipc_path;
+
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(r->gitdir) < 1) {
+ ipc_path = fsmonitor_ipc__get_default_path();
+ return ipc_path;
+ }
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
+ free(sock_dir);
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 00000000000..e08c505c148
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 699f0b272e6..7241c4c22c9 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -26,7 +26,7 @@
static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
struct fs_info fs;
- const char *ipc_path = fsmonitor_ipc__get_path();
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
struct strbuf path = STRBUF_INIT;
strbuf_add(&path, ipc_path, strlen(ipc_path));
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 5482a04b3ce..787738e6fa3 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
@@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397baa..c0f42301c84 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3af..8b489da762b 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v15 2/6] fsmonitor: relocate socket file if .git directory is remote
2022-10-04 17:32 ` [PATCH v15 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2023-01-30 9:58 ` Ævar Arnfjörð Bjarmason
0 siblings, 0 replies; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2023-01-30 9:58 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Tue, Oct 04 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
>
> If the .git directory is on a remote filesystem, create the socket
> file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME.
>
> Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
> ---
> Makefile | 1 +
> builtin/fsmonitor--daemon.c | 3 +-
> compat/fsmonitor/fsm-ipc-darwin.c | 52 ++++++++++++++++++++++++++
> compat/fsmonitor/fsm-ipc-win32.c | 9 +++++
> compat/fsmonitor/fsm-settings-darwin.c | 2 +-
> contrib/buildsystems/CMakeLists.txt | 2 +
> fsmonitor-ipc.c | 18 ++++-----
> fsmonitor-ipc.h | 4 +-
> 8 files changed, 78 insertions(+), 13 deletions(-)
> create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
> create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
>
> diff --git a/Makefile b/Makefile
> index ffab427ea5b..feb675a6959 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -2039,6 +2039,7 @@ ifdef FSMONITOR_DAEMON_BACKEND
> COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
> COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
> COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
> + COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
> endif
>
> ifdef FSMONITOR_OS_SETTINGS
> diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
> index 2c109cf8b37..0123fc33ed2 100644
> --- a/builtin/fsmonitor--daemon.c
> +++ b/builtin/fsmonitor--daemon.c
> @@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void)
> * directory.)
> */
> strbuf_init(&state.path_ipc, 0);
> - strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
> + strbuf_addstr(&state.path_ipc,
> + absolute_path(fsmonitor_ipc__get_path(the_repository)));
>
> /*
> * Confirm that we can create platform-specific resources for the
> diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
> new file mode 100644
> index 00000000000..ce843d63348
> --- /dev/null
> +++ b/compat/fsmonitor/fsm-ipc-darwin.c
> @@ -0,0 +1,52 @@
> +#include "cache.h"
> +#include "config.h"
> +#include "strbuf.h"
> +#include "fsmonitor.h"
> +#include "fsmonitor-ipc.h"
> +#include "fsmonitor-path-utils.h"
> +
> +static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
> +
> +const char *fsmonitor_ipc__get_path(struct repository *r)
> +{
> + static const char *ipc_path = NULL;
> + SHA_CTX sha1ctx;
> + char *sock_dir = NULL;
...don't init this to NULL...
> + struct strbuf ipc_file = STRBUF_INIT;
> + unsigned char hash[SHA_DIGEST_LENGTH];
> +
> + if (!r)
> + BUG("No repository passed into fsmonitor_ipc__get_path");
> +
> + if (ipc_path)
> + return ipc_path;
> +
> +
> + /* By default the socket file is created in the .git directory */
> + if (fsmonitor__is_fs_remote(r->gitdir) < 1) {
> + ipc_path = fsmonitor_ipc__get_default_path();
> + return ipc_path;
> + }
> +
> + SHA1_Init(&sha1ctx);
> + SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
> + SHA1_Final(hash, &sha1ctx);
> +
> + repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
...instead check the return value here. So:
if (!repo_config_get_string(..., &sock_dir))
...
> + /* Create the socket file in either socketDir or $HOME */
> + if (sock_dir && *sock_dir) {
> + strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
> + sock_dir, hash_to_hex(hash));
^ Add the body of this branch to the "..." above.
> + } else {
> + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
...and keep this in the "else".
> + }
> + free(sock_dir);
You'd then add this free() to the first branch, but better yet in this
case avoid this allocation, use "const char *" and use
repo_config_get_string_tmp(). It's made for exactly this sort of use-case.
> +
> + ipc_path = interpolate_path(ipc_file.buf, 1);
> + if (!ipc_path)
> + die(_("Invalid path: %s"), ipc_file.buf);
> +
> + strbuf_release(&ipc_file);
> + return ipc_path;
> +}
> diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
> new file mode 100644
> index 00000000000..e08c505c148
> --- /dev/null
> +++ b/compat/fsmonitor/fsm-ipc-win32.c
> @@ -0,0 +1,9 @@
> +#include "config.h"
> +#include "fsmonitor-ipc.h"
> +
> +const char *fsmonitor_ipc__get_path(struct repository *r) {
> + static char *ret;
Missing \n here.
> try_again:
> - state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
> - &connection);
> + state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
> + &options, &connection);
This post-image is mis-indented.
> #include "simple-ipc.h"
>
> +struct repository;
> +
I think we'd usually forard-declare such things, if needed...
> /*
> * Returns true if built-in file system monitor daemon is defined
> * for this platform.
> @@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
> *
> * Returns NULL if the daemon is not supported on this platform.
> */
> -const char *fsmonitor_ipc__get_path(void);
..right before they're needed, so before this line?
> +const char *fsmonitor_ipc__get_path(struct repository *r);
>
> /*
> * Try to determine whether there is a `git-fsmonitor--daemon` process
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v15 3/6] fsmonitor: avoid socket location check if using hook
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
2022-10-04 17:32 ` [PATCH v15 1/6] fsmonitor: refactor filesystem checks to common interface Eric DeCosta via GitGitGadget
2022-10-04 17:32 ` [PATCH v15 2/6] fsmonitor: relocate socket file if .git directory is remote Eric DeCosta via GitGitGadget
@ 2022-10-04 17:32 ` Eric DeCosta via GitGitGadget
2022-10-04 17:32 ` [PATCH v15 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
` (3 subsequent siblings)
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-10-04 17:32 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If monitoring is done via fsmonitor hook rather than IPC there is no
need to check if the location of the Unix Domain socket (UDS) file is
on a remote filesystem.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++----
compat/fsmonitor/fsm-settings-win32.c | 2 +-
fsmonitor-settings.c | 8 ++++----
fsmonitor-settings.h | 2 +-
4 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index 7241c4c22c9..6abbc7af3ab 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -48,13 +48,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_uds_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index d88b06ae610..a8af31b71de 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index d288cbad479..531a1b6f956 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r)
}
#endif
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
reason = check_remote(r);
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = fsm_os__incompatible(r);
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197f..0721617b95a 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v15 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (2 preceding siblings ...)
2022-10-04 17:32 ` [PATCH v15 3/6] fsmonitor: avoid socket location check if using hook Eric DeCosta via GitGitGadget
@ 2022-10-04 17:32 ` Eric DeCosta via GitGitGadget
2023-01-30 10:08 ` Ævar Arnfjörð Bjarmason
2022-10-04 17:32 ` [PATCH v15 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
` (2 subsequent siblings)
6 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-10-04 17:32 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Starting with macOS 10.15 (Catalina), Apple introduced a new feature
called 'firmlinks' in order to separate the boot volume into two
volumes, one read-only and one writable but still present them to the
user as a single volume. Along with this change, Apple removed the
ability to create symlinks in the root directory and replaced them with
'synthetic firmlinks'. See 'man synthetic.conf'
When FSEevents reports the path of changed files, if the path involves
a synthetic firmlink, the path is reported from the point of the
synthetic firmlink and not the real path. For example:
Real path:
/System/Volumes/Data/network/working/directory/foo.txt
Synthetic firmlink:
/network -> /System/Volumes/Data/network
FSEvents path:
/network/working/directory/foo.txt
This causes the FSEvents path to not match against the worktree
directory.
There are several ways in which synthetic firmlinks can be created:
they can be defined in /etc/synthetic.conf, the automounter can create
them, and there may be other means. Simply reading /etc/synthetic.conf
is insufficient. No matter what process creates synthetic firmlinks,
they all get created in the root directory.
Therefore, in order to deal with synthetic firmlinks, the root directory
is scanned and the first possible synthetic firmink that, when resolved,
is a prefix of the worktree is used to map FSEvents paths to worktree
paths.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
builtin/fsmonitor--daemon.c | 8 +++
compat/fsmonitor/fsm-listen-darwin.c | 14 +++-
compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++
compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++
fsmonitor--daemon.h | 3 +
fsmonitor-path-utils.h | 36 +++++++++-
6 files changed, 167 insertions(+), 3 deletions(-)
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0123fc33ed2..7a4cb78c7dd 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -1282,6 +1283,11 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ strbuf_init(&state.alias.alias, 0);
+ strbuf_init(&state.alias.points_to, 0);
+ if ((err = fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)))
+ goto done;
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
@@ -1391,6 +1397,8 @@ done:
strbuf_release(&state.path_gitdir_watch);
strbuf_release(&state.path_cookie_prefix);
strbuf_release(&state.path_ipc);
+ strbuf_release(&state.alias.alias);
+ strbuf_release(&state.alias.points_to);
return err;
}
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289e..daeee4e465c 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -198,8 +199,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
struct string_list cookie_list = STRING_LIST_INIT_DUP;
const char *path_k;
const char *slash;
- int k;
+ char *resolved = NULL;
struct strbuf tmp = STRBUF_INIT;
+ int k;
/*
* Build a list of all filesystem changes into a private/local
@@ -209,7 +211,12 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ free(resolved);
+ resolved = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (resolved)
+ path_k = resolved;
+ else
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +245,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
@@ -360,12 +368,14 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
}
}
+ free(resolved);
fsmonitor_publish(state, batch, &cookie_list);
string_list_clear(&cookie_list, 0);
strbuf_release(&tmp);
return;
force_shutdown:
+ free(resolved);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
index d46d7f13538..ce5a8febe09 100644
--- a/compat/fsmonitor/fsm-path-utils-darwin.c
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -1,5 +1,8 @@
#include "fsmonitor.h"
#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
@@ -41,3 +44,92 @@ int fsmonitor__is_fs_remote(const char *path)
return fs.is_remote;
}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR *dir;
+ int retval = -1;
+ const char *const root = "/";
+ struct stat st;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to = STRBUF_INIT;
+
+ dir = opendir(root);
+ if (!dir)
+ return error_errno(_("opendir('%s') failed"), root);
+
+ strbuf_init(&alias, 256);
+
+ while ((de = readdir(dir)) != NULL) {
+ strbuf_reset(&alias);
+ strbuf_addf(&alias, "%s%s", root, de->d_name);
+
+ 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:
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ if (closedir(dir) < 0)
+ return error_errno(_("closedir('%s') failed"), root);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ if (!info->alias.len)
+ return NULL;
+
+ if ((!strncmp(info->alias.buf, path, info->alias.len))
+ && path[info->alias.len] == '/') {
+ struct strbuf tmp = STRBUF_INIT;
+ const char *remainder = path + info->alias.len;
+
+ strbuf_addbuf(&tmp, &info->points_to);
+ strbuf_add(&tmp, remainder, strlen(remainder));
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
index a90b8f7925b..0d95bbb416f 100644
--- a/compat/fsmonitor/fsm-path-utils-win32.c
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path)
return -1;
return fs.is_remote;
}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff5..e24838f9a86 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
index 41edf5b934f..5bfdfb81c14 100644
--- a/fsmonitor-path-utils.h
+++ b/fsmonitor-path-utils.h
@@ -1,13 +1,21 @@
#ifndef FSM_PATH_UTILS_H
#define FSM_PATH_UTILS_H
+#include "strbuf.h"
+
+struct alias_info
+{
+ struct strbuf alias;
+ struct strbuf points_to;
+};
+
struct fs_info {
int is_remote;
char *typename;
};
/*
- * Get some basic filesystem informtion for the given path
+ * Get some basic filesystem information for the given path
*
* The caller owns the storage that is occupied by fs_info and
* is responsible for releasing it.
@@ -23,4 +31,30 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
*/
int fsmonitor__is_fs_remote(const char *path);
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by info.alias and
+ * info.points_to and is responsible for releasing it.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
#endif
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v15 4/6] fsmonitor: deal with synthetic firmlinks on macOS
2022-10-04 17:32 ` [PATCH v15 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2023-01-30 10:08 ` Ævar Arnfjörð Bjarmason
0 siblings, 0 replies; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2023-01-30 10:08 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Tue, Oct 04 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
> + struct strbuf alias;
Rather than init-ing here...
> + struct strbuf points_to = STRBUF_INIT;
> +
> + dir = opendir(root);
> + if (!dir)
> + return error_errno(_("opendir('%s') failed"), root);
> +
> + strbuf_init(&alias, 256);
...we pre-grow here...
> + while ((de = readdir(dir)) != NULL) {
...but as shown here, we may not even use this at all, but even then is
this micro-optimization worth it? If it is a reader would be helped with
an explanation of what the 256 is, is this meant to be some OSX-specific
PATH_MAX, but hardcoded?
> + strbuf_reset(&alias);
> + strbuf_addf(&alias, "%s%s", root, de->d_name);
> +
> + 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;
> + }
> +
Maybe this code would be simpler if you split it into a trivial static
function, so you could pass in the "alias" and "points_to", and just do
"return error...(...)" here and in the other places.
> + 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);
Earlier you use strbuf_addf() for a "append two strings", maybe we could
save ourselves a line and do the same here...
> + trace_printf_key(&trace_fsmonitor,
> + "Found alias for '%s' : '%s' -> '%s'",
> + path, info->alias.buf, info->points_to.buf);
...except we're only doing this to emit this, and then we'll free() it?
Can't we just use %s%s here instead of %s, and e.g. pass
"info->alias.buf, alias" instead of the now-appende-to
"info->alias.buf"?
> +char *fsmonitor__resolve_alias(const char *path,
> + const struct alias_info *info)
I commented on this in a few other places, and I'll stop noting these
now, but you're mis-indenting function decls consistently, also in a *.h
change later in this commit.
Please look through those for this series.
> +{
> + if (!info->alias.len)
> + return NULL;
Maybe "check if we have a zero-length string" should belong in the
caller, as "resolve it as an alias" for "\0" is nonsense?
> +
> + if ((!strncmp(info->alias.buf, path, info->alias.len))
> + && path[info->alias.len] == '/') {
> + struct strbuf tmp = STRBUF_INIT;
> + const char *remainder = path + info->alias.len;
> +
> + strbuf_addbuf(&tmp, &info->points_to);
> + strbuf_add(&tmp, remainder, strlen(remainder));
There's no point in strbuf_add() if you have to dynamically use strlen()
over just using strbuf_addstr() (which inline resolves to the same),
let's just use that.
Or just a single strbuf_addf()...
> + return strbuf_detach(&tmp, NULL);
...Or actually, these last 3 lines can be replaced by a mere:
return xstrfmt("%s%s", info->points_to.buf, remainder);
Please just use that. It's not exactly the same due to the pre-sizing
with "addbuf", but again (I commented on a similar case in an earlier
commit), is such micro-optimization worth it here over brevity?
> +/*
> + * No-op for now.
> + */
Please just drop this comment, it doesn't add any information. It would
be useful to say why we're seemingly faking "no aliase on win32", or to
say that it does have them, but implementing them is a "TODO".
But we can see it's a "no-op for now" from the code....
> +int fsmonitor__get_alias(const char *path, struct alias_info *info)
> +{
> + return 0;
> +}
> +
> +/*
> + * No-op for now.
> + */
...ditto.
> +/*
> + * Get the alias in given path, if any.
> + *
> + * Sets alias to the first alias that matches any part of the path.
> + *
> + * If an alias is found, info.alias and info.points_to are set to the
> + * found mapping.
> + *
> + * Returns -1 on error, 0 otherwise.
> + *
> + * The caller owns the storage that is occupied by info.alias and
> + * info.points_to and is responsible for releasing it.
> + */
> +int fsmonitor__get_alias(const char *path, struct alias_info *info);
I have not looked carefully at this interface, but instead of all of
this explanation & the caller needing to carefully reason about what
parts of this struct it can and can't peek into couldn't we just make it
take two "char **" arguments, one for "alias" and another for
"points_to".
It would then be obvious what the semantics are, and who owns the
memory.
But maybe retaining the strbuf-ness is important (but even then, we
could pass a "struct strbuf *" to populate.
> +
> +/*
> + * Resolve the path against the given alias.
> + *
> + * Returns the resolved path if there is one, NULL otherwise.
> + *
> + * The caller owns the storage that the returned string occupies and
> + * is responsible for releasing it.
> + */
> +char *fsmonitor__resolve_alias(const char *path,
> + const struct alias_info *info);
> +
Here we don't say anything about the ownership & freeing of "info", does
the same apply? But the API design comment above also applies.
^ permalink raw reply [flat|nested] 170+ messages in thread
* [PATCH v15 5/6] fsmonitor: check for compatability before communicating with fsmonitor
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (3 preceding siblings ...)
2022-10-04 17:32 ` [PATCH v15 4/6] fsmonitor: deal with synthetic firmlinks on macOS Eric DeCosta via GitGitGadget
@ 2022-10-04 17:32 ` Eric DeCosta via GitGitGadget
2022-10-04 17:32 ` [PATCH v15 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
2022-10-05 18:05 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Junio C Hamano
6 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-10-04 17:32 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
If fsmonitor is not in a compatible state, warn with an appropriate message.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
fsmonitor-settings.c | 10 +++++++---
fsmonitor-settings.h | 2 +-
fsmonitor.c | 7 +++++++
3 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 531a1b6f956..ee63a97dc51 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
+#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
#include "fsmonitor-path-utils.h"
@@ -242,10 +243,11 @@ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
return r->settings.fsmonitor->reason;
}
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason)
{
struct strbuf msg = STRBUF_INIT;
+ const char *socket_dir;
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
@@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
goto done;
case FSMONITOR_REASON_NOSOCKETS:
+ socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
strbuf_addf(&msg,
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
+ _("socket directory '%s' is incompatible with fsmonitor due"
+ " to lack of Unix sockets support"),
+ socket_dir);
goto done;
}
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index 0721617b95a..ab02e3995ee 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
const char *fsm_settings__get_hook_path(struct repository *r);
enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason);
struct fsmonitor_settings;
diff --git a/fsmonitor.c b/fsmonitor.c
index 57d6a483bee..540736b39fd 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -295,6 +295,7 @@ static int fsmonitor_force_update_threshold = 100;
void refresh_fsmonitor(struct index_state *istate)
{
+ static int warn_once = 0;
struct strbuf query_result = STRBUF_INIT;
int query_success = 0, hook_version = -1;
size_t bol = 0; /* beginning of line */
@@ -305,6 +306,12 @@ void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (!warn_once && reason > FSMONITOR_REASON_OK) {
+ warn_once = 1;
+ warning("%s", fsm_settings__get_incompatible_msg(r, reason));
+ }
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* [PATCH v15 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (4 preceding siblings ...)
2022-10-04 17:32 ` [PATCH v15 5/6] fsmonitor: check for compatability before communicating with fsmonitor Eric DeCosta via GitGitGadget
@ 2022-10-04 17:32 ` Eric DeCosta via GitGitGadget
2023-01-30 10:04 ` Ævar Arnfjörð Bjarmason
2022-10-05 18:05 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Junio C Hamano
6 siblings, 1 reply; 170+ messages in thread
From: Eric DeCosta via GitGitGadget @ 2022-10-04 17:32 UTC (permalink / raw)
To: git
Cc: Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta, Eric DeCosta
From: Eric DeCosta <edecosta@mathworks.com>
Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'.
Call-out experimental nature of 'fsmonitor.allowRemote' and limited
filesystem support for 'fsmonitor.socketDir'.
Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
Documentation/config.txt | 2 ++
Documentation/config/fsmonitor--daemon.txt | 11 +++++++
Documentation/git-fsmonitor--daemon.txt | 37 ++++++++++++++++++++--
3 files changed, 47 insertions(+), 3 deletions(-)
create mode 100644 Documentation/config/fsmonitor--daemon.txt
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5b5b9765699..1e205831656 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -423,6 +423,8 @@ include::config/filter.txt[]
include::config/fsck.txt[]
+include::config/fsmonitor--daemon.txt[]
+
include::config/gc.txt[]
include::config/gitcvs.txt[]
diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.txt
new file mode 100644
index 00000000000..c225c6c9e74
--- /dev/null
+++ b/Documentation/config/fsmonitor--daemon.txt
@@ -0,0 +1,11 @@
+fsmonitor.allowRemote::
+ By default, the fsmonitor daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides this
+ behavior. Only respected when `core.fsmonitor` is set to `true`.
+
+fsmonitor.socketDir::
+ This Mac OS-specific option, if set, specifies the directory in
+ which to create the Unix domain socket used for communication
+ between the fsmonitor daemon and various Git commands. The directory must
+ reside on a native Mac OS filesystem. Only respected when `core.fsmonitor`
+ is set to `true`.
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb8612..8238eadb0e1 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
NAME
----
-git-fsmonitor--daemon - A Built-in File System Monitor
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
SYNOPSIS
--------
@@ -17,7 +17,7 @@ DESCRIPTION
-----------
A daemon to watch the working directory for file and directory
-changes using platform-specific file system notification facilities.
+changes using platform-specific filesystem notification facilities.
This daemon communicates directly with commands like `git status`
using the link:technical/api-simple-ipc.html[simple IPC] interface
@@ -63,13 +63,44 @@ CAVEATS
-------
The fsmonitor daemon does not currently know about submodules and does
-not know to filter out file system events that happen within a
+not know to filter out filesystem events that happen within a
submodule. If fsmonitor daemon is watching a super repo and a file is
modified within the working directory of a submodule, it will report
the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory, however, if the
+`.git` directory is on a network-mounted filesystem, it will be instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fsmonitor--daemon.txt[]
+
GIT
---
Part of the linkgit:git[1] suite
--
gitgitgadget
^ permalink raw reply related [flat|nested] 170+ messages in thread
* Re: [PATCH v15 6/6] fsmonitor: add documentation for allowRemote and socketDir options
2022-10-04 17:32 ` [PATCH v15 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2023-01-30 10:04 ` Ævar Arnfjörð Bjarmason
0 siblings, 0 replies; 170+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2023-01-30 10:04 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ramsay Jones, Johannes Schindelin, Eric DeCosta
On Tue, Oct 04 2022, Eric DeCosta via GitGitGadget wrote:
> From: Eric DeCosta <edecosta@mathworks.com>
> [...]
> +include::config/fsmonitor--daemon.txt[]
We tend to name these files after the config namespace, not the name of
the built-in that's (mostly?) using it.
> +
> include::config/gc.txt[]
>
> include::config/gitcvs.txt[]
> diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.txt
> new file mode 100644
> index 00000000000..c225c6c9e74
> --- /dev/null
> +++ b/Documentation/config/fsmonitor--daemon.txt
> @@ -0,0 +1,11 @@
So this should be just .../config/fsmonitor.txt
^ permalink raw reply [flat|nested] 170+ messages in thread
* Re: [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-10-04 17:32 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Eric DeCosta via GitGitGadget
` (5 preceding siblings ...)
2022-10-04 17:32 ` [PATCH v15 6/6] fsmonitor: add documentation for allowRemote and socketDir options Eric DeCosta via GitGitGadget
@ 2022-10-05 18:05 ` Junio C Hamano
2022-10-05 21:14 ` Eric DeCosta
6 siblings, 1 reply; 170+ messages in thread
From: Junio C Hamano @ 2022-10-05 18:05 UTC (permalink / raw)
To: Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin, Eric DeCosta
"Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
> 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.
>
> v15 differs from v14:
>
> * fix memory leak
Thanks. I thought "what, another iteration? didn't we see this
enough times already?" and a note like this does help reminding
reviewers why we need one.
Very much appreciated.
^ permalink raw reply [flat|nested] 170+ messages in thread
* RE: [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos
2022-10-05 18:05 ` [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run against network-mounted repos Junio C Hamano
@ 2022-10-05 21:14 ` Eric DeCosta
0 siblings, 0 replies; 170+ messages in thread
From: Eric DeCosta @ 2022-10-05 21:14 UTC (permalink / raw)
To: Junio C Hamano, Eric DeCosta via GitGitGadget
Cc: git, Jeff Hostetler, Eric Sunshine, Torsten Bögershausen,
Ævar Arnfjörð Bjarmason, Ramsay Jones,
Johannes Schindelin
> -----Original Message-----
> From: Junio C Hamano <jch2355@gmail.com> On Behalf Of Junio C Hamano
> Sent: Wednesday, October 5, 2022 2:05 PM
> To: Eric DeCosta via GitGitGadget <gitgitgadget@gmail.com>
> Cc: git@vger.kernel.org; Jeff Hostetler <git@jeffhostetler.com>; Eric Sunshine
> <sunshine@sunshineco.com>; Torsten Bögershausen <tboegi@web.de>;
> Ævar Arnfjörð Bjarmason <avarab@gmail.com>; Ramsay Jones
> <ramsay@ramsayjones.plus.com>; Johannes Schindelin
> <Johannes.Schindelin@gmx.de>; Eric DeCosta <edecosta@mathworks.com>
> Subject: Re: [PATCH v15 0/6] fsmonitor: option to allow fsmonitor to run
> against network-mounted repos
>
> "Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > 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.
> >
> > v15 differs from v14:
> >
> > * fix memory leak
>
> Thanks. I thought "what, another iteration? didn't we see this enough times
> already?" and a note like this does help reminding reviewers why we need
> one.
>
> Very much appreciated.
Thanks. Just getting better at doing the right thing as I climb up the learning curve :)
Hopefully it is in a state where it is now GTM.
-Eric
^ permalink raw reply [flat|nested] 170+ messages in thread