]> git.ipfire.org Git - thirdparty/git.git/blob - compat/fsmonitor/fsm-path-utils-win32.c
commit -a -m: allow the top-level tree to become empty again
[thirdparty/git.git] / compat / fsmonitor / fsm-path-utils-win32.c
1 #include "cache.h"
2 #include "fsmonitor.h"
3 #include "fsmonitor-path-utils.h"
4
5 /*
6 * Check remote working directory protocol.
7 *
8 * Return -1 if client machine cannot get remote protocol information.
9 */
10 static int check_remote_protocol(wchar_t *wpath)
11 {
12 HANDLE h;
13 FILE_REMOTE_PROTOCOL_INFO proto_info;
14
15 h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
16 FILE_FLAG_BACKUP_SEMANTICS, NULL);
17
18 if (h == INVALID_HANDLE_VALUE) {
19 error(_("[GLE %ld] unable to open for read '%ls'"),
20 GetLastError(), wpath);
21 return -1;
22 }
23
24 if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
25 &proto_info, sizeof(proto_info))) {
26 error(_("[GLE %ld] unable to get protocol information for '%ls'"),
27 GetLastError(), wpath);
28 CloseHandle(h);
29 return -1;
30 }
31
32 CloseHandle(h);
33
34 trace_printf_key(&trace_fsmonitor,
35 "check_remote_protocol('%ls') remote protocol %#8.8lx",
36 wpath, proto_info.Protocol);
37
38 return 0;
39 }
40
41 /*
42 * Notes for testing:
43 *
44 * (a) Windows allows a network share to be mapped to a drive letter.
45 * (This is the normal method to access it.)
46 *
47 * $ NET USE Z: \\server\share
48 * $ git -C Z:/repo status
49 *
50 * (b) Windows allows a network share to be referenced WITHOUT mapping
51 * it to drive letter.
52 *
53 * $ NET USE \\server\share\dir
54 * $ git -C //server/share/repo status
55 *
56 * (c) Windows allows "SUBST" to create a fake drive mapping to an
57 * arbitrary path (which may be remote)
58 *
59 * $ SUBST Q: Z:\repo
60 * $ git -C Q:/ status
61 *
62 * (d) Windows allows a directory symlink to be created on a local
63 * file system that points to a remote repo.
64 *
65 * $ mklink /d ./link //server/share/repo
66 * $ git -C ./link status
67 */
68 int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
69 {
70 wchar_t wpath[MAX_PATH];
71 wchar_t wfullpath[MAX_PATH];
72 size_t wlen;
73 UINT driveType;
74
75 /*
76 * Do everything in wide chars because the drive letter might be
77 * a multi-byte sequence. See win32_has_dos_drive_prefix().
78 */
79 if (xutftowcs_path(wpath, path) < 0) {
80 return -1;
81 }
82
83 /*
84 * GetDriveTypeW() requires a final slash. We assume that the
85 * worktree pathname points to an actual directory.
86 */
87 wlen = wcslen(wpath);
88 if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
89 wpath[wlen++] = L'\\';
90 wpath[wlen] = 0;
91 }
92
93 /*
94 * Normalize the path. If nothing else, this converts forward
95 * slashes to backslashes. This is essential to get GetDriveTypeW()
96 * correctly handle some UNC "\\server\share\..." paths.
97 */
98 if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
99 return -1;
100 }
101
102 driveType = GetDriveTypeW(wfullpath);
103 trace_printf_key(&trace_fsmonitor,
104 "DriveType '%s' L'%ls' (%u)",
105 path, wfullpath, driveType);
106
107 if (driveType == DRIVE_REMOTE) {
108 fs_info->is_remote = 1;
109 if (check_remote_protocol(wfullpath) < 0)
110 return -1;
111 } else {
112 fs_info->is_remote = 0;
113 }
114
115 trace_printf_key(&trace_fsmonitor,
116 "'%s' is_remote: %d",
117 path, fs_info->is_remote);
118
119 return 0;
120 }
121
122 int fsmonitor__is_fs_remote(const char *path)
123 {
124 struct fs_info fs;
125 if (fsmonitor__get_fs_info(path, &fs))
126 return -1;
127 return fs.is_remote;
128 }
129
130 /*
131 * No-op for now.
132 */
133 int fsmonitor__get_alias(const char *path, struct alias_info *info)
134 {
135 return 0;
136 }
137
138 /*
139 * No-op for now.
140 */
141 char *fsmonitor__resolve_alias(const char *path,
142 const struct alias_info *info)
143 {
144 return NULL;
145 }