mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-04 17:13:25 +00:00
Win32: UTF-8 <-> WCHAR conversion overhaul
This commit is contained in:
parent
bfc50f83f8
commit
c2c8161541
43
src/path.c
43
src/path.c
@ -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;
|
||||
git_win32_path filter_w;
|
||||
bool empty = false;
|
||||
|
||||
if (!git_path_isdir(path))
|
||||
return false;
|
||||
if (git_win32__findfirstfile_filter(filter_w, path)) {
|
||||
WIN32_FIND_DATAW findData;
|
||||
HANDLE hFind = FindFirstFileW(filter_w, &findData);
|
||||
|
||||
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));
|
||||
/* If the find handle was created successfully, then it's a directory */
|
||||
if (INVALID_HANDLE_VALUE != hFind) {
|
||||
empty = true;
|
||||
|
||||
hFind = FindFirstFileW(wbuf, &ffd);
|
||||
if (INVALID_HANDLE_VALUE == hFind)
|
||||
return false;
|
||||
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));
|
||||
|
||||
do {
|
||||
if (!git_path_is_dot_or_dotdotW(ffd.cFileName)) {
|
||||
retval = false;
|
||||
break;
|
||||
FindClose(hFind);
|
||||
}
|
||||
} while (FindNextFileW(hFind, &ffd) != 0);
|
||||
}
|
||||
|
||||
FindClose(hFind);
|
||||
return retval;
|
||||
return empty;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
int proxy_wide_len = git__utf8_to_16_alloc(&proxy_wide, proxy_url);
|
||||
|
||||
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;
|
||||
|
||||
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,
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -17,56 +17,36 @@
|
||||
#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)
|
||||
typedef struct {
|
||||
git_win32_path path;
|
||||
DWORD len;
|
||||
} _findfile_path;
|
||||
|
||||
static int git_win32__expand_path(_findfile_path *dest, const wchar_t *src)
|
||||
{
|
||||
s_root->len = ExpandEnvironmentStringsW(templ, s_root->path, MAX_PATH);
|
||||
return s_root->len ? 0 : -1;
|
||||
}
|
||||
dest->len = ExpandEnvironmentStringsW(src, dest->path, ARRAY_SIZE(dest->path));
|
||||
|
||||
static int win32_path_to_8(git_buf *path_utf8, const wchar_t *path)
|
||||
{
|
||||
char temp_utf8[GIT_PATH_MAX];
|
||||
|
||||
git__utf16_to_8(temp_utf8, GIT_PATH_MAX, path);
|
||||
git_path_mkposix(temp_utf8);
|
||||
|
||||
return git_buf_sets(path_utf8, temp_utf8);
|
||||
}
|
||||
|
||||
int git_win32__find_file(
|
||||
git_buf *path, const struct git_win32__path *root, const char *filename)
|
||||
{
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
win32_path_to_8(path, file_utf16);
|
||||
git__free(file_utf16);
|
||||
if (!dest->len || dest->len > ARRAY_SIZE(dest->path))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int win32_path_to_8(git_buf *dest, const wchar_t *src)
|
||||
{
|
||||
git_win32_utf8_path utf8_path;
|
||||
|
||||
if (git_win32_path_to_utf8(utf8_path, src) < 0) {
|
||||
giterr_set(GITERR_OS, "Unable to convert path to UTF-8");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert backslashes to forward slashes */
|
||||
git_path_mkposix(utf8_path);
|
||||
|
||||
return git_buf_sets(dest, utf8_path);
|
||||
}
|
||||
|
||||
static wchar_t* win32_walkpath(wchar_t *path, wchar_t *buf, size_t buflen)
|
||||
{
|
||||
wchar_t term, *base = path;
|
||||
@ -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 hieve, 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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
/* 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));
|
||||
|
||||
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;
|
||||
/* 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;
|
||||
|
||||
git__free(target_w);
|
||||
CloseHandle(hFile);
|
||||
error = 0;
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
on_error:
|
||||
dwLastError = GetLastError();
|
||||
|
||||
/* Skip first 4 characters if they are "\\?\" */
|
||||
if (dwRet > 4 &&
|
||||
target[0] == '\\' && target[1] == '\\' &&
|
||||
target[2] == '?' && target[3] == '\\')
|
||||
{
|
||||
unsigned int offset = 4;
|
||||
dwRet -= 4;
|
||||
if (hFile && INVALID_HANDLE_VALUE != hFile)
|
||||
CloseHandle(hFile);
|
||||
|
||||
/* \??\UNC\ */
|
||||
if (dwRet > 7 &&
|
||||
target[4] == 'U' && target[5] == 'N' && target[6] == 'C')
|
||||
{
|
||||
offset += 2;
|
||||
dwRet -= 2;
|
||||
target[offset] = '\\';
|
||||
}
|
||||
if (target_w)
|
||||
git__free(target_w);
|
||||
|
||||
memmove(target, target + offset, dwRet);
|
||||
}
|
||||
|
||||
target[dwRet] = '\0';
|
||||
|
||||
return dwRet;
|
||||
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;
|
||||
|
||||
/* This error can be returned when trying to rmdir an extant file. */
|
||||
case ERROR_DIRECTORY:
|
||||
errno = ENOTDIR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
69
src/win32/w32_util.c
Normal file
69
src/win32/w32_util.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
31
src/win32/w32_util.h
Normal file
31
src/win32/w32_util.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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
|
@ -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);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
@ -21,7 +21,7 @@ static char *home_values[] = {
|
||||
"f\xc4\x80ke_\xc4\xa4ome", /* latin extended */
|
||||
"f\xce\xb1\xce\xba\xce\xb5_h\xce\xbfm\xce\xad", /* having fun with greek */
|
||||
"fa\xe0" "\xb8" "\x87" "e_\xe0" "\xb8" "\x99" "ome", /* thai characters */
|
||||
"f\xe1\x9cx80ke_\xe1\x9c\x91ome", /* tagalog characters */
|
||||
"f\xe1\x9c\x80ke_\xe1\x9c\x91ome", /* 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
|
||||
|
Loading…
Reference in New Issue
Block a user