Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
c2c81615
Commit
c2c81615
authored
Apr 19, 2014
by
Philip Kelley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Win32: UTF-8 <-> WCHAR conversion overhaul
parent
bfc50f83
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
659 additions
and
431 deletions
+659
-431
src/path.c
+26
-25
src/repository.c
+7
-3
src/transports/winhttp.c
+50
-75
src/unix/posix.h
+0
-1
src/win32/dir.c
+4
-23
src/win32/dir.h
+2
-1
src/win32/error.c
+5
-31
src/win32/findfile.c
+37
-56
src/win32/findfile.h
+0
-11
src/win32/mingw-compat.h
+2
-0
src/win32/posix.h
+1
-10
src/win32/posix_w32.c
+205
-151
src/win32/utf-conv.c
+130
-3
src/win32/utf-conv.h
+66
-10
src/win32/w32_util.c
+69
-0
src/win32/w32_util.h
+31
-0
tests/clar_libgit2.c
+23
-30
tests/core/env.c
+1
-1
No files found.
src/path.c
View file @
c2c81615
...
...
@@ -9,6 +9,7 @@
#include "posix.h"
#ifdef GIT_WIN32
#include "win32/posix.h"
#include "win32/w32_util.h"
#else
#include <dirent.h>
#endif
...
...
@@ -486,33 +487,33 @@ bool git_path_isfile(const char *path)
bool
git_path_is_empty_dir
(
const
char
*
path
)
{
HANDLE
hFind
=
INVALID_HANDLE_VALUE
;
git_win32_path
wbuf
;
int
wbufsz
;
WIN32_FIND_DATAW
ffd
;
bool
retval
=
true
;
if
(
!
git_path_isdir
(
path
))
return
false
;
wbufsz
=
git_win32_path_from_c
(
wbuf
,
path
);
if
(
!
wbufsz
||
wbufsz
+
2
>
GIT_WIN_PATH_UTF16
)
return
false
;
memcpy
(
&
wbuf
[
wbufsz
-
1
],
L"
\\
*"
,
3
*
sizeof
(
wchar_t
));
hFind
=
FindFirstFileW
(
wbuf
,
&
ffd
);
if
(
INVALID_HANDLE_VALUE
==
hFind
)
return
false
;
do
{
if
(
!
git_path_is_dot_or_dotdotW
(
ffd
.
cFileName
))
{
retval
=
false
;
break
;
git_win32_path
filter_w
;
bool
empty
=
false
;
if
(
git_win32__findfirstfile_filter
(
filter_w
,
path
))
{
WIN32_FIND_DATAW
findData
;
HANDLE
hFind
=
FindFirstFileW
(
filter_w
,
&
findData
);
/* If the find handle was created successfully, then it's a directory */
if
(
INVALID_HANDLE_VALUE
!=
hFind
)
{
empty
=
true
;
do
{
/* Allow the enumeration to return . and .. and still be considered
* empty. In the special case of drive roots (i.e. C:\) where . and
* .. do not occur, we can still consider the path to be an empty
* directory if there's nothing there. */
if
(
!
git_path_is_dot_or_dotdotW
(
findData
.
cFileName
))
{
empty
=
false
;
break
;
}
}
while
(
FindNextFileW
(
hFind
,
&
findData
));
FindClose
(
hFind
);
}
}
while
(
FindNextFileW
(
hFind
,
&
ffd
)
!=
0
);
}
FindClose
(
hFind
);
return
retval
;
return
empty
;
}
#else
...
...
src/repository.c
View file @
c2c81615
...
...
@@ -27,6 +27,10 @@
#include "merge.h"
#include "diff_driver.h"
#ifdef GIT_WIN32
# include "win32/w32_util.h"
#endif
#define GIT_FILE_CONTENT_PREFIX "gitdir:"
#define GIT_BRANCH_MASTER "master"
...
...
@@ -1149,7 +1153,7 @@ static int repo_write_template(
#ifdef GIT_WIN32
if
(
!
error
&&
hidden
)
{
if
(
p_hide_directory__w32
(
path
.
ptr
)
<
0
)
if
(
git_win32__sethidden
(
path
.
ptr
)
<
0
)
error
=
-
1
;
}
#else
...
...
@@ -1234,8 +1238,8 @@ static int repo_init_structure(
/* Hide the ".git" directory */
#ifdef GIT_WIN32
if
((
opts
->
flags
&
GIT_REPOSITORY_INIT__HAS_DOTGIT
)
!=
0
)
{
if
(
p_hide_directory__w32
(
repo_dir
)
<
0
)
{
giterr_set
(
GITERR_
REPOSITORY
,
if
(
git_win32__sethidden
(
repo_dir
)
<
0
)
{
giterr_set
(
GITERR_
OS
,
"Failed to mark Git repository folder as hidden"
);
return
-
1
;
}
...
...
src/transports/winhttp.c
View file @
c2c81615
...
...
@@ -91,7 +91,7 @@ static int apply_basic_credential(HINTERNET request, git_cred *cred)
git_cred_userpass_plaintext
*
c
=
(
git_cred_userpass_plaintext
*
)
cred
;
git_buf
buf
=
GIT_BUF_INIT
,
raw
=
GIT_BUF_INIT
;
wchar_t
*
wide
=
NULL
;
int
error
=
-
1
,
wide_len
=
0
;
int
error
=
-
1
,
wide_len
;
git_buf_printf
(
&
raw
,
"%s:%s"
,
c
->
username
,
c
->
password
);
...
...
@@ -100,21 +100,7 @@ static int apply_basic_credential(HINTERNET request, git_cred *cred)
git_buf_put_base64
(
&
buf
,
git_buf_cstr
(
&
raw
),
raw
.
size
)
<
0
)
goto
on_error
;
wide_len
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
git_buf_cstr
(
&
buf
),
-
1
,
NULL
,
0
);
if
(
!
wide_len
)
{
giterr_set
(
GITERR_OS
,
"Failed to measure string for wide conversion"
);
goto
on_error
;
}
wide
=
git__malloc
(
wide_len
*
sizeof
(
wchar_t
));
if
(
!
wide
)
goto
on_error
;
if
(
!
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
git_buf_cstr
(
&
buf
),
-
1
,
wide
,
wide_len
))
{
if
((
wide_len
=
git__utf8_to_16_alloc
(
&
wide
,
git_buf_cstr
(
&
buf
)))
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to convert string to wide form"
);
goto
on_error
;
}
...
...
@@ -171,23 +157,11 @@ static int fallback_cred_acquire_cb(
/* If the target URI supports integrated Windows authentication
* as an authentication mechanism */
if
(
GIT_CREDTYPE_DEFAULT
&
allowed_types
)
{
LPWSTR
wide_url
;
DWORD
wide_len
;
wchar_t
*
wide_url
;
/* Convert URL to wide characters */
wide_len
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
url
,
-
1
,
NULL
,
0
);
if
(
!
wide_len
)
{
giterr_set
(
GITERR_OS
,
"Failed to measure string for wide conversion"
);
return
-
1
;
}
wide_url
=
git__malloc
(
wide_len
*
sizeof
(
WCHAR
));
GITERR_CHECK_ALLOC
(
wide_url
);
if
(
!
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
url
,
-
1
,
wide_url
,
wide_len
))
{
if
(
git__utf8_to_16_alloc
(
&
wide_url
,
url
)
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to convert string to wide form"
);
git__free
(
wide_url
);
return
-
1
;
}
...
...
@@ -232,7 +206,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
wchar_t
ct
[
MAX_CONTENT_TYPE_LEN
];
wchar_t
*
types
[]
=
{
L"*/*"
,
NULL
};
BOOL
peerdist
=
FALSE
;
int
error
=
-
1
,
wide_len
;
int
error
=
-
1
;
unsigned
long
disable_redirects
=
WINHTTP_DISABLE_REDIRECTS
;
/* Prepare URL */
...
...
@@ -242,21 +216,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
return
-
1
;
/* Convert URL to wide characters */
wide_len
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
git_buf_cstr
(
&
buf
),
-
1
,
NULL
,
0
);
if
(
!
wide_len
)
{
giterr_set
(
GITERR_OS
,
"Failed to measure string for wide conversion"
);
goto
on_error
;
}
s
->
request_uri
=
git__malloc
(
wide_len
*
sizeof
(
wchar_t
));
if
(
!
s
->
request_uri
)
goto
on_error
;
if
(
!
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
git_buf_cstr
(
&
buf
),
-
1
,
s
->
request_uri
,
wide_len
))
{
if
(
git__utf8_to_16_alloc
(
&
s
->
request_uri
,
git_buf_cstr
(
&
buf
))
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to convert string to wide form"
);
goto
on_error
;
}
...
...
@@ -285,30 +245,17 @@ static int winhttp_stream_connect(winhttp_stream *s)
wchar_t
*
proxy_wide
;
/* Convert URL to wide characters */
wide_len
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
proxy_url
,
-
1
,
NULL
,
0
);
if
(
!
wide_len
)
{
giterr_set
(
GITERR_OS
,
"Failed to measure string for wide conversion"
);
goto
on_error
;
}
proxy_wide
=
git__malloc
(
wide_len
*
sizeof
(
wchar_t
));
if
(
!
proxy_wide
)
goto
on_error
;
int
proxy_wide_len
=
git__utf8_to_16_alloc
(
&
proxy_wide
,
proxy_url
);
if
(
!
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
proxy_url
,
-
1
,
proxy_wide
,
wide_len
))
{
if
(
proxy_wide_len
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to convert string to wide form"
);
git__free
(
proxy_wide
);
goto
on_error
;
}
/* Strip any trailing forward slash on the proxy URL;
* WinHTTP doesn't like it if one is present */
if
(
wide_len
>
1
&&
L'/'
==
proxy_wide
[
wide_len
-
2
])
proxy_wide
[
wide_len
-
2
]
=
L'\0'
;
if
(
proxy_wide_len
>
1
&&
L'/'
==
proxy_wide
[
proxy_
wide_len
-
2
])
proxy_wide
[
proxy_
wide_len
-
2
]
=
L'\0'
;
proxy_info
.
dwAccessType
=
WINHTTP_ACCESS_TYPE_NAMED_PROXY
;
proxy_info
.
lpszProxy
=
proxy_wide
;
...
...
@@ -359,7 +306,10 @@ static int winhttp_stream_connect(winhttp_stream *s)
s
->
service
)
<
0
)
goto
on_error
;
git__utf8_to_16
(
ct
,
MAX_CONTENT_TYPE_LEN
,
git_buf_cstr
(
&
buf
));
if
(
git__utf8_to_16
(
ct
,
MAX_CONTENT_TYPE_LEN
,
git_buf_cstr
(
&
buf
))
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to convert content-type to wide characters"
);
goto
on_error
;
}
if
(
!
WinHttpAddRequestHeaders
(
s
->
request
,
ct
,
(
ULONG
)
-
1L
,
WINHTTP_ADDREQ_FLAG_ADD
|
WINHTTP_ADDREQ_FLAG_REPLACE
))
{
...
...
@@ -373,7 +323,10 @@ static int winhttp_stream_connect(winhttp_stream *s)
s
->
service
)
<
0
)
goto
on_error
;
git__utf8_to_16
(
ct
,
MAX_CONTENT_TYPE_LEN
,
git_buf_cstr
(
&
buf
));
if
(
git__utf8_to_16
(
ct
,
MAX_CONTENT_TYPE_LEN
,
git_buf_cstr
(
&
buf
))
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to convert accept header to wide characters"
);
goto
on_error
;
}
if
(
!
WinHttpAddRequestHeaders
(
s
->
request
,
ct
,
(
ULONG
)
-
1L
,
WINHTTP_ADDREQ_FLAG_ADD
|
WINHTTP_ADDREQ_FLAG_REPLACE
))
{
...
...
@@ -506,16 +459,20 @@ static int winhttp_connect(
const
char
*
url
)
{
wchar_t
*
ua
=
L"git/1.0 (libgit2 "
WIDEN
(
LIBGIT2_VERSION
)
L")"
;
git_win32_path
host
;
wchar_t
*
wide_
host
;
int32_t
port
;
const
char
*
default_port
=
"80"
;
int
error
=
-
1
;
/* Prepare port */
if
(
git__strtol32
(
&
port
,
t
->
connection_data
.
port
,
NULL
,
10
)
<
0
)
return
-
1
;
/* Prepare host */
git_win32_path_from_c
(
host
,
t
->
connection_data
.
host
);
if
(
git__utf8_to_16_alloc
(
&
wide_host
,
t
->
connection_data
.
host
)
<
0
)
{
giterr_set
(
GITERR_OS
,
"Unable to convert host to wide characters"
);
return
-
1
;
}
/* Establish session */
t
->
session
=
WinHttpOpen
(
...
...
@@ -527,22 +484,27 @@ static int winhttp_connect(
if
(
!
t
->
session
)
{
giterr_set
(
GITERR_OS
,
"Failed to init WinHTTP"
);
return
-
1
;
goto
on_error
;
}
/* Establish connection */
t
->
connection
=
WinHttpConnect
(
t
->
session
,
host
,
wide_
host
,
(
INTERNET_PORT
)
port
,
0
);
if
(
!
t
->
connection
)
{
giterr_set
(
GITERR_OS
,
"Failed to connect to host"
);
return
-
1
;
goto
on_error
;
}
return
0
;
error
=
0
;
on_error:
git__free
(
wide_host
);
return
error
;
}
static
int
winhttp_stream_read
(
...
...
@@ -693,7 +655,6 @@ replay:
}
location
=
git__malloc
(
location_length
);
location8
=
git__malloc
(
location_length
);
GITERR_CHECK_ALLOC
(
location
);
if
(
!
WinHttpQueryHeaders
(
s
->
request
,
...
...
@@ -706,7 +667,14 @@ replay:
git__free
(
location
);
return
-
1
;
}
git__utf16_to_8
(
location8
,
location_length
,
location
);
/* Convert the Location header to UTF-8 */
if
(
git__utf16_to_8_alloc
(
&
location8
,
location
)
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to convert Location header to UTF-8"
);
git__free
(
location
);
return
-
1
;
}
git__free
(
location
);
/* Replay the request */
...
...
@@ -716,8 +684,11 @@ replay:
if
(
!
git__prefixcmp_icase
(
location8
,
prefix_https
))
{
/* Upgrade to secure connection; disconnect and start over */
if
(
gitno_connection_data_from_url
(
&
t
->
connection_data
,
location8
,
s
->
service_url
)
<
0
)
if
(
gitno_connection_data_from_url
(
&
t
->
connection_data
,
location8
,
s
->
service_url
)
<
0
)
{
git__free
(
location8
);
return
-
1
;
}
winhttp_connect
(
t
,
location8
);
}
...
...
@@ -778,7 +749,11 @@ replay:
else
snprintf
(
expected_content_type_8
,
MAX_CONTENT_TYPE_LEN
,
"application/x-git-%s-advertisement"
,
s
->
service
);
git__utf8_to_16
(
expected_content_type
,
MAX_CONTENT_TYPE_LEN
,
expected_content_type_8
);
if
(
git__utf8_to_16
(
expected_content_type
,
MAX_CONTENT_TYPE_LEN
,
expected_content_type_8
)
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to convert expected content-type to wide characters"
);
return
-
1
;
}
content_type_length
=
sizeof
(
content_type
);
if
(
!
WinHttpQueryHeaders
(
s
->
request
,
...
...
src/unix/posix.h
View file @
c2c81615
...
...
@@ -28,7 +28,6 @@ char *p_realpath(const char *, char *);
#define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a)
#define p_snprintf(b, c, f, ...) snprintf(b, c, f, __VA_ARGS__)
#define p_mkstemp(p) mkstemp(p)
#define p_setenv(n,v,o) setenv(n,v,o)
#define p_inet_pton(a, b, c) inet_pton(a, b, c)
/* see win32/posix.h for explanation about why this exists */
...
...
src/win32/dir.c
View file @
c2c81615
...
...
@@ -7,29 +7,13 @@
#define GIT__WIN32_NO_WRAP_DIR
#include "posix.h"
static
int
init_filter
(
char
*
filter
,
size_t
n
,
const
char
*
dir
)
{
size_t
len
=
strlen
(
dir
);
if
(
len
+
3
>=
n
)
return
0
;
strcpy
(
filter
,
dir
);
if
(
len
&&
dir
[
len
-
1
]
!=
'/'
)
strcat
(
filter
,
"/"
);
strcat
(
filter
,
"*"
);
return
1
;
}
git__DIR
*
git__opendir
(
const
char
*
dir
)
{
git_win32_path_as_utf8
filter
;
git_win32_path
filter_w
;
git__DIR
*
new
=
NULL
;
size_t
dirlen
;
if
(
!
dir
||
!
init_filter
(
filter
,
sizeof
(
filter
)
,
dir
))
if
(
!
dir
||
!
git_win32__findfirstfile_filter
(
filter_w
,
dir
))
return
NULL
;
dirlen
=
strlen
(
dir
);
...
...
@@ -39,7 +23,6 @@ git__DIR *git__opendir(const char *dir)
return
NULL
;
memcpy
(
new
->
dir
,
dir
,
dirlen
);
git_win32_path_from_c
(
filter_w
,
filter
);
new
->
h
=
FindFirstFileW
(
filter_w
,
&
new
->
f
);
if
(
new
->
h
==
INVALID_HANDLE_VALUE
)
{
...
...
@@ -72,10 +55,10 @@ int git__readdir_ext(
return
-
1
;
}
if
(
wcslen
(
d
->
f
.
cFileName
)
>=
sizeof
(
entry
->
d_name
))
/* Convert the path to UTF-8 */
if
(
git_win32_path_to_utf8
(
entry
->
d_name
,
d
->
f
.
cFileName
)
<
0
)
return
-
1
;
git_win32_path_to_c
(
entry
->
d_name
,
d
->
f
.
cFileName
);
entry
->
d_ino
=
0
;
*
result
=
entry
;
...
...
@@ -96,7 +79,6 @@ struct git__dirent *git__readdir(git__DIR *d)
void
git__rewinddir
(
git__DIR
*
d
)
{
git_win32_path_as_utf8
filter
;
git_win32_path
filter_w
;
if
(
!
d
)
...
...
@@ -108,10 +90,9 @@ void git__rewinddir(git__DIR *d)
d
->
first
=
0
;
}
if
(
!
init_filter
(
filter
,
sizeof
(
filter
)
,
d
->
dir
))
if
(
!
git_win32__findfirstfile_filter
(
filter_w
,
d
->
dir
))
return
;
git_win32_path_from_c
(
filter_w
,
filter
);
d
->
h
=
FindFirstFileW
(
filter_w
,
&
d
->
f
);
if
(
d
->
h
==
INVALID_HANDLE_VALUE
)
...
...
src/win32/dir.h
View file @
c2c81615
...
...
@@ -8,10 +8,11 @@
#define INCLUDE_dir_h__
#include "common.h"
#include "w32_util.h"
struct
git__dirent
{
int
d_ino
;
git_win32_
path_as_utf8
d_name
;
git_win32_
utf8_path
d_name
;
};
typedef
struct
{
...
...
src/win32/error.c
View file @
c2c81615
...
...
@@ -7,21 +7,17 @@
#include "common.h"
#include "error.h"
#include "utf-conv.h"
#ifdef GIT_WINHTTP
# include <winhttp.h>
#endif
#ifndef WC_ERR_INVALID_CHARS
#define WC_ERR_INVALID_CHARS 0x80
#endif
char
*
git_win32_get_error_message
(
DWORD
error_code
)
{
LPWSTR
lpMsgBuf
=
NULL
;
HMODULE
hModule
=
NULL
;
char
*
utf8_msg
=
NULL
;
int
utf8_size
;
DWORD
dwFlags
=
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_IGNORE_INSERTS
;
...
...
@@ -45,33 +41,11 @@ char *git_win32_get_error_message(DWORD error_code)
if
(
FormatMessageW
(
dwFlags
,
hModule
,
error_code
,
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
(
LPWSTR
)
&
lpMsgBuf
,
0
,
NULL
))
{
/* Convert the message to UTF-8. If this fails, we will
* return NULL, which is a condition expected by the caller */
if
(
git__utf16_to_8_alloc
(
&
utf8_msg
,
lpMsgBuf
)
<
0
)
utf8_msg
=
NULL
;
/* Invalid code point check supported on Vista+ only */
if
(
git_has_win32_version
(
6
,
0
,
0
))
dwFlags
=
WC_ERR_INVALID_CHARS
;
else
dwFlags
=
0
;
utf8_size
=
WideCharToMultiByte
(
CP_UTF8
,
dwFlags
,
lpMsgBuf
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
if
(
!
utf8_size
)
{
assert
(
0
);
goto
on_error
;
}
utf8_msg
=
git__malloc
(
utf8_size
);
if
(
!
utf8_msg
)
goto
on_error
;
if
(
!
WideCharToMultiByte
(
CP_UTF8
,
dwFlags
,
lpMsgBuf
,
-
1
,
utf8_msg
,
utf8_size
,
NULL
,
NULL
))
{
git__free
(
utf8_msg
);
goto
on_error
;
}
on_error:
LocalFree
(
lpMsgBuf
);
}
...
...
src/win32/findfile.c
View file @
c2c81615
...
...
@@ -17,54 +17,34 @@
#define REG_MSYSGIT_INSTALL L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1"
#endif
int
git_win32__expand_path
(
struct
git_win32__path
*
s_root
,
const
wchar_t
*
templ
)
{
s_root
->
len
=
ExpandEnvironmentStringsW
(
templ
,
s_root
->
path
,
MAX_PATH
);
return
s_root
->
len
?
0
:
-
1
;
}
typedef
struct
{
git_win32_path
path
;
DWORD
len
;
}
_findfile_path
;
static
int
win32_path_to_8
(
git_buf
*
path_utf8
,
const
wchar_t
*
path
)
static
int
git_win32__expand_path
(
_findfile_path
*
dest
,
const
wchar_t
*
src
)
{
char
temp_utf8
[
GIT_PATH_MAX
]
;
dest
->
len
=
ExpandEnvironmentStringsW
(
src
,
dest
->
path
,
ARRAY_SIZE
(
dest
->
path
))
;
git__utf16_to_8
(
temp_utf8
,
GIT_PATH_MAX
,
path
);
git_path_mkposix
(
temp_utf8
)
;
if
(
!
dest
->
len
||
dest
->
len
>
ARRAY_SIZE
(
dest
->
path
))
return
-
1
;
return
git_buf_sets
(
path_utf8
,
temp_utf8
)
;
return
0
;
}
int
git_win32__find_file
(
git_buf
*
path
,
const
struct
git_win32__path
*
root
,
const
char
*
filename
)
static
int
win32_path_to_8
(
git_buf
*
dest
,
const
wchar_t
*
src
)
{
size_t
len
,
alloc_len
;
wchar_t
*
file_utf16
=
NULL
;
if
(
!
root
||
!
filename
||
(
len
=
strlen
(
filename
))
==
0
)
return
GIT_ENOTFOUND
;
/* allocate space for wchar_t path to file */
alloc_len
=
root
->
len
+
len
+
2
;
file_utf16
=
git__calloc
(
alloc_len
,
sizeof
(
wchar_t
));
GITERR_CHECK_ALLOC
(
file_utf16
);
git_win32_utf8_path
utf8_path
;
/* append root + '\\' + filename as wchar_t */
memcpy
(
file_utf16
,
root
->
path
,
root
->
len
*
sizeof
(
wchar_t
));
if
(
*
filename
==
'/'
||
*
filename
==
'\\'
)
filename
++
;
git__utf8_to_16
(
file_utf16
+
root
->
len
-
1
,
alloc_len
-
root
->
len
,
filename
);
/* check access */
if
(
_waccess
(
file_utf16
,
F_OK
)
<
0
)
{
git__free
(
file_utf16
);
return
GIT_ENOTFOUND
;
if
(
git_win32_path_to_utf8
(
utf8_path
,
src
)
<
0
)
{
giterr_set
(
GITERR_OS
,
"Unable to convert path to UTF-8"
);
return
-
1
;
}
win32_path_to_8
(
path
,
file_utf16
);
git_
_free
(
file_utf16
);
/* Convert backslashes to forward slashes */
git_
path_mkposix
(
utf8_path
);
return
0
;
return
git_buf_sets
(
dest
,
utf8_path
)
;
}
static
wchar_t
*
win32_walkpath
(
wchar_t
*
path
,
wchar_t
*
buf
,
size_t
buflen
)
...
...
@@ -89,7 +69,7 @@ static wchar_t* win32_walkpath(wchar_t *path, wchar_t *buf, size_t buflen)
static
int
win32_find_git_in_path
(
git_buf
*
buf
,
const
wchar_t
*
gitexe
,
const
wchar_t
*
subdir
)
{
wchar_t
*
env
=
_wgetenv
(
L"PATH"
),
lastch
;
struct
git_win32_
_path
root
;
_findfile
_path
root
;
size_t
gitexe_len
=
wcslen
(
gitexe
);
if
(
!
env
)
...
...
@@ -122,43 +102,44 @@ static int win32_find_git_in_path(git_buf *buf, const wchar_t *gitexe, const wch
}
static
int
win32_find_git_in_registry
(
git_buf
*
buf
,
const
HKEY
hi
e
ve
,
const
wchar_t
*
key
,
const
wchar_t
*
subdir
)
git_buf
*
buf
,
const
HKEY
hive
,
const
wchar_t
*
key
,
const
wchar_t
*
subdir
)
{
HKEY
hKey
;
DWORD
dwType
=
REG_SZ
;
struct
git_win32__path
path16
;
int
error
=
GIT_ENOTFOUND
;
assert
(
buf
);
path16
.
len
=
MAX_PATH
;
if
(
!
RegOpenKeyExW
(
hive
,
key
,
0
,
KEY_READ
,
&
hKey
))
{
DWORD
dwType
,
cbData
;
git_win32_path
path
;
if
(
RegOpenKeyExW
(
hieve
,
key
,
0
,
KEY_READ
,
&
hKey
)
==
ERROR_SUCCESS
)
{
if
(
RegQueryValueExW
(
hKey
,
L"InstallLocation"
,
NULL
,
&
dwType
,
(
LPBYTE
)
&
path16
.
path
,
&
path16
.
len
)
==
ERROR_SUCCESS
)
{
/* InstallLocation points to the root of the git directory */
/* Ensure that the buffer is big enough to have the suffix attached
* after we receive the result. */
cbData
=
(
DWORD
)(
sizeof
(
path
)
-
wcslen
(
subdir
)
*
sizeof
(
wchar_t
));
if
(
path16
.
len
+
4
>
MAX_PATH
)
{
/* 4 = wcslen(L"etc\\") */
giterr_set
(
GITERR_OS
,
"Cannot locate git - path too long"
);
return
-
1
;
}
/* InstallLocation points to the root of the git directory */
if
(
!
RegQueryValueExW
(
hKey
,
L"InstallLocation"
,
NULL
,
&
dwType
,
(
LPBYTE
)
path
,
&
cbData
)
&&
REG_SZ
==
dwType
)
{
wcscat
(
path16
.
path
,
subdir
);
path16
.
len
+=
4
;
/* Append the suffix */
wcscat
(
path
,
subdir
)
;
win32_path_to_8
(
buf
,
path16
.
path
);
/* Convert to UTF-8, with forward slashes, and output the path
* to the provided buffer */
if
(
!
win32_path_to_8
(
buf
,
path
))
error
=
0
;
}
RegCloseKey
(
hKey
);
}
return
path16
.
len
?
0
:
GIT_ENOTFOUND
;
return
error
;
}
static
int
win32_find_existing_dirs
(
git_buf
*
out
,
const
wchar_t
*
tmpl
[])
{
struct
git_win32_
_path
path16
;
_findfile
_path
path16
;
git_buf
buf
=
GIT_BUF_INIT
;
git_buf_clear
(
out
);
...
...
src/win32/findfile.h
View file @
c2c81615
...
...
@@ -8,17 +8,6 @@
#ifndef INCLUDE_git_findfile_h__
#define INCLUDE_git_findfile_h__
struct
git_win32__path
{
wchar_t
path
[
MAX_PATH
];
DWORD
len
;
};
extern
int
git_win32__expand_path
(
struct
git_win32__path
*
s_root
,
const
wchar_t
*
templ
);
extern
int
git_win32__find_file
(
git_buf
*
path
,
const
struct
git_win32__path
*
root
,
const
char
*
filename
);
extern
int
git_win32__find_system_dirs
(
git_buf
*
out
,
const
wchar_t
*
subpath
);
extern
int
git_win32__find_global_dirs
(
git_buf
*
out
);
extern
int
git_win32__find_xdg_dirs
(
git_buf
*
out
);
...
...
src/win32/mingw-compat.h
View file @
c2c81615
...
...
@@ -11,7 +11,9 @@
/* use a 64-bit file offset type */
# define lseek _lseeki64
# undef stat
# define stat _stati64
# undef fstat
# define fstat _fstati64
/* stat: file mode type testing macros */
...
...
src/win32/posix.h
View file @
c2c81615
...
...
@@ -27,24 +27,15 @@ GIT_INLINE(int) p_link(const char *old, const char *new)
return
-
1
;
}
GIT_INLINE
(
int
)
p_mkdir
(
const
char
*
path
,
mode_t
mode
)
{
git_win32_path
buf
;
GIT_UNUSED
(
mode
);
git_win32_path_from_c
(
buf
,
path
);
return
_wmkdir
(
buf
);
}
extern
int
p_mkdir
(
const
char
*
path
,
mode_t
mode
);
extern
int
p_unlink
(
const
char
*
path
);
extern
int
p_lstat
(
const
char
*
file_name
,
struct
stat
*
buf
);
extern
int
p_readlink
(
const
char
*
link
,
char
*
target
,
size_t
target_len
);
extern
int
p_symlink
(
const
char
*
old
,
const
char
*
new
);
extern
int
p_hide_directory__w32
(
const
char
*
path
);
extern
char
*
p_realpath
(
const
char
*
orig_path
,
char
*
buffer
);
extern
int
p_vsnprintf
(
char
*
buffer
,
size_t
count
,
const
char
*
format
,
va_list
argptr
);
extern
int
p_snprintf
(
char
*
buffer
,
size_t
count
,
const
char
*
format
,
...)
GIT_FORMAT_PRINTF
(
3
,
4
);
extern
int
p_mkstemp
(
char
*
tmp_path
);
extern
int
p_setenv
(
const
char
*
name
,
const
char
*
value
,
int
overwrite
);
extern
int
p_stat
(
const
char
*
path
,
struct
stat
*
buf
);
extern
int
p_chdir
(
const
char
*
path
);
extern
int
p_chmod
(
const
char
*
path
,
mode_t
mode
);
...
...
src/win32/posix_w32.c
View file @
c2c81615
...
...
@@ -14,12 +14,59 @@
#include <fcntl.h>
#include <ws2tcpip.h>
#if defined(__MINGW32__)
# define FILE_NAME_NORMALIZED 0
#endif
/* GetFinalPathNameByHandleW signature */
typedef
DWORD
(
WINAPI
*
PFGetFinalPathNameByHandleW
)(
HANDLE
,
LPWSTR
,
DWORD
,
DWORD
);
/* Helper function which converts UTF-8 paths to UTF-16.
* On failure, errno is set. */
static
int
utf8_to_16_with_errno
(
git_win32_path
dest
,
const
char
*
src
)
{
int
len
=
git_win32_path_from_utf8
(
dest
,
src
);
if
(
len
<
0
)
{
if
(
GetLastError
()
==
ERROR_INSUFFICIENT_BUFFER
)
errno
=
ENAMETOOLONG
;
else
errno
=
EINVAL
;
/* Bad code point, presumably */
}
return
len
;
}
int
p_mkdir
(
const
char
*
path
,
mode_t
mode
)
{
git_win32_path
buf
;
GIT_UNUSED
(
mode
);
if
(
utf8_to_16_with_errno
(
buf
,
path
)
<
0
)
return
-
1
;
return
_wmkdir
(
buf
);
}
int
p_unlink
(
const
char
*
path
)
{
git_win32_path
buf
;
git_win32_path_from_c
(
buf
,
path
);
_wchmod
(
buf
,
0666
);
return
_wunlink
(
buf
);
int
error
;
if
(
utf8_to_16_with_errno
(
buf
,
path
)
<
0
)
return
-
1
;
error
=
_wunlink
(
buf
);
/* If the file could not be deleted because it was
* read-only, clear the bit and try again */
if
(
-
1
==
error
&&
EACCES
==
errno
)
{
_wchmod
(
buf
,
0666
);
error
=
_wunlink
(
buf
);
}
return
error
;
}
int
p_fsync
(
int
fd
)
...
...
@@ -63,7 +110,8 @@ static int do_lstat(
wchar_t
lastch
;
int
flen
;
flen
=
git_win32_path_from_c
(
fbuf
,
file_name
);
if
((
flen
=
utf8_to_16_with_errno
(
fbuf
,
file_name
))
<
0
)
return
-
1
;
/* truncate trailing slashes */
for
(;
flen
>
0
;
--
flen
)
{
...
...
@@ -109,12 +157,9 @@ static int do_lstat(
* the length of the path pointed to, which we expect everywhere else
*/
if
(
S_ISLNK
(
fMode
))
{
git_win32_path_as_utf8
target
;
int
readlink_result
;
git_win32_utf8_path
target
;
readlink_result
=
p_readlink
(
file_name
,
target
,
sizeof
(
target
));
if
(
readlink_result
==
-
1
)
if
(
p_readlink
(
file_name
,
target
,
GIT_WIN_PATH_UTF8
)
==
-
1
)
return
-
1
;
buf
->
st_size
=
strlen
(
target
);
...
...
@@ -160,6 +205,28 @@ int p_lstat_posixly(const char *filename, struct stat *buf)
return
do_lstat
(
filename
,
buf
,
1
);
}
/*
* Returns the address of the GetFinalPathNameByHandleW function.
* This function is available on Windows Vista and higher.
*/
static
PFGetFinalPathNameByHandleW
get_fpnbyhandle
(
void
)
{
static
PFGetFinalPathNameByHandleW
pFunc
=
NULL
;
PFGetFinalPathNameByHandleW
toReturn
=
pFunc
;
if
(
!
toReturn
)
{
HMODULE
hModule
=
GetModuleHandleW
(
L"kernel32"
);
if
(
hModule
)
toReturn
=
(
PFGetFinalPathNameByHandleW
)
GetProcAddress
(
hModule
,
"GetFinalPathNameByHandleW"
);
pFunc
=
toReturn
;
}
assert
(
toReturn
);
return
toReturn
;
}
/*
* Parts of the The p_readlink function are heavily inspired by the php
...
...
@@ -171,87 +238,62 @@ int p_lstat_posixly(const char *filename, struct stat *buf)
*/
int
p_readlink
(
const
char
*
link
,
char
*
target
,
size_t
target_len
)
{
typedef
DWORD
(
WINAPI
*
fpath_func
)(
HANDLE
,
LPWSTR
,
DWORD
,
DWORD
);
static
fpath_func
pGetFinalPath
=
NULL
;
HANDLE
hFile
;
DWORD
dwRet
;
static
const
wchar_t
prefix
[]
=
L"
\\\\
?
\\
"
;
PFGetFinalPathNameByHandleW
pgfp
=
get_fpnbyhandle
();
HANDLE
hFile
=
NULL
;
wchar_t
*
target_w
=
NULL
;
bool
trim_prefix
;
git_win32_path
link_w
;
wchar_t
*
target_w
;
int
error
=
0
;
DWORD
dwChars
,
dwLastError
;
int
error
=
-
1
;
assert
(
link
&&
target
&&
target_len
>
0
);
/* Check that we found the function, and convert to UTF-16 */
if
(
!
pgfp
||
utf8_to_16_with_errno
(
link_w
,
link
)
<
0
)
goto
on_error
;
/*
* Try to load the pointer to pGetFinalPath dynamically, because
* it is not available in platforms older than Vista
*/
if
(
pGetFinalPath
==
NULL
)
{
HMODULE
module
=
GetModuleHandle
(
"kernel32"
);
/* Use FILE_FLAG_BACKUP_SEMANTICS so we can open a directory. Do not
* specify FILE_FLAG_OPEN_REPARSE_POINT; we want to open a handle to the
* target of the link. */
hFile
=
CreateFileW
(
link_w
,
GENERIC_READ
,
FILE_SHARE_READ
|
FILE_SHARE_DELETE
,
NULL
,
OPEN_EXISTING
,
FILE_FLAG_BACKUP_SEMANTICS
,
NULL
);
if
(
module
!=
NULL
)
pGetFinalPath
=
(
fpath_func
)
GetProcAddress
(
module
,
"GetFinalPathNameByHandleW"
)
;
if
(
hFile
==
INVALID_HANDLE_VALUE
)
goto
on_error
;
if
(
pGetFinalPath
==
NULL
)
{
giterr_set
(
GITERR_OS
,
"'GetFinalPathNameByHandleW' is not available in this platform"
);
return
-
1
;
}
}
/* Find out how large the buffer should be to hold the result */
if
(
!
(
dwChars
=
pgfp
(
hFile
,
NULL
,
0
,
FILE_NAME_NORMALIZED
)))
goto
on_error
;
git_win32_path_from_c
(
link_w
,
link
);
if
(
!
(
target_w
=
git__malloc
(
dwChars
*
sizeof
(
wchar_t
))))
goto
on_error
;
hFile
=
CreateFileW
(
link_w
,
// file to open
GENERIC_READ
,
// open for reading
FILE_SHARE_READ
,
// share for reading
NULL
,
// default security
OPEN_EXISTING
,
// existing file only
FILE_FLAG_BACKUP_SEMANTICS
,
// normal file
NULL
);
// no attr. template
/* Call a second time */
dwChars
=
pgfp
(
hFile
,
target_w
,
dwChars
,
FILE_NAME_NORMALIZED
);
if
(
hFile
==
INVALID_HANDLE_VALUE
)
{
giterr_set
(
GITERR_OS
,
"Cannot open '%s' for reading"
,
link
);
return
-
1
;
}
if
(
!
dwChars
)
goto
on_error
;
target_w
=
(
wchar_t
*
)
git__malloc
(
target_len
*
sizeof
(
wchar_t
));
GITERR_CHECK_ALLOC
(
target_w
);
dwRet
=
pGetFinalPath
(
hFile
,
target_w
,
(
DWORD
)
target_len
,
0x0
);
if
(
dwRet
==
0
||
dwRet
>=
target_len
||
!
WideCharToMultiByte
(
CP_UTF8
,
0
,
target_w
,
-
1
,
target
,
(
int
)(
target_len
*
sizeof
(
char
)),
NULL
,
NULL
))
error
=
-
1
;
git__free
(
target_w
);
CloseHandle
(
hFile
);
if
(
error
)
return
error
;
/* Skip first 4 characters if they are "\\?\" */
if
(
dwRet
>
4
&&
target
[
0
]
==
'\\'
&&
target
[
1
]
==
'\\'
&&
target
[
2
]
==
'?'
&&
target
[
3
]
==
'\\'
)
{
unsigned
int
offset
=
4
;
dwRet
-=
4
;
/* \??\UNC\ */
if
(
dwRet
>
7
&&
target
[
4
]
==
'U'
&&
target
[
5
]
==
'N'
&&
target
[
6
]
==
'C'
)
{
offset
+=
2
;
dwRet
-=
2
;
target
[
offset
]
=
'\\'
;
}
/* Do we need to trim off a \\?\ from the start of the path? */
trim_prefix
=
(
dwChars
>=
ARRAY_SIZE
(
prefix
))
&&
!
wcsncmp
(
prefix
,
target_w
,
ARRAY_SIZE
(
prefix
));
memmove
(
target
,
target
+
offset
,
dwRet
);
}
/* Convert the result to UTF-8 */
if
(
git__utf16_to_8
(
target
,
target_len
,
trim_prefix
?
target_w
+
4
:
target_w
)
<
0
)
goto
on_error
;
error
=
0
;
target
[
dwRet
]
=
'\0'
;
on_error
:
dwLastError
=
GetLastError
();
return
dwRet
;
if
(
hFile
&&
INVALID_HANDLE_VALUE
!=
hFile
)
CloseHandle
(
hFile
);
if
(
target_w
)
git__free
(
target_w
);
SetLastError
(
dwLastError
);
return
error
;
}
int
p_symlink
(
const
char
*
old
,
const
char
*
new
)
...
...
@@ -267,7 +309,8 @@ int p_open(const char *path, int flags, ...)
git_win32_path
buf
;
mode_t
mode
=
0
;
git_win32_path_from_c
(
buf
,
path
);
if
(
utf8_to_16_with_errno
(
buf
,
path
)
<
0
)
return
-
1
;
if
(
flags
&
O_CREAT
)
{
va_list
arg_list
;
...
...
@@ -283,33 +326,39 @@ int p_open(const char *path, int flags, ...)
int
p_creat
(
const
char
*
path
,
mode_t
mode
)
{
git_win32_path
buf
;
git_win32_path_from_c
(
buf
,
path
);
if
(
utf8_to_16_with_errno
(
buf
,
path
)
<
0
)
return
-
1
;
return
_wopen
(
buf
,
_O_WRONLY
|
_O_CREAT
|
_O_TRUNC
|
_O_BINARY
,
mode
);
}
int
p_getcwd
(
char
*
buffer_out
,
size_t
size
)
{
int
ret
;
wchar_t
*
buf
;
git_win32_path
buf
;
wchar_t
*
cwd
=
_wgetcwd
(
buf
,
GIT_WIN_PATH_UTF16
)
;
if
(
(
size_t
)((
int
)
size
)
!=
size
)
if
(
!
cwd
)
return
-
1
;
buf
=
(
wchar_t
*
)
git__malloc
(
sizeof
(
wchar_t
)
*
(
int
)
size
);
GITERR_CHECK_ALLOC
(
buf
);
/* Convert the working directory back to UTF-8 */
if
(
git__utf16_to_8
(
buffer_out
,
size
,
cwd
)
<
0
)
{
DWORD
code
=
GetLastError
();
_wgetcwd
(
buf
,
(
int
)
size
);
if
(
code
==
ERROR_INSUFFICIENT_BUFFER
)
errno
=
ERANGE
;
else
errno
=
EINVAL
;
ret
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
buf
,
-
1
,
buffer_out
,
(
int
)
size
,
NULL
,
NULL
);
return
-
1
;
}
git__free
(
buf
);
return
!
ret
?
-
1
:
0
;
return
0
;
}
int
p_stat
(
const
char
*
path
,
struct
stat
*
buf
)
{
git_win32_
path_as_utf8
target
;
git_win32_
utf8_path
target
;
int
error
=
0
;
error
=
do_lstat
(
path
,
buf
,
0
);
...
...
@@ -317,7 +366,7 @@ int p_stat(const char* path, struct stat* buf)
/* We need not do this in a loop to unwind chains of symlinks since
* p_readlink calls GetFinalPathNameByHandle which does it for us. */
if
(
error
>=
0
&&
S_ISLNK
(
buf
->
st_mode
)
&&
(
error
=
p_readlink
(
path
,
target
,
sizeof
(
target
)
))
>=
0
)
(
error
=
p_readlink
(
path
,
target
,
GIT_WIN_PATH_UTF8
))
>=
0
)
error
=
do_lstat
(
target
,
buf
,
0
);
return
error
;
...
...
@@ -326,82 +375,93 @@ int p_stat(const char* path, struct stat* buf)
int
p_chdir
(
const
char
*
path
)
{
git_win32_path
buf
;
git_win32_path_from_c
(
buf
,
path
);
if
(
utf8_to_16_with_errno
(
buf
,
path
)
<
0
)
return
-
1
;
return
_wchdir
(
buf
);
}
int
p_chmod
(
const
char
*
path
,
mode_t
mode
)
{
git_win32_path
buf
;
git_win32_path_from_c
(
buf
,
path
);
if
(
utf8_to_16_with_errno
(
buf
,
path
)
<
0
)
return
-
1
;
return
_wchmod
(
buf
,
mode
);
}
int
p_rmdir
(
const
char
*
path
)
{
int
error
;
git_win32_path
buf
;
git_win32_path_from_c
(
buf
,
path
);
int
error
;
if
(
utf8_to_16_with_errno
(
buf
,
path
)
<
0
)
return
-
1
;
error
=
_wrmdir
(
buf
);
/* _wrmdir() is documented to return EACCES if "A program has an open
* handle to the directory." This sounds like what everybody else calls
* EBUSY. Let's convert appropriate error codes.
*/
if
(
GetLastError
()
==
ERROR_SHARING_VIOLATION
)
errno
=
EBUSY
;
if
(
-
1
==
error
)
{
switch
(
GetLastError
())
{
/* _wrmdir() is documented to return EACCES if "A program has an open
* handle to the directory." This sounds like what everybody else calls
* EBUSY. Let's convert appropriate error codes.
*/
case
ERROR_SHARING_VIOLATION
:
errno
=
EBUSY
;
break
;
return
error
;
}
/* This error can be returned when trying to rmdir an extant file. */
case
ERROR_DIRECTORY
:
errno
=
ENOTDIR
;
break
;
}
}
int
p_hide_directory__w32
(
const
char
*
path
)
{
git_win32_path
buf
;
git_win32_path_from_c
(
buf
,
path
);
return
(
SetFileAttributesW
(
buf
,
FILE_ATTRIBUTE_HIDDEN
)
!=
0
)
?
0
:
-
1
;
return
error
;
}
char
*
p_realpath
(
const
char
*
orig_path
,
char
*
buffer
)
{
int
ret
;
git_win32_path
orig_path_w
;
git_win32_path
buffer_w
;
git_win32_path
orig_path_w
,
buffer_w
;
git_win32_path_from_c
(
orig_path_w
,
orig_path
);
if
(
utf8_to_16_with_errno
(
orig_path_w
,
orig_path
)
<
0
)
return
NULL
;
/* Implicitly use GetCurrentDirectory which can be a threading issue */
ret
=
GetFullPathNameW
(
orig_path_w
,
GIT_WIN_PATH_UTF16
,
buffer_w
,
NULL
);
/* Note that if the path provided is a relative path, then the current directory
* is used to resolve the path -- which is a concurrency issue because the current
* directory is a process-wide variable. */
if
(
!
GetFullPathNameW
(
orig_path_w
,
GIT_WIN_PATH_UTF16
,
buffer_w
,
NULL
))
{
if
(
GetLastError
()
==
ERROR_INSUFFICIENT_BUFFER
)
errno
=
ENAMETOOLONG
;
else
errno
=
EINVAL
;
/* According to MSDN, a return value equals to zero means a failure. */
if
(
ret
==
0
||
ret
>
GIT_WIN_PATH_UTF16
)
buffer
=
NULL
;
return
NULL
;
}
else
if
(
GetFileAttributesW
(
buffer_w
)
==
INVALID_FILE_ATTRIBUTES
)
{
buffer
=
NULL
;
/* The path must exist. */
if
(
INVALID_FILE_ATTRIBUTES
==
GetFileAttributesW
(
buffer_w
))
{
errno
=
ENOENT
;
return
NULL
;
}
else
if
(
buffer
==
NULL
)
{
int
buffer_sz
=
WideCharToMultiByte
(
CP_UTF8
,
0
,
buffer_w
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
if
(
!
buffer_sz
||
!
(
buffer
=
(
char
*
)
git__malloc
(
buffer_sz
))
||
!
WideCharToMultiByte
(
CP_UTF8
,
0
,
buffer_w
,
-
1
,
buffer
,
buffer_sz
,
NULL
,
NULL
))
{
git__free
(
buffer
);
buffer
=
NULL
;
}
/* Convert the path to UTF-8. */
if
(
buffer
)
{
/* If the caller provided a buffer, then it is assumed to be GIT_WIN_PATH_UTF8
* characters in size. If it isn't, then we may overflow. */
if
(
git__utf16_to_8
(
buffer
,
GIT_WIN_PATH_UTF8
,
buffer_w
)
<
0
)
return
NULL
;
}
else
{
/* If the caller did not provide a buffer, then we allocate one for the caller
* from the heap. */
if
(
git__utf16_to_8_alloc
(
&
buffer
,
buffer_w
)
<
0
)
return
NULL
;
}
else
if
(
!
WideCharToMultiByte
(
CP_UTF8
,
0
,
buffer_w
,
-
1
,
buffer
,
GIT_PATH_MAX
,
NULL
,
NULL
))
buffer
=
NULL
;
if
(
buffer
)
git_path_mkposix
(
buffer
);
/* Convert backslashes to forward slashes */
git_path_mkposix
(
buffer
);
return
buffer
;
}
...
...
@@ -433,8 +493,6 @@ int p_snprintf(char *buffer, size_t count, const char *format, ...)
return
r
;
}
extern
int
p_creat
(
const
char
*
path
,
mode_t
mode
);
int
p_mkstemp
(
char
*
tmp_path
)
{
#if defined(_MSC_VER)
...
...
@@ -448,18 +506,13 @@ int p_mkstemp(char *tmp_path)
return
p_creat
(
tmp_path
,
0744
);
//-V536
}
int
p_setenv
(
const
char
*
name
,
const
char
*
value
,
int
overwrite
)
{
if
(
overwrite
!=
1
)
return
-
1
;
return
(
SetEnvironmentVariableA
(
name
,
value
)
==
0
?
-
1
:
0
);
}
int
p_access
(
const
char
*
path
,
mode_t
mode
)
{
git_win32_path
buf
;
git_win32_path_from_c
(
buf
,
path
);
if
(
utf8_to_16_with_errno
(
buf
,
path
)
<
0
)
return
-
1
;
return
_waccess
(
buf
,
mode
);
}
...
...
@@ -471,8 +524,9 @@ int p_rename(const char *from, const char *to)
int
rename_succeeded
;
int
error
;
git_win32_path_from_c
(
wfrom
,
from
);
git_win32_path_from_c
(
wto
,
to
);
if
(
utf8_to_16_with_errno
(
wfrom
,
from
)
<
0
||
utf8_to_16_with_errno
(
wto
,
to
)
<
0
)
return
-
1
;
/* wait up to 50ms if file is locked by another thread or process */
rename_tries
=
0
;
...
...
src/win32/utf-conv.c
View file @
c2c81615
...
...
@@ -8,12 +8,139 @@
#include "common.h"
#include "utf-conv.h"
int
git__utf8_to_16
(
wchar_t
*
dest
,
size_t
dest_size
,
const
char
*
src
)
#ifndef WC_ERR_INVALID_CHARS
#define WC_ERR_INVALID_CHARS 0x80
#endif
GIT_INLINE
(
DWORD
)
get_wc_flags
(
void
)
{
return
MultiByteToWideChar
(
CP_UTF8
,
0
,
src
,
-
1
,
dest
,
(
int
)
dest_size
);
static
char
inited
=
0
;
static
DWORD
flags
;
/* Invalid code point check supported on Vista+ only */
if
(
!
inited
)
{
flags
=
git_has_win32_version
(
6
,
0
,
0
)
?
WC_ERR_INVALID_CHARS
:
0
;
inited
=
1
;
}
return
flags
;
}
/**
* Converts a UTF-8 string to wide characters.
*
* @param dest The buffer to receive the wide string.
* @param dest_size The size of the buffer, in characters.
* @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
*/
int
git__utf8_to_16
(
wchar_t
*
dest
,
size_t
dest_size
,
const
char
*
src
)
{
/* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to
* turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's
* length. MultiByteToWideChar never returns int's minvalue, so underflow is not possible */
return
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
src
,
-
1
,
dest
,
(
int
)
dest_size
)
-
1
;
}
/**
* Converts a wide string to UTF-8.
*
* @param dest The buffer to receive the UTF-8 string.
* @param dest_size The size of the buffer, in bytes.
* @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
*/
int
git__utf16_to_8
(
char
*
dest
,
size_t
dest_size
,
const
wchar_t
*
src
)
{
return
WideCharToMultiByte
(
CP_UTF8
,
0
,
src
,
-
1
,
dest
,
(
int
)
dest_size
,
NULL
,
NULL
);
/* Length of -1 indicates NULL termination of the input string. Subtract 1 from the result to
* turn 0 into -1 (an error code) and to not count the NULL terminator as part of the string's
* length. WideCharToMultiByte never returns int's minvalue, so underflow is not possible */
return
WideCharToMultiByte
(
CP_UTF8
,
get_wc_flags
(),
src
,
-
1
,
dest
,
(
int
)
dest_size
,
NULL
,
NULL
)
-
1
;
}
/**
* Converts a UTF-8 string to wide characters.
* Memory is allocated to hold the converted string.
* The caller is responsible for freeing the string with git__free.
*
* @param dest Receives a pointer to the wide string.
* @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
*/
int
git__utf8_to_16_alloc
(
wchar_t
**
dest
,
const
char
*
src
)
{
int
utf16_size
;
*
dest
=
NULL
;
/* Length of -1 indicates NULL termination of the input string */
utf16_size
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
src
,
-
1
,
NULL
,
0
);
if
(
!
utf16_size
)
return
-
1
;
*
dest
=
git__malloc
(
utf16_size
*
sizeof
(
wchar_t
));
if
(
!*
dest
)
return
-
1
;
utf16_size
=
MultiByteToWideChar
(
CP_UTF8
,
MB_ERR_INVALID_CHARS
,
src
,
-
1
,
*
dest
,
utf16_size
);
if
(
!
utf16_size
)
{
/* Don't let git__free stomp on the thread-local last error code,
* so that the caller can call giterr_set(GITERR_OS, ...) */
DWORD
last_error
=
GetLastError
();
git__free
(
*
dest
);
*
dest
=
NULL
;
SetLastError
(
last_error
);
}
/* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL
* terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue,
* so underflow is not possible */
return
utf16_size
-
1
;
}
/**
* Converts a wide string to UTF-8.
* Memory is allocated to hold the converted string.
* The caller is responsible for freeing the string with git__free.
*
* @param dest Receives a pointer to the UTF-8 string.
* @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
*/
int
git__utf16_to_8_alloc
(
char
**
dest
,
const
wchar_t
*
src
)
{
int
utf8_size
;
DWORD
dwFlags
=
get_wc_flags
();
*
dest
=
NULL
;
/* Length of -1 indicates NULL termination of the input string */
utf8_size
=
WideCharToMultiByte
(
CP_UTF8
,
dwFlags
,
src
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
if
(
!
utf8_size
)
return
-
1
;
*
dest
=
git__malloc
(
utf8_size
);
if
(
!*
dest
)
return
-
1
;
utf8_size
=
WideCharToMultiByte
(
CP_UTF8
,
dwFlags
,
src
,
-
1
,
*
dest
,
utf8_size
,
NULL
,
NULL
);
if
(
!
utf8_size
)
{
/* Don't let git__free stomp on the thread-local last error code,
* so that the caller can call giterr_set(GITERR_OS, ...) */
DWORD
last_error
=
GetLastError
();
git__free
(
*
dest
);
*
dest
=
NULL
;
SetLastError
(
last_error
);
}
/* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL
* terminator as part of the string's length. MultiByteToWideChar never returns int's minvalue,
* so underflow is not possible */
return
utf8_size
-
1
;
}
src/win32/utf-conv.h
View file @
c2c81615
...
...
@@ -10,27 +10,83 @@
#include <wchar.h>
#include "common.h"
/* Maximum characters in a Windows path plus one for NUL byte */
#define GIT_WIN_PATH_UTF16 (260 + 1)
/* Equal to the Win32 MAX_PATH constant. The maximum path length is 259
* characters plus a NULL terminator. */
#define GIT_WIN_PATH_UTF16 260
/* Maximum bytes necessary to convert a full-length UTF16 path to UTF8 */
#define GIT_WIN_PATH_UTF8 (260 * 4 + 1)
/* Maximum size of a UTF-8 Win32 path. UTF-8 does have 4-byte sequences,
* but they are encoded in UTF-16 using surrogate pairs, which takes up
* the space of two characters. Two characters in the range U+0800 ->
* U+FFFF take up more space in UTF-8 (6 bytes) than one surrogate pair
* (4 bytes). */
#define GIT_WIN_PATH_UTF8 (259 * 3 + 1)
/* Win32 path types */
typedef
wchar_t
git_win32_path
[
GIT_WIN_PATH_UTF16
];
typedef
char
git_win32_utf8_path
[
GIT_WIN_PATH_UTF8
];
typedef
char
git_win32_path_as_utf8
[
GIT_WIN_PATH_UTF8
];
/**
* Converts a UTF-8 string to wide characters.
*
* @param dest The buffer to receive the wide string.
* @param dest_size The size of the buffer, in characters.
* @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
*/
int
git__utf8_to_16
(
wchar_t
*
dest
,
size_t
dest_size
,
const
char
*
src
);
/* dest_size is the size of dest in wchar_t's */
int
git__utf8_to_16
(
wchar_t
*
dest
,
size_t
dest_size
,
const
char
*
src
);
/* dest_size is the size of dest in char's */
/**
* Converts a wide string to UTF-8.
*
* @param dest The buffer to receive the UTF-8 string.
* @param dest_size The size of the buffer, in bytes.
* @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
*/
int
git__utf16_to_8
(
char
*
dest
,
size_t
dest_size
,
const
wchar_t
*
src
);
GIT_INLINE
(
int
)
git_win32_path_from_c
(
git_win32_path
dest
,
const
char
*
src
)
/**
* Converts a UTF-8 string to wide characters.
* Memory is allocated to hold the converted string.
* The caller is responsible for freeing the string with git__free.
*
* @param dest Receives a pointer to the wide string.
* @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
*/
int
git__utf8_to_16_alloc
(
wchar_t
**
dest
,
const
char
*
src
);
/**
* Converts a wide string to UTF-8.
* Memory is allocated to hold the converted string.
* The caller is responsible for freeing the string with git__free.
*
* @param dest Receives a pointer to the UTF-8 string.
* @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
*/
int
git__utf16_to_8_alloc
(
char
**
dest
,
const
wchar_t
*
src
);
/**
* Converts a UTF-8 Win32 path to wide characters.
*
* @param dest The buffer to receive the wide string.
* @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
*/
GIT_INLINE
(
int
)
git_win32_path_from_utf8
(
git_win32_path
dest
,
const
char
*
src
)
{
return
git__utf8_to_16
(
dest
,
GIT_WIN_PATH_UTF16
,
src
);
}
GIT_INLINE
(
int
)
git_win32_path_to_c
(
git_win32_path_as_utf8
dest
,
const
wchar_t
*
src
)
/**
* Converts a wide Win32 path to UTF-8.
*
* @param dest The buffer to receive the UTF-8 string.
* @param src The wide string to convert.
* @return The length of the UTF-8 string, in bytes (not counting the NULL terminator), or < 0 for failure
*/
GIT_INLINE
(
int
)
git_win32_path_to_utf8
(
git_win32_utf8_path
dest
,
const
wchar_t
*
src
)
{
return
git__utf16_to_8
(
dest
,
GIT_WIN_PATH_UTF8
,
src
);
}
...
...
src/win32/w32_util.c
0 → 100644
View file @
c2c81615
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "w32_util.h"
/**
* Creates a FindFirstFile(Ex) filter string from a UTF-8 path.
* The filter string enumerates all items in the directory.
*
* @param dest The buffer to receive the filter string.
* @param src The UTF-8 path of the directory to enumerate.
* @return True if the filter string was created successfully; false otherwise
*/
bool
git_win32__findfirstfile_filter
(
git_win32_path
dest
,
const
char
*
src
)
{
static
const
wchar_t
suffix
[]
=
L"
\\
*"
;
int
len
=
git_win32_path_from_utf8
(
dest
,
src
);
/* Ensure the path was converted */
if
(
len
<
0
)
return
false
;
/* Ensure that the path does not end with a trailing slash --
* because we're about to add one! */
if
(
len
>
0
&&
(
dest
[
len
-
1
]
==
L'/'
||
dest
[
len
-
1
]
==
L'\\'
))
{
dest
[
len
-
1
]
=
L'\0'
;
len
--
;
}
/* Ensure we have enough room to add the suffix */
if
((
size_t
)
len
>
GIT_WIN_PATH_UTF16
-
ARRAY_SIZE
(
suffix
))
return
false
;
wcscat
(
dest
,
suffix
);
return
true
;
}
/**
* Ensures the given path (file or folder) has the +H (hidden) attribute set.
*
* @param path The path which should receive the +H bit.
* @return 0 on success; -1 on failure
*/
int
git_win32__sethidden
(
const
char
*
path
)
{
git_win32_path
buf
;
DWORD
attrs
;
if
(
git_win32_path_from_utf8
(
buf
,
path
)
<
0
)
return
-
1
;
attrs
=
GetFileAttributesW
(
buf
);
/* Ensure the path exists */
if
(
INVALID_FILE_ATTRIBUTES
==
attrs
)
return
-
1
;
/* If the item isn't already +H, add the bit */
if
(
0
==
(
attrs
&
FILE_ATTRIBUTE_HIDDEN
)
&&
!
SetFileAttributesW
(
buf
,
attrs
|
FILE_ATTRIBUTE_HIDDEN
))
return
-
1
;
return
0
;
}
src/win32/w32_util.h
0 → 100644
View file @
c2c81615
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_w32_util_h__
#define INCLUDE_w32_util_h__
#include "utf-conv.h"
/**
* Creates a FindFirstFile(Ex) filter string from a UTF-8 path.
* The filter string enumerates all items in the directory.
*
* @param dest The buffer to receive the filter string.
* @param src The UTF-8 path of the directory to enumerate.
* @return True if the filter string was created successfully; false otherwise
*/
bool
git_win32__findfirstfile_filter
(
git_win32_path
dest
,
const
char
*
src
);
/**
* Ensures the given path (file or folder) has the +H (hidden) attribute set.
*
* @param path The path which should receive the +H bit.
* @return 0 on success; -1 on failure
*/
int
git_win32__sethidden
(
const
char
*
path
);
#endif
tests/clar_libgit2.c
View file @
c2c81615
...
...
@@ -59,47 +59,40 @@ void cl_git_rewritefile(const char *path, const char *content)
char
*
cl_getenv
(
const
char
*
name
)
{
git_win32_path
name_utf16
;
DWORD
alloc_len
;
wchar_t
*
value_utf16
;
char
*
value_utf8
;
wchar_t
*
wide_name
,
*
wide_value
;
char
*
utf8_value
=
NULL
;
DWORD
value_len
;
git_win32_path_from_c
(
name_utf16
,
name
);
alloc_len
=
GetEnvironmentVariableW
(
name_utf16
,
NULL
,
0
);
if
(
alloc_len
<=
0
)
return
NULL
;
cl_assert
(
git__utf8_to_16_alloc
(
&
wide_name
,
name
)
>=
0
);
cl_assert
(
value_utf16
=
git__calloc
(
alloc_len
,
sizeof
(
wchar_t
))
);
value_len
=
GetEnvironmentVariableW
(
wide_name
,
NULL
,
0
);
GetEnvironmentVariableW
(
name_utf16
,
value_utf16
,
alloc_len
);
alloc_len
=
alloc_len
*
4
+
1
;
/* worst case UTF16->UTF8 growth */
cl_assert
(
value_utf8
=
git__calloc
(
alloc_len
,
1
));
git__utf16_to_8
(
value_utf8
,
alloc_len
,
value_utf16
);
git__free
(
value_utf16
);
if
(
value_len
)
{
cl_assert
(
wide_value
=
git__malloc
(
value_len
*
sizeof
(
wchar_t
)));
cl_assert
(
GetEnvironmentVariableW
(
wide_name
,
wide_value
,
value_len
));
cl_assert
(
git__utf16_to_8_alloc
(
&
utf8_value
,
wide_value
)
>=
0
);
git__free
(
wide_value
);
}
return
value_utf8
;
git__free
(
wide_name
);
return
utf8_value
;
}
int
cl_setenv
(
const
char
*
name
,
const
char
*
value
)
{
git_win32_path
name_utf16
;
git_win32_path
value_utf16
;
wchar_t
*
wide_name
,
*
wide_value
;
git_win32_path_from_c
(
name_utf16
,
name
);
cl_assert
(
git__utf8_to_16_alloc
(
&
wide_name
,
name
)
>=
0
);
if
(
value
)
{
git_win32_path_from_c
(
value_utf16
,
value
);
cl_assert
(
SetEnvironmentVariableW
(
name_utf16
,
value_utf16
));
cl_assert
(
git__utf8_to_16_alloc
(
&
wide_value
,
value
)
>=
0
);
cl_assert
(
SetEnvironmentVariableW
(
wide_name
,
wide_value
));
}
else
{
/* Windows XP returns 0 (failed) when passing NULL for lpValue when
* lpName does not exist in the environment block. This behavior
* seems to have changed in later versions. Don't check return value
* of SetEnvironmentVariable when passing NULL for lpValue.
*/
SetEnvironmentVariableW
(
name_utf16
,
NULL
);
* lpName does not exist in the environment block. This behavior
* seems to have changed in later versions. Don't check the return value
* of SetEnvironmentVariable when passing NULL for lpValue. */
SetEnvironmentVariableW
(
wide_name
,
NULL
);
}
return
0
;
...
...
@@ -115,8 +108,8 @@ int cl_rename(const char *source, const char *dest)
git_win32_path
dest_utf16
;
unsigned
retries
=
1
;
git_win32_path_from_c
(
source_utf16
,
source
);
git_win32_path_from_c
(
dest_utf16
,
dest
);
cl_assert
(
git_win32_path_from_utf8
(
source_utf16
,
source
)
>=
0
);
cl_assert
(
git_win32_path_from_utf8
(
dest_utf16
,
dest
)
>=
0
);
while
(
!
MoveFileW
(
source_utf16
,
dest_utf16
))
{
/* Only retry if the error is ERROR_ACCESS_DENIED;
...
...
tests/core/env.c
View file @
c2c81615
...
...
@@ -21,7 +21,7 @@ static char *home_values[] = {
"f
\xc4\x80
ke_
\xc4\xa4
ome"
,
/* latin extended */
"f
\xce\xb1\xce\xba\xce\xb5
_h
\xce\xbf
m
\xce\xad
"
,
/* having fun with greek */
"fa
\xe0
"
"
\xb8
"
"
\x87
"
"e_
\xe0
"
"
\xb8
"
"
\x99
"
"ome"
,
/* thai characters */
"f
\xe1\x9c
x80ke_
\xe1\x9c\x91
ome"
,
/* tagalog characters */
"f
\xe1\x9c
\
x80
ke_
\xe1\x9c\x91
ome"
,
/* tagalog characters */
"
\xe1\xb8\x9f\xe1\xba\xa2
"
"ke_ho"
"
\xe1
"
"
\xb9
"
"
\x81
"
"e"
,
/* latin extended additional */
"
\xf0\x9f\x98\x98\xf0\x9f\x98\x82
"
,
/* emoticons */
NULL
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment