|
| 1 | +#include "../../git-compat-util.h" |
| 2 | +#include "../win32.h" |
| 3 | +#include "../../repository.h" |
| 4 | +#include "config.h" |
| 5 | +#include "ntifs.h" |
| 6 | +#include "wsl.h" |
| 7 | + |
| 8 | +int are_wsl_compatible_mode_bits_enabled(void) |
| 9 | +{ |
| 10 | + /* default to `false` during initialization */ |
| 11 | + static const int fallback = 0; |
| 12 | + static int enabled = -1; |
| 13 | + |
| 14 | + if (enabled < 0) { |
| 15 | + /* avoid infinite recursion */ |
| 16 | + if (!the_repository) |
| 17 | + return fallback; |
| 18 | + |
| 19 | + if (the_repository->config && |
| 20 | + the_repository->config->hash_initialized && |
| 21 | + git_config_get_bool("core.wslcompat", &enabled) < 0) |
| 22 | + enabled = 0; |
| 23 | + } |
| 24 | + |
| 25 | + return enabled < 0 ? fallback : enabled; |
| 26 | +} |
| 27 | + |
| 28 | +int copy_wsl_mode_bits_from_disk(const wchar_t *wpath, ssize_t wpathlen, |
| 29 | + _mode_t *mode) |
| 30 | +{ |
| 31 | + int ret = -1; |
| 32 | + HANDLE h; |
| 33 | + if (wpathlen >= 0) { |
| 34 | + /* |
| 35 | + * It's caller's duty to make sure wpathlen is reasonable so |
| 36 | + * it does not overflow. |
| 37 | + */ |
| 38 | + wchar_t *fn2 = (wchar_t*)alloca((wpathlen + 1) * sizeof(wchar_t)); |
| 39 | + memcpy(fn2, wpath, wpathlen * sizeof(wchar_t)); |
| 40 | + fn2[wpathlen] = 0; |
| 41 | + wpath = fn2; |
| 42 | + } |
| 43 | + h = CreateFileW(wpath, FILE_READ_EA | SYNCHRONIZE, |
| 44 | + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 45 | + NULL, OPEN_EXISTING, |
| 46 | + FILE_FLAG_BACKUP_SEMANTICS | |
| 47 | + FILE_FLAG_OPEN_REPARSE_POINT, |
| 48 | + NULL); |
| 49 | + if (h != INVALID_HANDLE_VALUE) { |
| 50 | + ret = get_wsl_mode_bits_by_handle(h, mode); |
| 51 | + CloseHandle(h); |
| 52 | + } |
| 53 | + return ret; |
| 54 | +} |
| 55 | + |
| 56 | +#define LX_FILE_METADATA_HAS_UID 0x1 |
| 57 | +#define LX_FILE_METADATA_HAS_GID 0x2 |
| 58 | +#define LX_FILE_METADATA_HAS_MODE 0x4 |
| 59 | +#define LX_FILE_METADATA_HAS_DEVICE_ID 0x8 |
| 60 | +#define LX_FILE_CASE_SENSITIVE_DIR 0x10 |
| 61 | +typedef struct _FILE_STAT_LX_INFORMATION { |
| 62 | + LARGE_INTEGER FileId; |
| 63 | + LARGE_INTEGER CreationTime; |
| 64 | + LARGE_INTEGER LastAccessTime; |
| 65 | + LARGE_INTEGER LastWriteTime; |
| 66 | + LARGE_INTEGER ChangeTime; |
| 67 | + LARGE_INTEGER AllocationSize; |
| 68 | + LARGE_INTEGER EndOfFile; |
| 69 | + uint32_t FileAttributes; |
| 70 | + uint32_t ReparseTag; |
| 71 | + uint32_t NumberOfLinks; |
| 72 | + ACCESS_MASK EffectiveAccess; |
| 73 | + uint32_t LxFlags; |
| 74 | + uint32_t LxUid; |
| 75 | + uint32_t LxGid; |
| 76 | + uint32_t LxMode; |
| 77 | + uint32_t LxDeviceIdMajor; |
| 78 | + uint32_t LxDeviceIdMinor; |
| 79 | +} FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION; |
| 80 | + |
| 81 | +/* |
| 82 | + * This struct is extended from the original FILE_FULL_EA_INFORMATION of |
| 83 | + * Microsoft Windows. |
| 84 | + */ |
| 85 | +struct wsl_full_ea_info_t { |
| 86 | + uint32_t NextEntryOffset; |
| 87 | + uint8_t Flags; |
| 88 | + uint8_t EaNameLength; |
| 89 | + uint16_t EaValueLength; |
| 90 | + char EaName[7]; |
| 91 | + char EaValue[4]; |
| 92 | + char Padding[1]; |
| 93 | +}; |
| 94 | + |
| 95 | +enum { |
| 96 | + FileStatLxInformation = 70, |
| 97 | +}; |
| 98 | +__declspec(dllimport) NTSTATUS WINAPI |
| 99 | + NtQueryInformationFile(HANDLE FileHandle, |
| 100 | + PIO_STATUS_BLOCK IoStatusBlock, |
| 101 | + PVOID FileInformation, ULONG Length, |
| 102 | + uint32_t FileInformationClass); |
| 103 | +__declspec(dllimport) NTSTATUS WINAPI |
| 104 | + NtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, |
| 105 | + PVOID FileInformation, ULONG Length, |
| 106 | + uint32_t FileInformationClass); |
| 107 | +__declspec(dllimport) NTSTATUS WINAPI |
| 108 | + NtSetEaFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, |
| 109 | + PVOID EaBuffer, ULONG EaBufferSize); |
| 110 | + |
| 111 | +int set_wsl_mode_bits_by_handle(HANDLE h, _mode_t mode) |
| 112 | +{ |
| 113 | + uint32_t value = mode; |
| 114 | + struct wsl_full_ea_info_t ea_info; |
| 115 | + IO_STATUS_BLOCK iob; |
| 116 | + /* mode should be valid to make WSL happy */ |
| 117 | + assert(S_ISREG(mode) || S_ISDIR(mode)); |
| 118 | + ea_info.NextEntryOffset = 0; |
| 119 | + ea_info.Flags = 0; |
| 120 | + ea_info.EaNameLength = 6; |
| 121 | + ea_info.EaValueLength = sizeof(value); /* 4 */ |
| 122 | + strlcpy(ea_info.EaName, "$LXMOD", sizeof(ea_info.EaName)); |
| 123 | + memcpy(ea_info.EaValue, &value, sizeof(value)); |
| 124 | + ea_info.Padding[0] = 0; |
| 125 | + return NtSetEaFile(h, &iob, &ea_info, sizeof(ea_info)); |
| 126 | +} |
| 127 | + |
| 128 | +int get_wsl_mode_bits_by_handle(HANDLE h, _mode_t *mode) |
| 129 | +{ |
| 130 | + FILE_STAT_LX_INFORMATION fxi; |
| 131 | + IO_STATUS_BLOCK iob; |
| 132 | + if (NtQueryInformationFile(h, &iob, &fxi, sizeof(fxi), |
| 133 | + FileStatLxInformation) == 0) { |
| 134 | + if (fxi.LxFlags & LX_FILE_METADATA_HAS_MODE) |
| 135 | + *mode = (_mode_t)fxi.LxMode; |
| 136 | + return 0; |
| 137 | + } |
| 138 | + return -1; |
| 139 | +} |
0 commit comments