Commit 7110000d by Philip Kelley

React to feedback for UTF-8 <-> WCHAR and reparse work

parent 65477db1
...@@ -495,7 +495,7 @@ bool git_path_is_empty_dir(const char *path) ...@@ -495,7 +495,7 @@ bool git_path_is_empty_dir(const char *path)
HANDLE hFind = FindFirstFileW(filter_w, &findData); HANDLE hFind = FindFirstFileW(filter_w, &findData);
/* If the find handle was created successfully, then it's a directory */ /* If the find handle was created successfully, then it's a directory */
if (INVALID_HANDLE_VALUE != hFind) { if (hFind != INVALID_HANDLE_VALUE) {
empty = true; empty = true;
do { do {
......
...@@ -22,6 +22,15 @@ ...@@ -22,6 +22,15 @@
#define GIT_DATE_RFC2822_SZ 32 #define GIT_DATE_RFC2822_SZ 32
/**
* Return the length of a constant string.
* We are aware that `strlen` performs the same task and is usually
* optimized away by the compiler, whilst being safer because it returns
* valid values when passed a pointer instead of a constant string; however
* this macro will transparently work with wide-char and single-char strings.
*/
#define CONST_STRLEN(x) ((sizeof(x)/sizeof(x[0])) - 1)
/* /*
* Custom memory allocation wrappers * Custom memory allocation wrappers
* that set error code and error message * that set error code and error message
......
...@@ -119,7 +119,7 @@ static int win32_find_git_in_registry( ...@@ -119,7 +119,7 @@ static int win32_find_git_in_registry(
/* InstallLocation points to the root of the git directory */ /* InstallLocation points to the root of the git directory */
if (!RegQueryValueExW(hKey, L"InstallLocation", NULL, &dwType, (LPBYTE)path, &cbData) && if (!RegQueryValueExW(hKey, L"InstallLocation", NULL, &dwType, (LPBYTE)path, &cbData) &&
REG_SZ == dwType) { dwType == REG_SZ) {
/* Append the suffix */ /* Append the suffix */
wcscat(path, subdir); wcscat(path, subdir);
......
...@@ -62,7 +62,7 @@ int p_unlink(const char *path) ...@@ -62,7 +62,7 @@ int p_unlink(const char *path)
/* If the file could not be deleted because it was /* If the file could not be deleted because it was
* read-only, clear the bit and try again */ * read-only, clear the bit and try again */
if (-1 == error && EACCES == errno) { if (error == -1 && errno == EACCES) {
_wchmod(buf, 0666); _wchmod(buf, 0666);
error = _wunlink(buf); error = _wunlink(buf);
} }
...@@ -120,7 +120,7 @@ static int readlink_w( ...@@ -120,7 +120,7 @@ static int readlink_w(
FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (INVALID_HANDLE_VALUE == handle) { if (handle == INVALID_HANDLE_VALUE) {
errno = ENOENT; errno = ENOENT;
return -1; return -1;
} }
...@@ -149,7 +149,7 @@ static int readlink_w( ...@@ -149,7 +149,7 @@ static int readlink_w(
if (target_len) { if (target_len) {
/* The path may need to have a prefix removed. */ /* The path may need to have a prefix removed. */
target_len = git_win32__to_dos(target, target_len); target_len = git_win32__canonicalize_path(target, target_len);
/* Need one additional character in the target buffer /* Need one additional character in the target buffer
* for the terminating NULL. */ * for the terminating NULL. */
...@@ -235,7 +235,7 @@ static int lstat_w( ...@@ -235,7 +235,7 @@ static int lstat_w(
path[path_len] = L'\0'; path[path_len] = L'\0';
attrs = GetFileAttributesW(path); attrs = GetFileAttributesW(path);
if (INVALID_FILE_ATTRIBUTES != attrs) { if (attrs != INVALID_FILE_ATTRIBUTES) {
if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) if (!(attrs & FILE_ATTRIBUTE_DIRECTORY))
errno = ENOTDIR; errno = ENOTDIR;
break; break;
...@@ -393,23 +393,18 @@ static int getfinalpath_w( ...@@ -393,23 +393,18 @@ static int getfinalpath_w(
hFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, hFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile == INVALID_HANDLE_VALUE) if (INVALID_HANDLE_VALUE == hFile)
return -1; return -1;
/* Call GetFinalPathNameByHandle */ /* Call GetFinalPathNameByHandle */
dwChars = pgfp(hFile, dest, GIT_WIN_PATH_UTF16, FILE_NAME_NORMALIZED); dwChars = pgfp(hFile, dest, GIT_WIN_PATH_UTF16, FILE_NAME_NORMALIZED);
CloseHandle(hFile);
if (!dwChars || dwChars >= GIT_WIN_PATH_UTF16) { if (!dwChars || dwChars >= GIT_WIN_PATH_UTF16)
DWORD error = GetLastError();
CloseHandle(hFile);
SetLastError(error);
return -1; return -1;
}
CloseHandle(hFile);
/* The path may be delivered to us with a prefix; canonicalize */ /* The path may be delivered to us with a prefix; canonicalize */
return (int)git_win32__to_dos(dest, dwChars); return (int)git_win32__canonicalize_path(dest, dwChars);
} }
static int follow_and_lstat_link(git_win32_path path, struct stat* buf) static int follow_and_lstat_link(git_win32_path path, struct stat* buf)
...@@ -473,7 +468,7 @@ int p_rmdir(const char* path) ...@@ -473,7 +468,7 @@ int p_rmdir(const char* path)
error = _wrmdir(buf); error = _wrmdir(buf);
if (-1 == error) { if (error == -1) {
switch (GetLastError()) { switch (GetLastError()) {
/* _wrmdir() is documented to return EACCES if "A program has an open /* _wrmdir() is documented to return EACCES if "A program has an open
* handle to the directory." This sounds like what everybody else calls * handle to the directory." This sounds like what everybody else calls
...@@ -513,7 +508,7 @@ char *p_realpath(const char *orig_path, char *buffer) ...@@ -513,7 +508,7 @@ char *p_realpath(const char *orig_path, char *buffer)
} }
/* The path must exist. */ /* The path must exist. */
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(buffer_w)) { if (GetFileAttributesW(buffer_w) == INVALID_FILE_ATTRIBUTES) {
errno = ENOENT; errno = ENOENT;
return NULL; return NULL;
} }
......
...@@ -54,4 +54,4 @@ typedef struct _GIT_REPARSE_DATA_BUFFER { ...@@ -54,4 +54,4 @@ typedef struct _GIT_REPARSE_DATA_BUFFER {
# define FSCTL_SET_REPARSE_POINT 0x000900a4 # define FSCTL_SET_REPARSE_POINT 0x000900a4
#endif #endif
#endif #endif
\ No newline at end of file
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "utf-conv.h" #include "utf-conv.h"
#ifndef WC_ERR_INVALID_CHARS #ifndef WC_ERR_INVALID_CHARS
#define WC_ERR_INVALID_CHARS 0x80 # define WC_ERR_INVALID_CHARS 0x80
#endif #endif
GIT_INLINE(DWORD) get_wc_flags(void) GIT_INLINE(DWORD) get_wc_flags(void)
...@@ -87,12 +87,8 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src) ...@@ -87,12 +87,8 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, *dest, utf16_size); utf16_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src, -1, *dest, utf16_size);
if (!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); git__free(*dest);
*dest = NULL; *dest = NULL;
SetLastError(last_error);
} }
/* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL
...@@ -131,12 +127,8 @@ int git__utf16_to_8_alloc(char **dest, const wchar_t *src) ...@@ -131,12 +127,8 @@ int git__utf16_to_8_alloc(char **dest, const wchar_t *src)
utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, src, -1, *dest, utf8_size, NULL, NULL); utf8_size = WideCharToMultiByte(CP_UTF8, dwFlags, src, -1, *dest, utf8_size, NULL, NULL);
if (!utf8_size) { 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); git__free(*dest);
*dest = NULL; *dest = NULL;
SetLastError(last_error);
} }
/* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL /* Subtract 1 from the result to turn 0 into -1 (an error code) and to not count the NULL
......
...@@ -7,8 +7,6 @@ ...@@ -7,8 +7,6 @@
#include "w32_util.h" #include "w32_util.h"
#define CONST_STRLEN(x) ((sizeof(x)/sizeof(x[0])) - 1)
/** /**
* Creates a FindFirstFile(Ex) filter string from a UTF-8 path. * Creates a FindFirstFile(Ex) filter string from a UTF-8 path.
* The filter string enumerates all items in the directory. * The filter string enumerates all items in the directory.
...@@ -26,8 +24,10 @@ bool git_win32__findfirstfile_filter(git_win32_path dest, const char *src) ...@@ -26,8 +24,10 @@ bool git_win32__findfirstfile_filter(git_win32_path dest, const char *src)
if (len < 0) if (len < 0)
return false; return false;
/* Ensure that the path does not end with a trailing slash -- /* Ensure that the path does not end with a trailing slash,
* because we're about to add one! */ * because we're about to add one. Don't rely our trim_end
* helper, because we want to remove the backslash even for
* drive letter paths, in this case. */
if (len > 0 && if (len > 0 &&
(dest[len - 1] == L'/' || dest[len - 1] == L'\\')) { (dest[len - 1] == L'/' || dest[len - 1] == L'\\')) {
dest[len - 1] = L'\0'; dest[len - 1] = L'\0';
...@@ -35,7 +35,7 @@ bool git_win32__findfirstfile_filter(git_win32_path dest, const char *src) ...@@ -35,7 +35,7 @@ bool git_win32__findfirstfile_filter(git_win32_path dest, const char *src)
} }
/* Ensure we have enough room to add the suffix */ /* Ensure we have enough room to add the suffix */
if ((size_t)len > GIT_WIN_PATH_UTF16 - ARRAY_SIZE(suffix)) if ((size_t)len >= GIT_WIN_PATH_UTF16 - CONST_STRLEN(suffix))
return false; return false;
wcscat(dest, suffix); wcscat(dest, suffix);
...@@ -59,11 +59,11 @@ int git_win32__sethidden(const char *path) ...@@ -59,11 +59,11 @@ int git_win32__sethidden(const char *path)
attrs = GetFileAttributesW(buf); attrs = GetFileAttributesW(buf);
/* Ensure the path exists */ /* Ensure the path exists */
if (INVALID_FILE_ATTRIBUTES == attrs) if (attrs == INVALID_FILE_ATTRIBUTES)
return -1; return -1;
/* If the item isn't already +H, add the bit */ /* If the item isn't already +H, add the bit */
if (0 == (attrs & FILE_ATTRIBUTE_HIDDEN) && if ((attrs & FILE_ATTRIBUTE_HIDDEN) == 0 &&
!SetFileAttributesW(buf, attrs | FILE_ATTRIBUTE_HIDDEN)) !SetFileAttributesW(buf, attrs | FILE_ATTRIBUTE_HIDDEN))
return -1; return -1;
...@@ -85,7 +85,7 @@ size_t git_win32__path_trim_end(wchar_t *str, size_t len) ...@@ -85,7 +85,7 @@ size_t git_win32__path_trim_end(wchar_t *str, size_t len)
/* Don't trim backslashes from drive letter paths, which /* Don't trim backslashes from drive letter paths, which
* are 3 characters long and of the form C:\, D:\, etc. */ * are 3 characters long and of the form C:\, D:\, etc. */
if (3 == len && git_win32__isalpha(str[0]) && str[1] == ':') if (len == 3 && git_win32__isalpha(str[0]) && str[1] == ':')
break; break;
len--; len--;
...@@ -103,7 +103,7 @@ size_t git_win32__path_trim_end(wchar_t *str, size_t len) ...@@ -103,7 +103,7 @@ size_t git_win32__path_trim_end(wchar_t *str, size_t len)
* @param path The path which should be converted. * @param path The path which should be converted.
* @return The length of the modified string (<= the input length) * @return The length of the modified string (<= the input length)
*/ */
size_t git_win32__to_dos(wchar_t *str, size_t len) size_t git_win32__canonicalize_path(wchar_t *str, size_t len)
{ {
static const wchar_t dosdevices_prefix[] = L"\\\?\?\\"; static const wchar_t dosdevices_prefix[] = L"\\\?\?\\";
static const wchar_t nt_prefix[] = L"\\\\?\\"; static const wchar_t nt_prefix[] = L"\\\\?\\";
...@@ -136,4 +136,4 @@ size_t git_win32__to_dos(wchar_t *str, size_t len) ...@@ -136,4 +136,4 @@ size_t git_win32__to_dos(wchar_t *str, size_t len)
} }
return git_win32__path_trim_end(str, len); return git_win32__path_trim_end(str, len);
} }
\ No newline at end of file
...@@ -49,6 +49,6 @@ size_t git_win32__path_trim_end(wchar_t *str, size_t len); ...@@ -49,6 +49,6 @@ size_t git_win32__path_trim_end(wchar_t *str, size_t len);
* @param path The path which should be converted. * @param path The path which should be converted.
* @return The length of the modified string (<= the input length) * @return The length of the modified string (<= the input length)
*/ */
size_t git_win32__to_dos(wchar_t *str, size_t len); size_t git_win32__canonicalize_path(wchar_t *str, size_t len);
#endif #endif
...@@ -137,7 +137,7 @@ static void do_junction(const char *old, const char *new) ...@@ -137,7 +137,7 @@ static void do_junction(const char *old, const char *new)
reparse_buf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; reparse_buf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
reparse_buf->MountPointReparseBuffer.SubstituteNameOffset = 0; reparse_buf->MountPointReparseBuffer.SubstituteNameOffset = 0;
reparse_buf->MountPointReparseBuffer.SubstituteNameLength = subst_byte_len; reparse_buf->MountPointReparseBuffer.SubstituteNameLength = subst_byte_len;
reparse_buf->MountPointReparseBuffer.PrintNameOffset = (USHORT)(subst_byte_len + sizeof(WCHAR)); reparse_buf->MountPointReparseBuffer.PrintNameOffset = (USHORT)(subst_byte_len + sizeof(WCHAR));
reparse_buf->MountPointReparseBuffer.PrintNameLength = print_byte_len; reparse_buf->MountPointReparseBuffer.PrintNameLength = print_byte_len;
reparse_buf->ReparseDataLength = reparse_buflen - REPARSE_DATA_HEADER_SIZE; reparse_buf->ReparseDataLength = reparse_buflen - REPARSE_DATA_HEADER_SIZE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment