Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/compat
diff options
context:
space:
mode:
Diffstat (limited to 'compat')
-rw-r--r--compat/disk.h56
-rw-r--r--compat/fsmonitor/fsm-darwin-gcc.h4
-rw-r--r--compat/fsmonitor/fsm-ipc-darwin.c52
-rw-r--r--compat/fsmonitor/fsm-ipc-win32.c9
-rw-r--r--compat/fsmonitor/fsm-listen-darwin.c51
-rw-r--r--compat/fsmonitor/fsm-path-utils-darwin.c135
-rw-r--r--compat/fsmonitor/fsm-path-utils-win32.c145
-rw-r--r--compat/fsmonitor/fsm-settings-darwin.c77
-rw-r--r--compat/fsmonitor/fsm-settings-win32.c106
-rw-r--r--compat/mingw.c11
-rw-r--r--compat/nonblock.c2
-rw-r--r--compat/terminal.c2
-rw-r--r--compat/win32/pthread.h2
13 files changed, 473 insertions, 179 deletions
diff --git a/compat/disk.h b/compat/disk.h
new file mode 100644
index 0000000000..50a32e3d8a
--- /dev/null
+++ b/compat/disk.h
@@ -0,0 +1,56 @@
+#ifndef COMPAT_DISK_H
+#define COMPAT_DISK_H
+
+#include "git-compat-util.h"
+
+static int get_disk_info(struct strbuf *out)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int res = 0;
+
+#ifdef GIT_WINDOWS_NATIVE
+ char volume_name[MAX_PATH], fs_name[MAX_PATH];
+ DWORD serial_number, component_length, flags;
+ ULARGE_INTEGER avail2caller, total, avail;
+
+ strbuf_realpath(&buf, ".", 1);
+ if (!GetDiskFreeSpaceExA(buf.buf, &avail2caller, &total, &avail)) {
+ error(_("could not determine free disk size for '%s'"),
+ buf.buf);
+ res = -1;
+ goto cleanup;
+ }
+
+ strbuf_setlen(&buf, offset_1st_component(buf.buf));
+ if (!GetVolumeInformationA(buf.buf, volume_name, sizeof(volume_name),
+ &serial_number, &component_length, &flags,
+ fs_name, sizeof(fs_name))) {
+ error(_("could not get info for '%s'"), buf.buf);
+ res = -1;
+ goto cleanup;
+ }
+ strbuf_addf(out, "Available space on '%s': ", buf.buf);
+ strbuf_humanise_bytes(out, avail2caller.QuadPart);
+ strbuf_addch(out, '\n');
+#else
+ struct statvfs stat;
+
+ strbuf_realpath(&buf, ".", 1);
+ if (statvfs(buf.buf, &stat) < 0) {
+ error_errno(_("could not determine free disk size for '%s'"),
+ buf.buf);
+ res = -1;
+ goto cleanup;
+ }
+
+ strbuf_addf(out, "Available space on '%s': ", buf.buf);
+ strbuf_humanise_bytes(out, (off_t)stat.f_bsize * (off_t)stat.f_bavail);
+ strbuf_addf(out, " (mount flags 0x%lx)\n", stat.f_flag);
+#endif
+
+cleanup:
+ strbuf_release(&buf);
+ return res;
+}
+
+#endif /* COMPAT_DISK_H */
diff --git a/compat/fsmonitor/fsm-darwin-gcc.h b/compat/fsmonitor/fsm-darwin-gcc.h
index 1c75c3d48e..3496e29b3a 100644
--- a/compat/fsmonitor/fsm-darwin-gcc.h
+++ b/compat/fsmonitor/fsm-darwin-gcc.h
@@ -80,9 +80,7 @@ void CFRunLoopRun(void);
void CFRunLoopStop(CFRunLoopRef run_loop);
CFRunLoopRef CFRunLoopGetCurrent(void);
extern CFStringRef kCFRunLoopDefaultMode;
-void FSEventStreamScheduleWithRunLoop(FSEventStreamRef stream,
- CFRunLoopRef run_loop,
- CFStringRef run_loop_mode);
+void FSEventStreamSetDispatchQueue(FSEventStreamRef stream, dispatch_queue_t q);
unsigned char FSEventStreamStart(FSEventStreamRef stream);
void FSEventStreamStop(FSEventStreamRef stream);
void FSEventStreamInvalidate(FSEventStreamRef stream);
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 0000000000..d67b0ee50d
--- /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;
+ git_SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[GIT_MAX_RAWSZ];
+
+ 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;
+ }
+
+ git_SHA1_Init(&sha1ctx);
+ git_SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ git_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 0000000000..e08c505c14
--- /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-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289..97a55a6f0a 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -1,4 +1,5 @@
#ifndef __clang__
+#include <dispatch/dispatch.h>
#include "fsm-darwin-gcc.h"
#else
#include <CoreFoundation/CoreFoundation.h>
@@ -26,6 +27,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -37,7 +39,9 @@ struct fsm_listen_data
FSEventStreamRef stream;
- CFRunLoopRef rl;
+ dispatch_queue_t dq;
+ pthread_cond_t dq_finished;
+ pthread_mutex_t dq_lock;
enum shutdown_style {
SHUTDOWN_EVENT = 0,
@@ -198,8 +202,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 +214,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 +248,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
@@ -328,7 +339,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
* know how much to invalidate/refresh.
*/
- if (event_flags[k] & kFSEventStreamEventFlagItemIsFile) {
+ if (event_flags[k] & (kFSEventStreamEventFlagItemIsFile | kFSEventStreamEventFlagItemIsSymlink)) {
const char *rel = path_k +
state->path_worktree_watch.len + 1;
@@ -360,17 +371,22 @@ 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);
+ pthread_mutex_lock(&data->dq_lock);
data->shutdown_style = FORCE_SHUTDOWN;
- CFRunLoopStop(data->rl);
+ pthread_cond_broadcast(&data->dq_finished);
+ pthread_mutex_unlock(&data->dq_lock);
+
strbuf_release(&tmp);
return;
}
@@ -431,10 +447,6 @@ int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
if (!data->stream)
goto failed;
- /*
- * `data->rl` needs to be set inside the listener thread.
- */
-
return 0;
failed:
@@ -461,6 +473,11 @@ void fsm_listen__dtor(struct fsmonitor_daemon_state *state)
FSEventStreamRelease(data->stream);
}
+ if (data->dq)
+ dispatch_release(data->dq);
+ pthread_cond_destroy(&data->dq_finished);
+ pthread_mutex_destroy(&data->dq_lock);
+
FREE_AND_NULL(state->listen_data);
}
@@ -469,9 +486,11 @@ void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
struct fsm_listen_data *data;
data = state->listen_data;
- data->shutdown_style = SHUTDOWN_EVENT;
- CFRunLoopStop(data->rl);
+ pthread_mutex_lock(&data->dq_lock);
+ data->shutdown_style = SHUTDOWN_EVENT;
+ pthread_cond_broadcast(&data->dq_finished);
+ pthread_mutex_unlock(&data->dq_lock);
}
void fsm_listen__loop(struct fsmonitor_daemon_state *state)
@@ -480,9 +499,11 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
data = state->listen_data;
- data->rl = CFRunLoopGetCurrent();
+ pthread_mutex_init(&data->dq_lock, NULL);
+ pthread_cond_init(&data->dq_finished, NULL);
+ data->dq = dispatch_queue_create("FSMonitor", NULL);
- FSEventStreamScheduleWithRunLoop(data->stream, data->rl, kCFRunLoopDefaultMode);
+ FSEventStreamSetDispatchQueue(data->stream, data->dq);
data->stream_scheduled = 1;
if (!FSEventStreamStart(data->stream)) {
@@ -491,7 +512,9 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
}
data->stream_started = 1;
- CFRunLoopRun();
+ pthread_mutex_lock(&data->dq_lock);
+ pthread_cond_wait(&data->dq_finished, &data->dq_lock);
+ pthread_mutex_unlock(&data->dq_lock);
switch (data->shutdown_style) {
case FORCE_ERROR_STOP:
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 0000000000..ce5a8febe0
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,135 @@
+#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>
+
+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;
+}
+
+/*
+ * 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
new file mode 100644
index 0000000000..0d95bbb416
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,145 @@
+#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;
+}
+
+/*
+ * 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/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f3..6abbc7af3a 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,52 +16,47 @@
* 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(r);
+ 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))
- return FSMONITOR_REASON_REMOTE;
-
- 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;
}
-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_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 907655720b..a8af31b71d 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,104 +25,7 @@ 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 fsm_os__incompatible(struct repository *r, int ipc)
{
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/compat/mingw.c b/compat/mingw.c
index 9e59a56f27..af397e68a1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -196,16 +196,19 @@ static int read_yes_no_answer(void)
static int ask_yes_no_if_possible(const char *format, ...)
{
char question[4096];
- const char *retry_hook[] = { NULL, NULL, NULL };
+ const char *retry_hook;
va_list args;
va_start(args, format);
vsnprintf(question, sizeof(question), format, args);
va_end(args);
- if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
- retry_hook[1] = question;
- return !run_command_v_opt(retry_hook, 0);
+ retry_hook = mingw_getenv("GIT_ASK_YESNO");
+ if (retry_hook) {
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ strvec_pushl(&cmd.args, retry_hook, question, NULL);
+ return !run_command(&cmd);
}
if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr)))
diff --git a/compat/nonblock.c b/compat/nonblock.c
index 9694ebdb1d..5b51195c32 100644
--- a/compat/nonblock.c
+++ b/compat/nonblock.c
@@ -41,7 +41,7 @@ int enable_pipe_nonblock(int fd)
#else
-int enable_pipe_nonblock(int fd)
+int enable_pipe_nonblock(int fd UNUSED)
{
errno = ENOSYS;
return -1;
diff --git a/compat/terminal.c b/compat/terminal.c
index 7db330c52d..ea490a7ced 100644
--- a/compat/terminal.c
+++ b/compat/terminal.c
@@ -477,7 +477,7 @@ struct escape_sequence_entry {
char sequence[FLEX_ARRAY];
};
-static int sequence_entry_cmp(const void *hashmap_cmp_fn_data,
+static int sequence_entry_cmp(const void *hashmap_cmp_fn_data UNUSED,
const struct escape_sequence_entry *e1,
const struct escape_sequence_entry *e2,
const void *keydata)
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index 737983d00b..cc3221cb2c 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -66,7 +66,7 @@ pthread_t pthread_self(void);
static inline void NORETURN pthread_exit(void *ret)
{
- ExitThread((DWORD)(intptr_t)ret);
+ _endthreadex((unsigned)(uintptr_t)ret);
}
typedef DWORD pthread_key_t;