From 9e8d75c7d447531d81133bf880c1a5f45a45c340 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Wed, 8 Feb 2017 11:41:10 +0100 Subject: [PATCH] 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 '/'. --- src/path.c | 22 +++++++++++++++------- tests/core/path.c | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/path.c b/src/path.c index 3c78c8b7c..c3d3eb1ce 100644 --- a/src/path.c +++ b/src/path.c @@ -125,14 +125,14 @@ static int win32_prefix_length(const char *path, int len) * 'C:/' here */ if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX(path)) - return 3; + return 2; /* * Similarly checks if we're dealing with a network computer name * '//computername/.git' will return '//computername/' */ if (looks_like_network_computer_name(path, len)) - return len + 1; + return len; #endif return -1; @@ -145,7 +145,7 @@ static int win32_prefix_length(const char *path, int len) int git_path_dirname_r(git_buf *buffer, const char *path) { const char *endp; - int len; + int is_prefix = 0, len; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { @@ -159,8 +159,10 @@ int git_path_dirname_r(git_buf *buffer, const char *path) while (endp > path && *endp == '/') endp--; - if ((len = win32_prefix_length(path, endp - path + 1)) > 0) + if ((len = win32_prefix_length(path, endp - path + 1)) > 0) { + is_prefix = 1; goto Exit; + } /* Find the start of the dir */ while (endp > path && *endp != '/') @@ -177,15 +179,21 @@ int git_path_dirname_r(git_buf *buffer, const char *path) endp--; } while (endp > path && *endp == '/'); - if ((len = win32_prefix_length(path, endp - path + 1)) > 0) + if ((len = win32_prefix_length(path, endp - path + 1)) > 0) { + is_prefix = 1; goto Exit; + } /* Cast is safe because max path < max int */ len = (int)(endp - path + 1); Exit: - if (buffer != NULL && git_buf_set(buffer, path, len) < 0) - return -1; + if (buffer) { + if (git_buf_set(buffer, path, len) < 0) + return -1; + if (is_prefix && git_buf_putc(buffer, '/') < 0) + return -1; + } return len; } diff --git a/tests/core/path.c b/tests/core/path.c index eaaaf7245..fefe2aeac 100644 --- a/tests/core/path.c +++ b/tests/core/path.c @@ -90,9 +90,11 @@ void test_core_path__00_dirname(void) #ifdef GIT_WIN32 check_dirname("C:/", "C:/"); + check_dirname("C:", "C:/"); check_dirname("C:/path/", "C:/"); check_dirname("C:/path", "C:/"); check_dirname("//computername/", "//computername/"); + check_dirname("//computername", "//computername/"); check_dirname("//computername/path/", "//computername/"); check_dirname("//computername/path", "//computername/"); check_dirname("//computername/sub/path/", "//computername/sub");