git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / code / Atom feed
blob e5ec5b0a9f73bcf04085b5d62d7b123690ce937e 5791 bytes (raw)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
 
#include "cache.h"
#include "config.h"
#include "repository.h"
#include "fsmonitor-settings.h"
#include "fsmonitor.h"

/*
 * VFS for Git is incompatible with FSMonitor.
 *
 * Granted, core Git does not know anything about VFS for Git and we
 * shouldn't make assumptions about a downstream feature, but users
 * can install both versions.  And this can lead to incorrect results
 * from core Git commands.  So, without bringing in any of the VFS for
 * Git code, do a simple config test for a published config setting.
 * (We do not look at the various *_TEST_* environment variables.)
 */
static enum fsmonitor_reason check_vfs4git(struct repository *r)
{
	const char *const_str;

	if (!repo_config_get_value(r, "core.virtualfilesystem", &const_str))
		return FSMONITOR_REASON_VFS4GIT;

	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;

	reason = check_vfs4git(r);
	if (reason != FSMONITOR_REASON_OK)
		return reason;

	reason = check_remote(r);
	if (reason != FSMONITOR_REASON_OK)
		return reason;

	return FSMONITOR_REASON_OK;
}

debug log:

solving e5ec5b0a9f7 ...
found e5ec5b0a9f7 in https://80x24.org/mirrors/git.git

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).