]> git.ipfire.org Git - thirdparty/git.git/blob - compat/fsmonitor/fsm-settings-win32.c
clone: allow "--bare" with "-o"
[thirdparty/git.git] / compat / fsmonitor / fsm-settings-win32.c
1 #include "cache.h"
2 #include "config.h"
3 #include "repository.h"
4 #include "fsmonitor-settings.h"
5 #include "fsmonitor.h"
6
7 /*
8 * VFS for Git is incompatible with FSMonitor.
9 *
10 * Granted, core Git does not know anything about VFS for Git and we
11 * shouldn't make assumptions about a downstream feature, but users
12 * can install both versions. And this can lead to incorrect results
13 * from core Git commands. So, without bringing in any of the VFS for
14 * Git code, do a simple config test for a published config setting.
15 * (We do not look at the various *_TEST_* environment variables.)
16 */
17 static enum fsmonitor_reason check_vfs4git(struct repository *r)
18 {
19 const char *const_str;
20
21 if (!repo_config_get_value(r, "core.virtualfilesystem", &const_str))
22 return FSMONITOR_REASON_VFS4GIT;
23
24 return FSMONITOR_REASON_OK;
25 }
26
27 /*
28 * Remote working directories are problematic for FSMonitor.
29 *
30 * The underlying file system on the server machine and/or the remote
31 * mount type dictates whether notification events are available at
32 * all to remote client machines.
33 *
34 * Kernel differences between the server and client machines also
35 * dictate the how (buffering, frequency, de-dup) the events are
36 * delivered to client machine processes.
37 *
38 * A client machine (such as a laptop) may choose to suspend/resume
39 * and it is unclear (without lots of testing) whether the watcher can
40 * resync after a resume. We might be able to treat this as a normal
41 * "events were dropped by the kernel" event and do our normal "flush
42 * and resync" --or-- we might need to close the existing (zombie?)
43 * notification fd and create a new one.
44 *
45 * In theory, the above issues need to be addressed whether we are
46 * using the Hook or IPC API.
47 *
48 * So (for now at least), mark remote working directories as
49 * incompatible.
50 *
51 * Notes for testing:
52 *
53 * (a) Windows allows a network share to be mapped to a drive letter.
54 * (This is the normal method to access it.)
55 *
56 * $ NET USE Z: \\server\share
57 * $ git -C Z:/repo status
58 *
59 * (b) Windows allows a network share to be referenced WITHOUT mapping
60 * it to drive letter.
61 *
62 * $ NET USE \\server\share\dir
63 * $ git -C //server/share/repo status
64 *
65 * (c) Windows allows "SUBST" to create a fake drive mapping to an
66 * arbitrary path (which may be remote)
67 *
68 * $ SUBST Q: Z:\repo
69 * $ git -C Q:/ status
70 *
71 * (d) Windows allows a directory symlink to be created on a local
72 * file system that points to a remote repo.
73 *
74 * $ mklink /d ./link //server/share/repo
75 * $ git -C ./link status
76 */
77 static enum fsmonitor_reason check_remote(struct repository *r)
78 {
79 wchar_t wpath[MAX_PATH];
80 wchar_t wfullpath[MAX_PATH];
81 size_t wlen;
82 UINT driveType;
83
84 /*
85 * Do everything in wide chars because the drive letter might be
86 * a multi-byte sequence. See win32_has_dos_drive_prefix().
87 */
88 if (xutftowcs_path(wpath, r->worktree) < 0)
89 return FSMONITOR_REASON_ERROR;
90
91 /*
92 * GetDriveTypeW() requires a final slash. We assume that the
93 * worktree pathname points to an actual directory.
94 */
95 wlen = wcslen(wpath);
96 if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
97 wpath[wlen++] = L'\\';
98 wpath[wlen] = 0;
99 }
100
101 /*
102 * Normalize the path. If nothing else, this converts forward
103 * slashes to backslashes. This is essential to get GetDriveTypeW()
104 * correctly handle some UNC "\\server\share\..." paths.
105 */
106 if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
107 return FSMONITOR_REASON_ERROR;
108
109 driveType = GetDriveTypeW(wfullpath);
110 trace_printf_key(&trace_fsmonitor,
111 "DriveType '%s' L'%ls' (%u)",
112 r->worktree, wfullpath, driveType);
113
114 if (driveType == DRIVE_REMOTE) {
115 trace_printf_key(&trace_fsmonitor,
116 "check_remote('%s') true",
117 r->worktree);
118 return FSMONITOR_REASON_REMOTE;
119 }
120
121 return FSMONITOR_REASON_OK;
122 }
123
124 enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
125 {
126 enum fsmonitor_reason reason;
127
128 reason = check_vfs4git(r);
129 if (reason != FSMONITOR_REASON_OK)
130 return reason;
131
132 reason = check_remote(r);
133 if (reason != FSMONITOR_REASON_OK)
134 return reason;
135
136 return FSMONITOR_REASON_OK;
137 }