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