From 4acde210fd75fa4daf9dee6a14f429d57f79b38f Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Sun, 24 Jul 2016 03:43:17 +0200 Subject: [PATCH] rework long path normalization stuf Simplify, set error codes, ensure 32-bit is ok as well. The canonicalization part is still an issue on win7 as the API is missing there. However a partial improvement is reached there as well thanks to the slash conversion. --- win32/ioutil.c | 41 ++++++++++++++++++++--------------------- win32/ioutil.h | 12 +++++++++++- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/win32/ioutil.c b/win32/ioutil.c index 1bf88c44b8..fc4413b2dd 100644 --- a/win32/ioutil.c +++ b/win32/ioutil.c @@ -66,7 +66,7 @@ #include */ -typedef HRESULT (WINAPI *MyPathCchCanonicalizeEx)(wchar_t *pszPathOut, size_t cchPathOut, const wchar_t *pszPathIn, unsigned long dwFlags); +typedef HRESULT (__stdcall *MyPathCchCanonicalizeEx)(wchar_t *pszPathOut, size_t cchPathOut, const wchar_t *pszPathIn, unsigned long dwFlags); static MyPathCchCanonicalizeEx canonicalize_path_w = NULL; @@ -506,14 +506,14 @@ PW32IO size_t php_win32_ioutil_dirname(char *path, size_t len) return ret_len; }/*}}}*/ -PW32IO BOOL php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len) +PW32IO php_win32_ioutil_normalization_result php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len) {/*{{{*/ wchar_t *pos, *idx = *buf, canonicalw[MAXPATHLEN]; - size_t ret_len = len, canonicalw_len, shift; + size_t ret_len = len; if (len >= MAXPATHLEN) { - SET_ERRNO_FROM_WIN32_CODE(ERROR_BUFFER_OVERFLOW); - return FALSE; + SET_ERRNO_FROM_WIN32_CODE(ERROR_BAD_LENGTH); + return PHP_WIN32_IOUTIL_NORM_FAIL; } while (NULL != (pos = wcschr(idx, PHP_WIN32_IOUTIL_FW_SLASHW)) && idx - *buf <= len) { @@ -521,30 +521,29 @@ PW32IO BOOL php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t idx = pos++; } - shift = PHP_WIN32_IOUTIL_IS_LONG_PATHW(*buf, len) ? PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW : 0; - if (S_OK != canonicalize_path_w(canonicalw, MAXPATHLEN, *buf + shift, PATHCCH_ALLOW_LONG_PATHS)) { - *new_len = ret_len; - return FALSE; + if (S_OK != canonicalize_path_w(canonicalw, MAXPATHLEN, *buf, PATHCCH_ALLOW_LONG_PATHS)) { + return PHP_WIN32_IOUTIL_NORM_PARTIAL; } - canonicalw_len = wcslen(canonicalw); - if (canonicalw_len + shift != len) { - if (canonicalw_len > len) { - *buf = realloc(*buf, (canonicalw_len + 1) * sizeof(wchar_t)); + ret_len = wcslen(canonicalw); + if (ret_len != len) { + if (ret_len > len) { + wchar_t *tmp = realloc(*buf, (ret_len + 1) * sizeof(wchar_t)); + if (!tmp) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_ENOUGH_MEMORY); + return PHP_WIN32_IOUTIL_NORM_PARTIAL; + } + *buf = tmp; } - memmove(*buf + shift, canonicalw, (canonicalw_len + 1) * sizeof(wchar_t)); - ret_len = canonicalw_len + shift; + memmove(*buf, canonicalw, (ret_len + 1) * sizeof(wchar_t)); } *new_len = ret_len; - return TRUE; + return PHP_WIN32_IOUTIL_NORM_OK; }/*}}}*/ -static HRESULT MyPathCchCanonicalizeExFallback(wchar_t *pszPathOut, size_t cchPathOut, const wchar_t *pszPathIn, unsigned long dwFlags) +static HRESULT __stdcall MyPathCchCanonicalizeExFallback(wchar_t *pszPathOut, size_t cchPathOut, const wchar_t *pszPathIn, unsigned long dwFlags) {/*{{{*/ - cchPathOut = wcslen(pszPathIn); - memmove(pszPathOut, pszPathIn, (cchPathOut + 1) * sizeof(wchar_t)); - - return S_OK; + return -42; }/*}}}*/ BOOL php_win32_ioutil_init(void) diff --git a/win32/ioutil.h b/win32/ioutil.h index a11c64912e..a97bbd7f56 100644 --- a/win32/ioutil.h +++ b/win32/ioutil.h @@ -87,6 +87,11 @@ typedef enum { PHP_WIN32_IOUTIL_IS_UTF8 } php_win32_ioutil_encoding; +typedef enum { + PHP_WIN32_IOUTIL_NORM_OK, + PHP_WIN32_IOUTIL_NORM_PARTIAL, + PHP_WIN32_IOUTIL_NORM_FAIL, +} php_win32_ioutil_normalization_result; #define PHP_WIN32_IOUTIL_FW_SLASHW L'/' #define PHP_WIN32_IOUTIL_FW_SLASH '/' @@ -133,7 +138,7 @@ typedef enum { } \ } while (0); -PW32IO BOOL php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len); +PW32IO php_win32_ioutil_normalization_result php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len); #ifdef PHP_EXPORTS /* This symbols are needed only for the DllMain, but should not be exported or be available when used with PHP binaries. */ @@ -160,6 +165,11 @@ __forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, siz return NULL; } + /* The return can be ignored here, as the normalization can fail for + various reasons not directly related to the operation itself. + Partial normalization could still do a better job further. And + otherwise, the path might be unchanged which is ok if the path + was valid long one. */ (void)php_win32_ioutil_normalize_path_w(&mb, mb_len, &mb_len); if (PHP_WIN32_IOUTIL_IS_LONG_PATHW(mb, mb_len)) { -- 2.40.0