Skip to content

Commit 9e8d75c

Browse files
committed
path: ensure dirname on Win32 prefix always has a trailing '/'
When calling `git_path_dirname_r` on a Win32 prefix, e.g. a drive or network share prefix, we always want to return the trailing '/'. This does not work currently when passing in a path like 'C:', where the '/' would not be appended correctly. Fix this by appending a '/' if we try to normalize a Win32 prefix and there is no trailing '/'.
1 parent 5d59520 commit 9e8d75c

File tree

2 files changed

+17
-7
lines changed

2 files changed

+17
-7
lines changed

src/path.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,14 @@ static int win32_prefix_length(const char *path, int len)
125125
* 'C:/' here
126126
*/
127127
if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path))
128-
return 3;
128+
return 2;
129129

130130
/*
131131
* Similarly checks if we're dealing with a network computer name
132132
* '//computername/.git' will return '//computername/'
133133
*/
134134
if (looks_like_network_computer_name(path, len))
135-
return len + 1;
135+
return len;
136136
#endif
137137

138138
return -1;
@@ -145,7 +145,7 @@ static int win32_prefix_length(const char *path, int len)
145145
int git_path_dirname_r(git_buf *buffer, const char *path)
146146
{
147147
const char *endp;
148-
int len;
148+
int is_prefix = 0, len;
149149

150150
/* Empty or NULL string gets treated as "." */
151151
if (path == NULL || *path == '\0') {
@@ -159,8 +159,10 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
159159
while (endp > path && *endp == '/')
160160
endp--;
161161

162-
if ((len = win32_prefix_length(path, endp - path + 1)) > 0)
162+
if ((len = win32_prefix_length(path, endp - path + 1)) > 0) {
163+
is_prefix = 1;
163164
goto Exit;
165+
}
164166

165167
/* Find the start of the dir */
166168
while (endp > path && *endp != '/')
@@ -177,15 +179,21 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
177179
endp--;
178180
} while (endp > path && *endp == '/');
179181

180-
if ((len = win32_prefix_length(path, endp - path + 1)) > 0)
182+
if ((len = win32_prefix_length(path, endp - path + 1)) > 0) {
183+
is_prefix = 1;
181184
goto Exit;
185+
}
182186

183187
/* Cast is safe because max path < max int */
184188
len = (int)(endp - path + 1);
185189

186190
Exit:
187-
if (buffer != NULL && git_buf_set(buffer, path, len) < 0)
188-
return -1;
191+
if (buffer) {
192+
if (git_buf_set(buffer, path, len) < 0)
193+
return -1;
194+
if (is_prefix && git_buf_putc(buffer, '/') < 0)
195+
return -1;
196+
}
189197

190198
return len;
191199
}

tests/core/path.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,11 @@ void test_core_path__00_dirname(void)
9090

9191
#ifdef GIT_WIN32
9292
check_dirname("C:/", "C:/");
93+
check_dirname("C:", "C:/");
9394
check_dirname("C:/path/", "C:/");
9495
check_dirname("C:/path", "C:/");
9596
check_dirname("//computername/", "//computername/");
97+
check_dirname("//computername", "//computername/");
9698
check_dirname("//computername/path/", "//computername/");
9799
check_dirname("//computername/path", "//computername/");
98100
check_dirname("//computername/sub/path/", "//computername/sub");

0 commit comments

Comments
 (0)