| 214 | } |
| 215 | |
| 216 | static bool watcher_windows_git_candidate(const wchar_t *entry, size_t entry_length, |
| 217 | char output[CBM_SZ_4K]) { |
| 218 | while (entry_length > 0U && (entry[0] == L' ' || entry[0] == L'\t')) { |
| 219 | entry++; |
| 220 | entry_length--; |
| 221 | } |
| 222 | while (entry_length > 0U && |
| 223 | (entry[entry_length - 1U] == L' ' || entry[entry_length - 1U] == L'\t')) { |
| 224 | entry_length--; |
| 225 | } |
| 226 | if (entry_length >= 2U && entry[0] == L'"' && entry[entry_length - 1U] == L'"') { |
| 227 | entry++; |
| 228 | entry_length -= 2U; |
| 229 | } |
| 230 | while (entry_length > 0U && (entry[0] == L' ' || entry[0] == L'\t')) { |
| 231 | entry++; |
| 232 | entry_length--; |
| 233 | } |
| 234 | while (entry_length > 0U && |
| 235 | (entry[entry_length - 1U] == L' ' || entry[entry_length - 1U] == L'\t')) { |
| 236 | entry_length--; |
| 237 | } |
| 238 | if (entry_length == 0U || entry_length >= CBM_SZ_4K) { |
| 239 | return false; |
| 240 | } |
| 241 | wchar_t directory[CBM_SZ_4K]; |
| 242 | memcpy(directory, entry, entry_length * sizeof(*directory)); |
| 243 | directory[entry_length] = L'\0'; |
| 244 | if (!watcher_windows_path_absolute(directory) || wcschr(directory, L'"') != NULL) { |
| 245 | return false; |
| 246 | } |
| 247 | |
| 248 | bool separator = directory[entry_length - 1U] == L'\\' || directory[entry_length - 1U] == L'/'; |
| 249 | wchar_t candidate[CBM_SZ_4K]; |
| 250 | int written = |
| 251 | swprintf(candidate, CBM_SZ_4K, separator ? L"%lsgit.exe" : L"%ls\\git.exe", directory); |
| 252 | if (written <= 0 || written >= CBM_SZ_4K) { |
| 253 | return false; |
| 254 | } |
| 255 | DWORD required = GetFullPathNameW(candidate, 0U, NULL, NULL); |
| 256 | wchar_t *normalized = |
| 257 | required > 0U ? malloc(((size_t)required + 1U) * sizeof(*normalized)) : NULL; |
| 258 | DWORD normalized_length = |
| 259 | normalized ? GetFullPathNameW(candidate, required + 1U, normalized, NULL) : 0U; |
| 260 | if (!normalized || normalized_length == 0U || normalized_length > required || |
| 261 | !watcher_windows_path_absolute(normalized)) { |
| 262 | free(normalized); |
| 263 | return false; |
| 264 | } |
| 265 | HANDLE file = CreateFileW(normalized, GENERIC_READ | FILE_READ_ATTRIBUTES, |
| 266 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, |
| 267 | OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL); |
| 268 | BY_HANDLE_FILE_INFORMATION information; |
| 269 | bool regular = file != INVALID_HANDLE_VALUE && GetFileType(file) == FILE_TYPE_DISK && |
| 270 | GetFileInformationByHandle(file, &information) != 0 && |
| 271 | (information.dwFileAttributes & |
| 272 | (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) == 0; |
| 273 | if (file != INVALID_HANDLE_VALUE) { |
no test coverage detected