Merge pull request #1767 from libgit2/win32-bigger-utf8-buffer

Bigger buffer for utf-8 parsing in win32
This commit is contained in:
Vicent Martí 2013-08-13 11:36:24 -07:00
commit 40948998ba
21 changed files with 179 additions and 104 deletions

View File

@ -58,9 +58,9 @@ int git_futils_creat_locked(const char *path, const mode_t mode)
int fd; int fd;
#ifdef GIT_WIN32 #ifdef GIT_WIN32
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
fd = _wopen(buf, O_WRONLY | O_CREAT | O_TRUNC | fd = _wopen(buf, O_WRONLY | O_CREAT | O_TRUNC |
O_EXCL | O_BINARY | O_CLOEXEC, mode); O_EXCL | O_BINARY | O_CLOEXEC, mode);
#else #else

View File

@ -8,7 +8,6 @@
#include "path.h" #include "path.h"
#include "posix.h" #include "posix.h"
#ifdef GIT_WIN32 #ifdef GIT_WIN32
#include "win32/dir.h"
#include "win32/posix.h" #include "win32/posix.h"
#else #else
#include <dirent.h> #include <dirent.h>
@ -486,24 +485,26 @@ bool git_path_is_empty_dir(const char *path)
{ {
git_buf pathbuf = GIT_BUF_INIT; git_buf pathbuf = GIT_BUF_INIT;
HANDLE hFind = INVALID_HANDLE_VALUE; HANDLE hFind = INVALID_HANDLE_VALUE;
wchar_t wbuf[GIT_WIN_PATH]; git_win32_path wbuf;
WIN32_FIND_DATAW ffd; WIN32_FIND_DATAW ffd;
bool retval = true; bool retval = true;
if (!git_path_isdir(path)) return false; if (!git_path_isdir(path)) return false;
git_buf_printf(&pathbuf, "%s\\*", path); git_buf_printf(&pathbuf, "%s\\*", path);
git__utf8_to_16(wbuf, GIT_WIN_PATH, git_buf_cstr(&pathbuf)); git_win32_path_from_c(wbuf, git_buf_cstr(&pathbuf));
hFind = FindFirstFileW(wbuf, &ffd); hFind = FindFirstFileW(wbuf, &ffd);
if (INVALID_HANDLE_VALUE == hFind) { if (INVALID_HANDLE_VALUE == hFind) {
giterr_set(GITERR_OS, "Couldn't open '%s'", path); giterr_set(GITERR_OS, "Couldn't open '%s'", path);
git_buf_free(&pathbuf);
return false; return false;
} }
do { do {
if (!git_path_is_dot_or_dotdotW(ffd.cFileName)) { if (!git_path_is_dot_or_dotdotW(ffd.cFileName)) {
retval = false; retval = false;
break;
} }
} while (FindNextFileW(hFind, &ffd) != 0); } while (FindNextFileW(hFind, &ffd) != 0);

View File

@ -893,7 +893,7 @@ static int winhttp_connect(
const char *url) const char *url)
{ {
wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")"; wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")";
wchar_t host[GIT_WIN_PATH]; git_win32_path host;
int32_t port; int32_t port;
const char *default_port = "80"; const char *default_port = "80";
int ret; int ret;
@ -920,7 +920,7 @@ static int winhttp_connect(
return -1; return -1;
/* Prepare host */ /* Prepare host */
git__utf8_to_16(host, GIT_WIN_PATH, t->host); git_win32_path_from_c(host, t->host);
/* Establish session */ /* Establish session */
t->session = WinHttpOpen( t->session = WinHttpOpen(
@ -934,7 +934,7 @@ static int winhttp_connect(
giterr_set(GITERR_OS, "Failed to init WinHTTP"); giterr_set(GITERR_OS, "Failed to init WinHTTP");
return -1; return -1;
} }
/* Establish connection */ /* Establish connection */
t->connection = WinHttpConnect( t->connection = WinHttpConnect(
t->session, t->session,

View File

@ -5,8 +5,7 @@
* a Linking Exception. For full terms see the included COPYING file. * a Linking Exception. For full terms see the included COPYING file.
*/ */
#define GIT__WIN32_NO_WRAP_DIR #define GIT__WIN32_NO_WRAP_DIR
#include "dir.h" #include "posix.h"
#include "utf-conv.h"
static int init_filter(char *filter, size_t n, const char *dir) static int init_filter(char *filter, size_t n, const char *dir)
{ {
@ -25,36 +24,32 @@ static int init_filter(char *filter, size_t n, const char *dir)
git__DIR *git__opendir(const char *dir) git__DIR *git__opendir(const char *dir)
{ {
char filter[GIT_WIN_PATH]; git_win32_path_as_utf8 filter;
wchar_t filter_w[GIT_WIN_PATH]; git_win32_path filter_w;
git__DIR *new = NULL; git__DIR *new = NULL;
size_t dirlen;
if (!dir || !init_filter(filter, sizeof(filter), dir)) if (!dir || !init_filter(filter, sizeof(filter), dir))
return NULL; return NULL;
new = git__calloc(1, sizeof(*new)); dirlen = strlen(dir);
new = git__calloc(sizeof(*new) + dirlen + 1, 1);
if (!new) if (!new)
return NULL; return NULL;
memcpy(new->dir, dir, dirlen);
new->dir = git__strdup(dir); git_win32_path_from_c(filter_w, filter);
if (!new->dir)
goto fail;
git__utf8_to_16(filter_w, GIT_WIN_PATH, filter);
new->h = FindFirstFileW(filter_w, &new->f); new->h = FindFirstFileW(filter_w, &new->f);
if (new->h == INVALID_HANDLE_VALUE) { if (new->h == INVALID_HANDLE_VALUE) {
giterr_set(GITERR_OS, "Could not open directory '%s'", dir); giterr_set(GITERR_OS, "Could not open directory '%s'", dir);
goto fail; git__free(new);
return NULL;
} }
new->first = 1; new->first = 1;
return new; return new;
fail:
git__free(new->dir);
git__free(new);
return NULL;
} }
int git__readdir_ext( int git__readdir_ext(
@ -80,7 +75,7 @@ int git__readdir_ext(
if (wcslen(d->f.cFileName) >= sizeof(entry->d_name)) if (wcslen(d->f.cFileName) >= sizeof(entry->d_name))
return -1; return -1;
git__utf16_to_8(entry->d_name, d->f.cFileName); git_win32_path_to_c(entry->d_name, d->f.cFileName);
entry->d_ino = 0; entry->d_ino = 0;
*result = entry; *result = entry;
@ -101,8 +96,8 @@ struct git__dirent *git__readdir(git__DIR *d)
void git__rewinddir(git__DIR *d) void git__rewinddir(git__DIR *d)
{ {
char filter[GIT_WIN_PATH]; git_win32_path_as_utf8 filter;
wchar_t filter_w[GIT_WIN_PATH]; git_win32_path filter_w;
if (!d) if (!d)
return; return;
@ -116,7 +111,7 @@ void git__rewinddir(git__DIR *d)
if (!init_filter(filter, sizeof(filter), d->dir)) if (!init_filter(filter, sizeof(filter), d->dir))
return; return;
git__utf8_to_16(filter_w, GIT_WIN_PATH, filter); git_win32_path_from_c(filter_w, filter);
d->h = FindFirstFileW(filter_w, &d->f); d->h = FindFirstFileW(filter_w, &d->f);
if (d->h == INVALID_HANDLE_VALUE) if (d->h == INVALID_HANDLE_VALUE)
@ -134,8 +129,7 @@ int git__closedir(git__DIR *d)
FindClose(d->h); FindClose(d->h);
d->h = INVALID_HANDLE_VALUE; d->h = INVALID_HANDLE_VALUE;
} }
git__free(d->dir);
d->dir = NULL;
git__free(d); git__free(d);
return 0; return 0;
} }

View File

@ -11,15 +11,15 @@
struct git__dirent { struct git__dirent {
int d_ino; int d_ino;
char d_name[261]; git_win32_path_as_utf8 d_name;
}; };
typedef struct { typedef struct {
HANDLE h; HANDLE h;
WIN32_FIND_DATAW f; WIN32_FIND_DATAW f;
struct git__dirent entry; struct git__dirent entry;
char *dir;
int first; int first;
char dir[GIT_FLEX_ARRAY];
} git__DIR; } git__DIR;
extern git__DIR *git__opendir(const char *); extern git__DIR *git__opendir(const char *);

View File

@ -23,11 +23,11 @@ int git_win32__expand_path(struct git_win32__path *s_root, const wchar_t *templ)
return s_root->len ? 0 : -1; return s_root->len ? 0 : -1;
} }
static int win32_path_utf16_to_8(git_buf *path_utf8, const wchar_t *path_utf16) static int win32_path_to_8(git_buf *path_utf8, const wchar_t *path)
{ {
char temp_utf8[GIT_PATH_MAX]; char temp_utf8[GIT_PATH_MAX];
git__utf16_to_8(temp_utf8, path_utf16); git__utf16_to_8(temp_utf8, GIT_PATH_MAX, path);
git_path_mkposix(temp_utf8); git_path_mkposix(temp_utf8);
return git_buf_sets(path_utf8, temp_utf8); return git_buf_sets(path_utf8, temp_utf8);
@ -53,7 +53,7 @@ int git_win32__find_file(
if (*filename == '/' || *filename == '\\') if (*filename == '/' || *filename == '\\')
filename++; filename++;
git__utf8_to_16(file_utf16 + root->len - 1, alloc_len, filename); git__utf8_to_16(file_utf16 + root->len - 1, alloc_len - root->len, filename);
/* check access */ /* check access */
if (_waccess(file_utf16, F_OK) < 0) { if (_waccess(file_utf16, F_OK) < 0) {
@ -61,7 +61,7 @@ int git_win32__find_file(
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
win32_path_utf16_to_8(path, file_utf16); win32_path_to_8(path, file_utf16);
git__free(file_utf16); git__free(file_utf16);
return 0; return 0;
@ -113,7 +113,7 @@ static int win32_find_git_in_path(git_buf *buf, const wchar_t *gitexe)
/* replace "bin\\" or "cmd\\" with "etc\\" */ /* replace "bin\\" or "cmd\\" with "etc\\" */
wcscpy(&root.path[root.len - 4], L"etc\\"); wcscpy(&root.path[root.len - 4], L"etc\\");
win32_path_utf16_to_8(buf, root.path); win32_path_to_8(buf, root.path);
return 0; return 0;
} }
} }
@ -146,7 +146,7 @@ static int win32_find_git_in_registry(
wcscat(path16.path, L"etc\\"); wcscat(path16.path, L"etc\\");
path16.len += 4; path16.len += 4;
win32_path_utf16_to_8(buf, path16.path); win32_path_to_8(buf, path16.path);
} }
RegCloseKey(hKey); RegCloseKey(hKey);
@ -168,7 +168,7 @@ static int win32_find_existing_dirs(
path16.path[0] != L'%' && path16.path[0] != L'%' &&
!_waccess(path16.path, F_OK)) !_waccess(path16.path, F_OK))
{ {
win32_path_utf16_to_8(&buf, path16.path); win32_path_to_8(&buf, path16.path);
if (buf.size) if (buf.size)
git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr);

View File

@ -8,7 +8,9 @@
#define INCLUDE_posix__w32_h__ #define INCLUDE_posix__w32_h__
#include "common.h" #include "common.h"
#include "../posix.h"
#include "utf-conv.h" #include "utf-conv.h"
#include "dir.h"
GIT_INLINE(int) p_link(const char *old, const char *new) GIT_INLINE(int) p_link(const char *old, const char *new)
{ {
@ -20,9 +22,9 @@ GIT_INLINE(int) p_link(const char *old, const char *new)
GIT_INLINE(int) p_mkdir(const char *path, mode_t mode) GIT_INLINE(int) p_mkdir(const char *path, mode_t mode)
{ {
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
GIT_UNUSED(mode); GIT_UNUSED(mode);
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
return _wmkdir(buf); return _wmkdir(buf);
} }

View File

@ -16,8 +16,8 @@
int p_unlink(const char *path) int p_unlink(const char *path)
{ {
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
_wchmod(buf, 0666); _wchmod(buf, 0666);
return _wunlink(buf); return _wunlink(buf);
} }
@ -59,10 +59,11 @@ static int do_lstat(
const char *file_name, struct stat *buf, int posix_enotdir) const char *file_name, struct stat *buf, int posix_enotdir)
{ {
WIN32_FILE_ATTRIBUTE_DATA fdata; WIN32_FILE_ATTRIBUTE_DATA fdata;
wchar_t fbuf[GIT_WIN_PATH], lastch; git_win32_path fbuf;
wchar_t lastch;
int flen; int flen;
flen = git__utf8_to_16(fbuf, GIT_WIN_PATH, file_name); flen = git_win32_path_from_c(fbuf, file_name);
/* truncate trailing slashes */ /* truncate trailing slashes */
for (; flen > 0; --flen) { for (; flen > 0; --flen) {
@ -108,10 +109,10 @@ static int do_lstat(
* the length of the path pointed to, which we expect everywhere else * the length of the path pointed to, which we expect everywhere else
*/ */
if (S_ISLNK(fMode)) { if (S_ISLNK(fMode)) {
char target[GIT_WIN_PATH]; git_win32_path_as_utf8 target;
int readlink_result; int readlink_result;
readlink_result = p_readlink(file_name, target, GIT_WIN_PATH); readlink_result = p_readlink(file_name, target, sizeof(target));
if (readlink_result == -1) if (readlink_result == -1)
return -1; return -1;
@ -165,7 +166,7 @@ int p_readlink(const char *link, char *target, size_t target_len)
static fpath_func pGetFinalPath = NULL; static fpath_func pGetFinalPath = NULL;
HANDLE hFile; HANDLE hFile;
DWORD dwRet; DWORD dwRet;
wchar_t link_w[GIT_WIN_PATH]; git_win32_path link_w;
wchar_t* target_w; wchar_t* target_w;
int error = 0; int error = 0;
@ -188,7 +189,7 @@ int p_readlink(const char *link, char *target, size_t target_len)
} }
} }
git__utf8_to_16(link_w, GIT_WIN_PATH, link); git_win32_path_from_c(link_w, link);
hFile = CreateFileW(link_w, // file to open hFile = CreateFileW(link_w, // file to open
GENERIC_READ, // open for reading GENERIC_READ, // open for reading
@ -254,10 +255,10 @@ int p_symlink(const char *old, const char *new)
int p_open(const char *path, int flags, ...) int p_open(const char *path, int flags, ...)
{ {
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
mode_t mode = 0; mode_t mode = 0;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
if (flags & O_CREAT) { if (flags & O_CREAT) {
va_list arg_list; va_list arg_list;
@ -272,8 +273,8 @@ int p_open(const char *path, int flags, ...)
int p_creat(const char *path, mode_t mode) int p_creat(const char *path, mode_t mode)
{ {
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
return _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode); return _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
} }
@ -299,7 +300,7 @@ int p_getcwd(char *buffer_out, size_t size)
int p_stat(const char* path, struct stat* buf) int p_stat(const char* path, struct stat* buf)
{ {
char target[GIT_WIN_PATH]; git_win32_path_as_utf8 target;
int error = 0; int error = 0;
error = do_lstat(path, buf, 0); error = do_lstat(path, buf, 0);
@ -307,7 +308,7 @@ int p_stat(const char* path, struct stat* buf)
/* We need not do this in a loop to unwind chains of symlinks since /* We need not do this in a loop to unwind chains of symlinks since
* p_readlink calls GetFinalPathNameByHandle which does it for us. */ * p_readlink calls GetFinalPathNameByHandle which does it for us. */
if (error >= 0 && S_ISLNK(buf->st_mode) && if (error >= 0 && S_ISLNK(buf->st_mode) &&
(error = p_readlink(path, target, GIT_WIN_PATH)) >= 0) (error = p_readlink(path, target, sizeof(target))) >= 0)
error = do_lstat(target, buf, 0); error = do_lstat(target, buf, 0);
return error; return error;
@ -315,23 +316,23 @@ int p_stat(const char* path, struct stat* buf)
int p_chdir(const char* path) int p_chdir(const char* path)
{ {
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
return _wchdir(buf); return _wchdir(buf);
} }
int p_chmod(const char* path, mode_t mode) int p_chmod(const char* path, mode_t mode)
{ {
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
return _wchmod(buf, mode); return _wchmod(buf, mode);
} }
int p_rmdir(const char* path) int p_rmdir(const char* path)
{ {
int error; int error;
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
error = _wrmdir(buf); error = _wrmdir(buf);
@ -347,24 +348,24 @@ int p_rmdir(const char* path)
int p_hide_directory__w32(const char *path) int p_hide_directory__w32(const char *path)
{ {
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
return (SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0) ? 0 : -1; return (SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0) ? 0 : -1;
} }
char *p_realpath(const char *orig_path, char *buffer) char *p_realpath(const char *orig_path, char *buffer)
{ {
int ret; int ret;
wchar_t orig_path_w[GIT_WIN_PATH]; git_win32_path orig_path_w;
wchar_t buffer_w[GIT_WIN_PATH]; git_win32_path buffer_w;
git__utf8_to_16(orig_path_w, GIT_WIN_PATH, orig_path); git_win32_path_from_c(orig_path_w, orig_path);
/* Implicitly use GetCurrentDirectory which can be a threading issue */ /* Implicitly use GetCurrentDirectory which can be a threading issue */
ret = GetFullPathNameW(orig_path_w, GIT_WIN_PATH, buffer_w, NULL); ret = GetFullPathNameW(orig_path_w, GIT_WIN_PATH_UTF16, buffer_w, NULL);
/* According to MSDN, a return value equals to zero means a failure. */ /* According to MSDN, a return value equals to zero means a failure. */
if (ret == 0 || ret > GIT_WIN_PATH) if (ret == 0 || ret > GIT_WIN_PATH_UTF16)
buffer = NULL; buffer = NULL;
else if (GetFileAttributesW(buffer_w) == INVALID_FILE_ATTRIBUTES) { else if (GetFileAttributesW(buffer_w) == INVALID_FILE_ATTRIBUTES) {
@ -448,18 +449,18 @@ int p_setenv(const char* name, const char* value, int overwrite)
int p_access(const char* path, mode_t mode) int p_access(const char* path, mode_t mode)
{ {
wchar_t buf[GIT_WIN_PATH]; git_win32_path buf;
git__utf8_to_16(buf, GIT_WIN_PATH, path); git_win32_path_from_c(buf, path);
return _waccess(buf, mode); return _waccess(buf, mode);
} }
int p_rename(const char *from, const char *to) int p_rename(const char *from, const char *to)
{ {
wchar_t wfrom[GIT_WIN_PATH]; git_win32_path wfrom;
wchar_t wto[GIT_WIN_PATH]; git_win32_path wto;
git__utf8_to_16(wfrom, GIT_WIN_PATH, from); git_win32_path_from_c(wfrom, from);
git__utf8_to_16(wto, GIT_WIN_PATH, to); git_win32_path_from_c(wto, to);
return MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1; return MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
} }
@ -513,10 +514,10 @@ p_gmtime_r (const time_t *timer, struct tm *result)
#else #else
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
#endif #endif
#ifndef _TIMEZONE_DEFINED #ifndef _TIMEZONE_DEFINED
#define _TIMEZONE_DEFINED #define _TIMEZONE_DEFINED
struct timezone struct timezone
{ {
int tz_minuteswest; /* minutes W of Greenwich */ int tz_minuteswest; /* minutes W of Greenwich */
int tz_dsttime; /* type of dst correction */ int tz_dsttime; /* type of dst correction */

View File

@ -70,12 +70,12 @@ void git__utf8_to_16(wchar_t *dest, size_t length, const char *src)
} }
#endif #endif
int git__utf8_to_16(wchar_t *dest, size_t length, const char *src) int git__utf8_to_16(wchar_t * dest, size_t dest_size, const char *src)
{ {
return MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, (int)length); return MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, (int)dest_size);
} }
int git__utf16_to_8(char *out, const wchar_t *input) int git__utf16_to_8(char *dest, size_t dest_size, const wchar_t *src)
{ {
return WideCharToMultiByte(CP_UTF8, 0, input, -1, out, GIT_WIN_PATH, NULL, NULL); return WideCharToMultiByte(CP_UTF8, 0, src, -1, dest, (int)dest_size, NULL, NULL);
} }

View File

@ -4,16 +4,35 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with * This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file. * a Linking Exception. For full terms see the included COPYING file.
*/ */
#include <wchar.h>
#ifndef INCLUDE_git_utfconv_h__ #ifndef INCLUDE_git_utfconv_h__
#define INCLUDE_git_utfconv_h__ #define INCLUDE_git_utfconv_h__
#define GIT_WIN_PATH (260 + 1) #include <wchar.h>
#include "common.h"
int git__utf8_to_16(wchar_t *dest, size_t length, const char *src); /* Maximum characters in a Windows path plus one for NUL byte */
int git__utf16_to_8(char *dest, const wchar_t *src); #define GIT_WIN_PATH_UTF16 (260 + 1)
/* Maximum bytes necessary to convert a full-length UTF16 path to UTF8 */
#define GIT_WIN_PATH_UTF8 (260 * 4 + 1)
typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16];
typedef char git_win32_path_as_utf8[GIT_WIN_PATH_UTF8];
/* 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 */
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)
{
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)
{
return git__utf16_to_8(dest, GIT_WIN_PATH_UTF8, src);
}
#endif #endif

View File

@ -677,3 +677,22 @@ void test_checkout_tree__target_directory_from_bare(void)
cl_git_pass(git_futils_rmdir_r( cl_git_pass(git_futils_rmdir_r(
"alternative", NULL, GIT_RMDIR_REMOVE_FILES)); "alternative", NULL, GIT_RMDIR_REMOVE_FILES));
} }
void test_checkout_tree__extremely_long_file_name(void)
{
// A utf-8 string with 83 characters, but 249 bytes.
const char *longname = "\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97";
char path[1024];
g_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_git_pass(git_revparse_single(&g_object, g_repo, "long-file-name"));
cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts));
sprintf(path, "testrepo/%s.txt", longname);
cl_assert(git_path_exists(path));
git_object_free(g_object);
cl_git_pass(git_revparse_single(&g_object, g_repo, "master"));
cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts));
cl_assert(!git_path_exists(path));
}

View File

@ -56,23 +56,24 @@ void cl_git_rewritefile(const char *filename, const char *new_content)
char *cl_getenv(const char *name) char *cl_getenv(const char *name)
{ {
wchar_t name_utf16[GIT_WIN_PATH]; git_win32_path name_utf16;
DWORD alloc_len; DWORD alloc_len;
wchar_t *value_utf16; wchar_t *value_utf16;
char *value_utf8; char *value_utf8;
git__utf8_to_16(name_utf16, GIT_WIN_PATH, name); git_win32_path_from_c(name_utf16, name);
alloc_len = GetEnvironmentVariableW(name_utf16, NULL, 0); alloc_len = GetEnvironmentVariableW(name_utf16, NULL, 0);
if (alloc_len <= 0) if (alloc_len <= 0)
return NULL; return NULL;
alloc_len = GIT_WIN_PATH;
cl_assert(value_utf16 = git__calloc(alloc_len, sizeof(wchar_t))); cl_assert(value_utf16 = git__calloc(alloc_len, sizeof(wchar_t)));
GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len); GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len);
cl_assert(value_utf8 = git__malloc(alloc_len)); alloc_len = alloc_len * 4 + 1; /* worst case UTF16->UTF8 growth */
git__utf16_to_8(value_utf8, value_utf16); cl_assert(value_utf8 = git__calloc(alloc_len, 1));
git__utf16_to_8(value_utf8, alloc_len, value_utf16);
git__free(value_utf16); git__free(value_utf16);
@ -81,13 +82,13 @@ char *cl_getenv(const char *name)
int cl_setenv(const char *name, const char *value) int cl_setenv(const char *name, const char *value)
{ {
wchar_t name_utf16[GIT_WIN_PATH]; git_win32_path name_utf16;
wchar_t value_utf16[GIT_WIN_PATH]; git_win32_path value_utf16;
git__utf8_to_16(name_utf16, GIT_WIN_PATH, name); git_win32_path_from_c(name_utf16, name);
if (value) { if (value) {
git__utf8_to_16(value_utf16, GIT_WIN_PATH, value); git_win32_path_from_c(value_utf16, value);
cl_assert(SetEnvironmentVariableW(name_utf16, value_utf16)); cl_assert(SetEnvironmentVariableW(name_utf16, value_utf16));
} else { } else {
/* Windows XP returns 0 (failed) when passing NULL for lpValue when /* Windows XP returns 0 (failed) when passing NULL for lpValue when
@ -107,12 +108,12 @@ int cl_setenv(const char *name, const char *value)
* the source is a directory, a child of the source). */ * the source is a directory, a child of the source). */
int cl_rename(const char *source, const char *dest) int cl_rename(const char *source, const char *dest)
{ {
wchar_t source_utf16[GIT_WIN_PATH]; git_win32_path source_utf16;
wchar_t dest_utf16[GIT_WIN_PATH]; git_win32_path dest_utf16;
unsigned retries = 1; unsigned retries = 1;
git__utf8_to_16(source_utf16, GIT_WIN_PATH, source); git_win32_path_from_c(source_utf16, source);
git__utf8_to_16(dest_utf16, GIT_WIN_PATH, dest); git_win32_path_from_c(dest_utf16, dest);
while (!MoveFileW(source_utf16, dest_utf16)) { while (!MoveFileW(source_utf16, dest_utf16)) {
/* Only retry if the error is ERROR_ACCESS_DENIED; /* Only retry if the error is ERROR_ACCESS_DENIED;

View File

@ -36,7 +36,7 @@ void test_refs_list__all(void)
/* We have exactly 12 refs in total if we include the packed ones: /* We have exactly 12 refs in total if we include the packed ones:
* there is a reference that exists both in the packfile and as * there is a reference that exists both in the packfile and as
* loose, but we only list it once */ * loose, but we only list it once */
cl_assert_equal_i((int)ref_list.count, 13); cl_assert_equal_i((int)ref_list.count, 14);
git_strarray_free(&ref_list); git_strarray_free(&ref_list);
} }
@ -51,7 +51,7 @@ void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_exten
"144344043ba4d4a405da03de3844aa829ae8be0e\n"); "144344043ba4d4a405da03de3844aa829ae8be0e\n");
cl_git_pass(git_reference_list(&ref_list, g_repo)); cl_git_pass(git_reference_list(&ref_list, g_repo));
cl_assert_equal_i((int)ref_list.count, 13); cl_assert_equal_i((int)ref_list.count, 14);
git_strarray_free(&ref_list); git_strarray_free(&ref_list);
} }

View File

@ -906,6 +906,7 @@ void test_repo_iterator__fs2(void)
static const char *expect_base[] = { static const char *expect_base[] = {
"heads/br2", "heads/br2",
"heads/dir", "heads/dir",
"heads/long-file-name",
"heads/master", "heads/master",
"heads/packed-test", "heads/packed-test",
"heads/subtrees", "heads/subtrees",
@ -922,6 +923,6 @@ void test_repo_iterator__fs2(void)
cl_git_pass(git_iterator_for_filesystem( cl_git_pass(git_iterator_for_filesystem(
&i, "testrepo/.git/refs", 0, NULL, NULL)); &i, "testrepo/.git/refs", 0, NULL, NULL));
expect_iterator_items(i, 11, expect_base, 11, expect_base); expect_iterator_items(i, 12, expect_base, 12, expect_base);
git_iterator_free(i); git_iterator_free(i);
} }

View File

@ -0,0 +1 @@
6b377958d8c6a4906e8573b53672a1a23a4e8ce6

View File

@ -177,7 +177,7 @@ void test_revwalk_basic__glob_heads_with_invalid(void)
/* walking */; /* walking */;
/* git log --branches --oneline | wc -l => 16 */ /* git log --branches --oneline | wc -l => 16 */
cl_assert_equal_i(16, i); cl_assert_equal_i(17, i);
} }
void test_revwalk_basic__push_head(void) void test_revwalk_basic__push_head(void)

View File

@ -1,5 +1,9 @@
#include "status_helpers.h" #include "status_helpers.h"
// A utf-8 string with 83 characters, but 249 bytes.
static const char *longname = "\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97";
/* entries for a plain copy of tests/resources/status */ /* entries for a plain copy of tests/resources/status */
static const char *entry_paths0[] = { static const char *entry_paths0[] = {

View File

@ -865,3 +865,35 @@ void test_status_worktree__sorting_by_case(void)
cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path); cl_assert_equal_i(0, counts.wrong_sorted_path);
} }
void test_status_worktree__long_filenames(void)
{
char path[260*4+1];
const char *expected_paths[] = {path};
const unsigned int expected_statuses[] = {GIT_STATUS_WT_NEW};
git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
status_entry_counts counts = {0};
// Create directory with amazingly long filename
sprintf(path, "empty_standard_repo/%s", longname);
cl_git_pass(git_futils_mkdir_r(path, NULL, 0777));
sprintf(path, "empty_standard_repo/%s/foo", longname);
cl_git_mkfile(path, "dummy");
sprintf(path, "%s/foo", longname);
counts.expected_entry_count = 1;
counts.expected_paths = expected_paths;
counts.expected_statuses = expected_statuses;
opts.show = GIT_STATUS_SHOW_WORKDIR_ONLY;
opts.flags = GIT_STATUS_OPT_DEFAULTS;
cl_git_pass(
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts) );
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
}