|
21 | 21 | #include <stdio.h> |
22 | 22 | #include <ctype.h> |
23 | 23 |
|
24 | | -#define LOOKS_LIKE_DRIVE_PREFIX(S) (git__isalpha((S)[0]) && (S)[1] == ':') |
| 24 | +static int dos_drive_prefix_length(const char *path) |
| 25 | +{ |
| 26 | + int i; |
| 27 | + |
| 28 | + /* |
| 29 | + * Does it start with an ASCII letter (i.e. highest bit not set), |
| 30 | + * followed by a colon? |
| 31 | + */ |
| 32 | + if (!(0x80 & (unsigned char)*path)) |
| 33 | + return *path && path[1] == ':' ? 2 : 0; |
| 34 | + |
| 35 | + /* |
| 36 | + * While drive letters must be letters of the English alphabet, it is |
| 37 | + * possible to assign virtually _any_ Unicode character via `subst` as |
| 38 | + * a drive letter to "virtual drives". Even `1`, or `ä`. Or fun stuff |
| 39 | + * like this: |
| 40 | + * |
| 41 | + * subst ֍: %USERPROFILE%\Desktop |
| 42 | + */ |
| 43 | + for (i = 1; i < 4 && (0x80 & (unsigned char)path[i]); i++) |
| 44 | + ; /* skip first UTF-8 character */ |
| 45 | + return path[i] == ':' ? i + 1 : 0; |
| 46 | +} |
25 | 47 |
|
26 | 48 | #ifdef GIT_WIN32 |
27 | 49 | static bool looks_like_network_computer_name(const char *path, int pos) |
@@ -123,11 +145,11 @@ static int win32_prefix_length(const char *path, int len) |
123 | 145 | GIT_UNUSED(len); |
124 | 146 | #else |
125 | 147 | /* |
126 | | - * Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return |
127 | | - * 'C:/' here |
| 148 | + * Mimic unix behavior where '/.git' returns '/': 'C:/.git' |
| 149 | + * will return 'C:/' here |
128 | 150 | */ |
129 | | - if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path)) |
130 | | - return 2; |
| 151 | + if (dos_drive_prefix_length(path) == len) |
| 152 | + return len; |
131 | 153 |
|
132 | 154 | /* |
133 | 155 | * Similarly checks if we're dealing with a network computer name |
@@ -272,11 +294,11 @@ const char *git_path_topdir(const char *path) |
272 | 294 |
|
273 | 295 | int git_path_root(const char *path) |
274 | 296 | { |
275 | | - int offset = 0; |
| 297 | + int offset = 0, prefix_len; |
276 | 298 |
|
277 | 299 | /* Does the root of the path look like a windows drive ? */ |
278 | | - if (LOOKS_LIKE_DRIVE_PREFIX(path)) |
279 | | - offset += 2; |
| 300 | + if ((prefix_len = dos_drive_prefix_length(path))) |
| 301 | + offset += prefix_len; |
280 | 302 |
|
281 | 303 | #ifdef GIT_WIN32 |
282 | 304 | /* Are we dealing with a windows network path? */ |
|
0 commit comments