@@ -110,14 +110,42 @@ int git_path_basename_r(git_buf *buffer, const char *path)
110110 return result ;
111111}
112112
113+ /*
114+ * Determine if the path is a Windows prefix and, if so, returns
115+ * its actual lentgh. If it is not a prefix, returns -1.
116+ */
117+ static int win32_prefix_length (const char * path , int len )
118+ {
119+ #ifndef GIT_WIN32
120+ GIT_UNUSED (path );
121+ GIT_UNUSED (len );
122+ #else
123+ /*
124+ * Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return
125+ * 'C:/' here
126+ */
127+ if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX (path ))
128+ return 2 ;
129+
130+ /*
131+ * Similarly checks if we're dealing with a network computer name
132+ * '//computername/.git' will return '//computername/'
133+ */
134+ if (looks_like_network_computer_name (path , len ))
135+ return len ;
136+ #endif
137+
138+ return -1 ;
139+ }
140+
113141/*
114142 * Based on the Android implementation, BSD licensed.
115143 * Check http://android.git.kernel.org/
116144 */
117145int git_path_dirname_r (git_buf * buffer , const char * path )
118146{
119147 const char * endp ;
120- int result , len ;
148+ int is_prefix = 0 , len ;
121149
122150 /* Empty or NULL string gets treated as "." */
123151 if (path == NULL || * path == '\0' ) {
@@ -131,6 +159,11 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
131159 while (endp > path && * endp == '/' )
132160 endp -- ;
133161
162+ if ((len = win32_prefix_length (path , endp - path + 1 )) > 0 ) {
163+ is_prefix = 1 ;
164+ goto Exit ;
165+ }
166+
134167 /* Find the start of the dir */
135168 while (endp > path && * endp != '/' )
136169 endp -- ;
@@ -146,35 +179,23 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
146179 endp -- ;
147180 } while (endp > path && * endp == '/' );
148181
149- /* Cast is safe because max path < max int */
150- len = (int )(endp - path + 1 );
151-
152- #ifdef GIT_WIN32
153- /* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return
154- 'C:/' here */
155-
156- if (len == 2 && LOOKS_LIKE_DRIVE_PREFIX (path )) {
157- len = 3 ;
182+ if ((len = win32_prefix_length (path , endp - path + 1 )) > 0 ) {
183+ is_prefix = 1 ;
158184 goto Exit ;
159185 }
160186
161- /* Similarly checks if we're dealing with a network computer name
162- '//computername/.git' will return '//computername/' */
163-
164- if (looks_like_network_computer_name (path , len )) {
165- len ++ ;
166- goto Exit ;
167- }
168-
169- #endif
187+ /* Cast is safe because max path < max int */
188+ len = (int )(endp - path + 1 );
170189
171190Exit :
172- result = len ;
173-
174- if (buffer != NULL && git_buf_set (buffer , path , len ) < 0 )
175- 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+ }
176197
177- return result ;
198+ return len ;
178199}
179200
180201
0 commit comments