diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:23:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:23:09 +0000 |
commit | 30d479c28c831a0d4f1fdb54a9e346b0fc176be1 (patch) | |
tree | aa35d7414ce9f1326abf6f723f6dfa5b0aa08b1d /misc/win32 | |
parent | Initial commit. (diff) | |
download | apr-upstream/1.7.2.tar.xz apr-upstream/1.7.2.zip |
Adding upstream version 1.7.2.upstream/1.7.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'misc/win32')
-rw-r--r-- | misc/win32/apr_app.c | 104 | ||||
-rw-r--r-- | misc/win32/charset.c | 55 | ||||
-rw-r--r-- | misc/win32/env.c | 192 | ||||
-rw-r--r-- | misc/win32/internal.c | 101 | ||||
-rw-r--r-- | misc/win32/misc.c | 266 | ||||
-rw-r--r-- | misc/win32/rand.c | 69 | ||||
-rw-r--r-- | misc/win32/start.c | 232 | ||||
-rw-r--r-- | misc/win32/utf8.c | 259 |
8 files changed, 1278 insertions, 0 deletions
diff --git a/misc/win32/apr_app.c b/misc/win32/apr_app.c new file mode 100644 index 0000000..4b1874f --- /dev/null +++ b/misc/win32/apr_app.c @@ -0,0 +1,104 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Usage Notes: + * + * this module, and the misc/win32/utf8.c modules must be + * compiled APR_EXPORT_STATIC and linked to an application with + * the /entry:wmainCRTStartup flag (which this module kindly + * provides to the developer who links to libaprapp-1.lib). + * This module becomes the true wmain entry point, and passes + * utf-8 reformatted argv and env arrays to the application's + * main() function as if nothing happened. + * + * This module is only compatible with Unicode operating systems. + * Mixed (Win9x backwards compatible) binaries should refer instead + * to the apr_startup.c module. + * + * _dbg_malloc/realloc is used in place of the usual API, in order + * to convince the MSVCRT that it created these entities. If we + * do not create them as _CRT_BLOCK entities, the crt will fault + * on an assert. We are not worrying about the crt's locks here, + * since we are single threaded [so far]. + */ + +#include "apr_general.h" +#include "ShellAPI.h" +#include "wchar.h" +#include "apr_arch_file_io.h" +#include "assert.h" +#include "apr_private.h" +#include "apr_arch_misc.h" + +#pragma comment(linker,"/ENTRY:wmainCRTStartup") + +extern int main(int argc, const char **argv, const char **env); + +int wmain(int argc, const wchar_t **wargv, const wchar_t **wenv) +{ + char **argv; + char **env; + int envc; + int i; + + (void)apr_wastrtoastr(&argv, wargv, argc); + + envc = 0; + while (wenv[envc]) { + envc++; + } + + /* Initial environment stored as single heap block, but uses + * separate heap entry for every environment variable + * after first change. + */ + env = apr_malloc_dbg((envc + 1) * sizeof(char *), __FILE__, __LINE__); + + for (i = 0; i < envc; i++) { + apr_size_t wcount; + apr_size_t envlen; + + wcount = wcslen(wenv[i]) + 1; + envlen = (wcount - 1) * 3 + 1; + + env[i] = apr_malloc_dbg(envlen, __FILE__, __LINE__); + + (void)apr_conv_ucs2_to_utf8(wenv[i], &wcount, env[i], &envlen); + } + + env[i] = NULL; + + _environ = env; + + /* MSVCRT will attempt to maintain the wide environment calls + * on _putenv(), which is bogus if we've passed a non-ascii + * string to _putenv(), since they use MultiByteToWideChar + * and breaking the implicit utf-8 assumption we've built. + * + * Reset _wenviron for good measure. + */ + if (_wenviron) { + _wenviron = NULL; + + /* There is no need to free _wenviron because MSVCRT + * automatically free 'initial' environment block. + */ + } + + apr_app_init_complete = 1; + + return main(argc, argv, env); +} diff --git a/misc/win32/charset.c b/misc/win32/charset.c new file mode 100644 index 0000000..41135b2 --- /dev/null +++ b/misc/win32/charset.c @@ -0,0 +1,55 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include "apr_strings.h" +#include "apr_portable.h" + + +APR_DECLARE(const char*) apr_os_default_encoding (apr_pool_t *pool) +{ + return apr_psprintf(pool, "CP%u", (unsigned) GetACP()); +} + + +APR_DECLARE(const char*) apr_os_locale_encoding (apr_pool_t *pool) +{ +#ifdef _UNICODE + int i; +#endif +#if defined(_WIN32_WCE) + LCID locale = GetUserDefaultLCID(); +#else + LCID locale = GetThreadLocale(); +#endif + int len = GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, NULL, 0); + char *cp = apr_palloc(pool, (len * sizeof(TCHAR)) + 2); + if (0 < GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, (TCHAR*) (cp + 2), len)) + { + /* Fix up the returned number to make a valid codepage name of + the form "CPnnnn". */ + cp[0] = 'C'; + cp[1] = 'P'; +#ifdef _UNICODE + for(i = 0; i < len; i++) { + cp[i + 2] = (char) ((TCHAR*) (cp + 2))[i]; + } +#endif + return cp; + } + + return apr_os_default_encoding(pool); +} diff --git a/misc/win32/env.c b/misc/win32/env.c new file mode 100644 index 0000000..644f59b --- /dev/null +++ b/misc/win32/env.c @@ -0,0 +1,192 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define APR_WANT_STRFUNC +#include "apr_want.h" +#include "apr.h" +#include "apr_arch_misc.h" +#include "apr_arch_utf8.h" +#include "apr_env.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_strings.h" + +#if APR_HAS_UNICODE_FS && !defined(_WIN32_WCE) +static apr_status_t widen_envvar_name (apr_wchar_t *buffer, + apr_size_t bufflen, + const char *envvar) +{ + apr_size_t inchars; + apr_status_t status; + + inchars = strlen(envvar) + 1; + status = apr_conv_utf8_to_ucs2(envvar, &inchars, buffer, &bufflen); + if (status == APR_INCOMPLETE) + status = APR_ENAMETOOLONG; + + return status; +} +#endif + + +APR_DECLARE(apr_status_t) apr_env_get(char **value, + const char *envvar, + apr_pool_t *pool) +{ +#if defined(_WIN32_WCE) + return APR_ENOTIMPL; +#else + char *val = NULL; + DWORD size; + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wenvvar[APR_PATH_MAX]; + apr_size_t inchars, outchars; + apr_wchar_t *wvalue, dummy; + apr_status_t status; + + status = widen_envvar_name(wenvvar, APR_PATH_MAX, envvar); + if (status) + return status; + + SetLastError(0); + size = GetEnvironmentVariableW(wenvvar, &dummy, 0); + if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) + /* The environment variable doesn't exist. */ + return APR_ENOENT; + + if (size == 0) { + /* The environment value exists, but is zero-length. */ + *value = apr_pstrdup(pool, ""); + return APR_SUCCESS; + } + + wvalue = apr_palloc(pool, size * sizeof(*wvalue)); + size = GetEnvironmentVariableW(wenvvar, wvalue, size); + + inchars = wcslen(wvalue) + 1; + outchars = 3 * inchars; /* Enough for any UTF-8 representation */ + val = apr_palloc(pool, outchars); + status = apr_conv_ucs2_to_utf8(wvalue, &inchars, val, &outchars); + if (status) + return status; + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + char dummy; + + SetLastError(0); + size = GetEnvironmentVariableA(envvar, &dummy, 0); + if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) + /* The environment variable doesn't exist. */ + return APR_ENOENT; + + if (size == 0) { + /* The environment value exists, but is zero-length. */ + *value = apr_pstrdup(pool, ""); + return APR_SUCCESS; + } + + val = apr_palloc(pool, size); + size = GetEnvironmentVariableA(envvar, val, size); + if (size == 0) + /* Mid-air collision?. Somebody must've changed the env. var. */ + return APR_INCOMPLETE; + } +#endif + + *value = val; + return APR_SUCCESS; +#endif +} + + +APR_DECLARE(apr_status_t) apr_env_set(const char *envvar, + const char *value, + apr_pool_t *pool) +{ +#if defined(_WIN32_WCE) + return APR_ENOTIMPL; +#else +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wenvvar[APR_PATH_MAX]; + apr_wchar_t *wvalue; + apr_size_t inchars, outchars; + apr_status_t status; + + status = widen_envvar_name(wenvvar, APR_PATH_MAX, envvar); + if (status) + return status; + + outchars = inchars = strlen(value) + 1; + wvalue = apr_palloc(pool, outchars * sizeof(*wvalue)); + status = apr_conv_utf8_to_ucs2(value, &inchars, wvalue, &outchars); + if (status) + return status; + + if (!SetEnvironmentVariableW(wenvvar, wvalue)) + return apr_get_os_error(); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + if (!SetEnvironmentVariableA(envvar, value)) + return apr_get_os_error(); + } +#endif + + return APR_SUCCESS; +#endif +} + + +APR_DECLARE(apr_status_t) apr_env_delete(const char *envvar, apr_pool_t *pool) +{ +#if defined(_WIN32_WCE) + return APR_ENOTIMPL; +#else +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wenvvar[APR_PATH_MAX]; + apr_status_t status; + + status = widen_envvar_name(wenvvar, APR_PATH_MAX, envvar); + if (status) + return status; + + if (!SetEnvironmentVariableW(wenvvar, NULL)) + return apr_get_os_error(); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + if (!SetEnvironmentVariableA(envvar, NULL)) + return apr_get_os_error(); + } +#endif + + return APR_SUCCESS; +#endif +} diff --git a/misc/win32/internal.c b/misc/win32/internal.c new file mode 100644 index 0000000..03362cf --- /dev/null +++ b/misc/win32/internal.c @@ -0,0 +1,101 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_private.h" + +#include "apr_arch_misc.h" +#include "apr_arch_file_io.h" +#include <assert.h> + +/* This module is the source of -static- helper functions that are + * entirely internal to apr. If the fn is exported - it does not + * belong here. + * + * Namespace decoration is still required to protect us from symbol + * clashes in static linkages. + */ + + +/* Shared by apr_app.c and start.c + * + * An internal apr function to convert an array of strings (either + * a counted or NULL terminated list, such as an argv[argc] or env[] + * list respectively) from wide Unicode strings to narrow utf-8 strings. + * These are allocated from the MSVCRT's _CRT_BLOCK to trick the system + * into trusting our store. + */ +int apr_wastrtoastr(char const * const * *retarr, + wchar_t const * const *arr, int args) +{ + apr_size_t elesize = 0; + char **newarr; + char *elements; + char *ele; + int arg; + + if (args < 0) { + for (args = 0; arr[args]; ++args) + ; + } + + newarr = apr_malloc_dbg((args + 1) * sizeof(char *), + __FILE__, __LINE__); + + for (arg = 0; arg < args; ++arg) { + newarr[arg] = (void*)(wcslen(arr[arg]) + 1); + elesize += (apr_size_t)newarr[arg]; + } + + /* This is a safe max allocation, we will realloc after + * processing and return the excess to the free store. + * 3 ucs bytes hold any single wchar_t value (16 bits) + * 4 ucs bytes will hold a wchar_t pair value (20 bits) + */ + elesize = elesize * 3 + 1; + ele = elements = apr_malloc_dbg(elesize * sizeof(char), + __FILE__, __LINE__); + + for (arg = 0; arg < args; ++arg) { + apr_size_t len = (apr_size_t)newarr[arg]; + apr_size_t newlen = elesize; + + newarr[arg] = ele; + (void)apr_conv_ucs2_to_utf8(arr[arg], &len, + newarr[arg], &elesize); + + newlen -= elesize; + ele += newlen; + assert(elesize && (len == 0)); + } + + newarr[arg] = NULL; + *(ele++) = '\0'; + + /* Return to the free store if the heap realloc is the least bit optimized + */ + ele = apr_realloc_dbg(elements, ele - elements, + __FILE__, __LINE__); + + if (ele != elements) { + apr_size_t diff = ele - elements; + for (arg = 0; arg < args; ++arg) { + newarr[arg] += diff; + } + } + + *retarr = (char const * const *)newarr; + return args; +} diff --git a/misc/win32/misc.c b/misc/win32/misc.c new file mode 100644 index 0000000..bfb7efa --- /dev/null +++ b/misc/win32/misc.c @@ -0,0 +1,266 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_private.h" +#include "apr_arch_misc.h" +#include "apr_arch_file_io.h" +#include "assert.h" +#include "apr_lib.h" +#include "tchar.h" + +APR_DECLARE_DATA apr_oslevel_e apr_os_level = APR_WIN_UNK; + +apr_status_t apr_get_oslevel(apr_oslevel_e *level) +{ + if (apr_os_level == APR_WIN_UNK) + { + OSVERSIONINFOEXW oslev; + oslev.dwOSVersionInfoSize = sizeof(oslev); + if (!GetVersionExW((OSVERSIONINFOW*) &oslev)) { + return apr_get_os_error(); + } + + if (oslev.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + unsigned int servpack = oslev.wServicePackMajor; + + if (oslev.dwMajorVersion < 3) { + apr_os_level = APR_WIN_UNSUP; + } + else if (oslev.dwMajorVersion == 3) { + if (oslev.dwMajorVersion < 50) { + apr_os_level = APR_WIN_UNSUP; + } + else if (oslev.dwMajorVersion == 50) { + apr_os_level = APR_WIN_NT_3_5; + } + else { + apr_os_level = APR_WIN_NT_3_51; + } + } + else if (oslev.dwMajorVersion == 4) { + if (servpack < 2) + apr_os_level = APR_WIN_NT_4; + else if (servpack <= 2) + apr_os_level = APR_WIN_NT_4_SP2; + else if (servpack <= 3) + apr_os_level = APR_WIN_NT_4_SP3; + else if (servpack <= 4) + apr_os_level = APR_WIN_NT_4_SP4; + else if (servpack <= 5) + apr_os_level = APR_WIN_NT_4_SP5; + else + apr_os_level = APR_WIN_NT_4_SP6; + } + else if (oslev.dwMajorVersion == 5) { + if (oslev.dwMinorVersion == 0) { + if (servpack == 0) + apr_os_level = APR_WIN_2000; + else if (servpack == 1) + apr_os_level = APR_WIN_2000_SP1; + else + apr_os_level = APR_WIN_2000_SP2; + } + else if (oslev.dwMinorVersion == 2) { + apr_os_level = APR_WIN_2003; + } + else { + if (servpack < 1) + apr_os_level = APR_WIN_XP; + else if (servpack == 1) + apr_os_level = APR_WIN_XP_SP1; + else + apr_os_level = APR_WIN_XP_SP2; + } + } + else if (oslev.dwMajorVersion == 6) { + if (oslev.dwMinorVersion == 0) + apr_os_level = APR_WIN_VISTA; + else if (oslev.dwMinorVersion == 1) { + if (servpack < 1) + apr_os_level = APR_WIN_7; + else + apr_os_level = APR_WIN_7_SP1; + } + else if (oslev.dwMinorVersion == 2) + apr_os_level = APR_WIN_8; + else + apr_os_level = APR_WIN_8_1; + } + else { + apr_os_level = APR_WIN_10; + } + } +#ifndef WINNT + else if (oslev.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + TCHAR *prevision; + if (prevision = oslev.szCSDVersion) { + while (*prevision && !apr_isupper(*prevision)) { + prevision++; + } + } + else prevision = _T(""); + + if (oslev.dwMinorVersion < 10) { + if (*prevision < _T('C')) + apr_os_level = APR_WIN_95; + else + apr_os_level = APR_WIN_95_OSR2; + } + else if (oslev.dwMinorVersion < 90) { + if (*prevision < _T('A')) + apr_os_level = APR_WIN_98; + else + apr_os_level = APR_WIN_98_SE; + } + else { + apr_os_level = APR_WIN_ME; + } + } +#endif +#ifdef _WIN32_WCE + else if (oslev.dwPlatformId == VER_PLATFORM_WIN32_CE) + { + if (oslev.dwMajorVersion < 3) { + apr_os_level = APR_WIN_UNSUP; + } + else { + apr_os_level = APR_WIN_CE_3; + } + } +#endif + else { + apr_os_level = APR_WIN_UNSUP; + } + } + + *level = apr_os_level; + + if (apr_os_level <= APR_WIN_UNSUP) { + return APR_EGENERAL; + } + + return APR_SUCCESS; +} + + +/* This is the helper code to resolve late bound entry points + * missing from one or more releases of the Win32 API + */ + +static const char* const lateDllName[DLL_defined] = { + "kernel32", "advapi32", "mswsock", "ws2_32", "shell32", "ntdll.dll", + "Iphplapi" }; +static HMODULE lateDllHandle[DLL_defined] = { + NULL, NULL, NULL, NULL, NULL, NULL, + NULL }; + +FARPROC apr_load_dll_func(apr_dlltoken_e fnLib, char* fnName, int ordinal) +{ + if (!lateDllHandle[fnLib]) { + lateDllHandle[fnLib] = LoadLibraryA(lateDllName[fnLib]); + if (!lateDllHandle[fnLib]) + return NULL; + } +#if defined(_WIN32_WCE) + if (ordinal) + return GetProcAddressA(lateDllHandle[fnLib], (const char *) + (apr_ssize_t)ordinal); + else + return GetProcAddressA(lateDllHandle[fnLib], fnName); +#else + if (ordinal) + return GetProcAddress(lateDllHandle[fnLib], (const char *) + (apr_ssize_t)ordinal); + else + return GetProcAddress(lateDllHandle[fnLib], fnName); +#endif +} + +/* Declared in include/arch/win32/apr_dbg_win32_handles.h + */ +APR_DECLARE_NONSTD(HANDLE) apr_dbg_log(char* fn, HANDLE ha, char* fl, int ln, + int nh, /* HANDLE hv, char *dsc */...) +{ + static DWORD tlsid = 0xFFFFFFFF; + static HANDLE fh = NULL; + static long ctr = 0; + static CRITICAL_SECTION cs; + long seq; + DWORD wrote; + char *sbuf; + + seq = (InterlockedIncrement)(&ctr); + + if (tlsid == 0xFFFFFFFF) { + tlsid = (TlsAlloc)(); + } + + sbuf = (TlsGetValue)(tlsid); + if (!fh || !sbuf) { + sbuf = (malloc)(1024); + (TlsSetValue)(tlsid, sbuf); + sbuf[1023] = '\0'; + if (!fh) { + (GetModuleFileNameA)(NULL, sbuf, 250); + sprintf(strchr(sbuf, '\0'), ".%u", + (unsigned int)(GetCurrentProcessId)()); + fh = (CreateFileA)(sbuf, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, 0, NULL); + (InitializeCriticalSection)(&cs); + } + } + + if (!nh) { + (sprintf)(sbuf, "%p %08x %08x %s() %s:%d\n", + ha, (unsigned int)seq, (unsigned int)GetCurrentThreadId(), + fn, fl, ln); + (EnterCriticalSection)(&cs); + (WriteFile)(fh, sbuf, (DWORD)strlen(sbuf), &wrote, NULL); + (LeaveCriticalSection)(&cs); + } + else { + va_list a; + va_start(a,nh); + (EnterCriticalSection)(&cs); + do { + HANDLE *hv = va_arg(a, HANDLE*); + char *dsc = va_arg(a, char*); + if (strcmp(dsc, "Signaled") == 0) { + if ((apr_ssize_t)ha >= STATUS_WAIT_0 + && (apr_ssize_t)ha < STATUS_ABANDONED_WAIT_0) { + hv += (apr_ssize_t)ha; + } + else if ((apr_ssize_t)ha >= STATUS_ABANDONED_WAIT_0 + && (apr_ssize_t)ha < STATUS_USER_APC) { + hv += (apr_ssize_t)ha - STATUS_ABANDONED_WAIT_0; + dsc = "Abandoned"; + } + else if ((apr_ssize_t)ha == WAIT_TIMEOUT) { + dsc = "Timed Out"; + } + } + (sprintf)(sbuf, "%p %08x %08x %s(%s) %s:%d\n", + *hv, (unsigned int)seq, + (unsigned int)GetCurrentThreadId(), + fn, dsc, fl, ln); + (WriteFile)(fh, sbuf, (DWORD)strlen(sbuf), &wrote, NULL); + } while (--nh); + (LeaveCriticalSection)(&cs); + va_end(a); + } + return ha; +} diff --git a/misc/win32/rand.c b/misc/win32/rand.c new file mode 100644 index 0000000..cb5a653 --- /dev/null +++ b/misc/win32/rand.c @@ -0,0 +1,69 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include <rpc.h> +#include <wincrypt.h> +#include "apr_private.h" +#include "apr_general.h" +#include "apr_portable.h" +#include "apr_arch_misc.h" + + +APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char * buf, + apr_size_t length) +{ + HCRYPTPROV hProv; + apr_status_t res = APR_SUCCESS; + + /* 0x40 bit = CRYPT_SILENT, only introduced in more recent PSDKs + * and will only work for Win2K and later. + */ + DWORD flags = CRYPT_VERIFYCONTEXT + | ((apr_os_level >= APR_WIN_2000) ? 0x40 : 0); + + if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, flags)) { + return apr_get_os_error(); + } + /* XXX: An ugly hack for Win64, randomness is such that noone should + * ever expect > 2^31 bytes of data at once without the prng + * coming to a complete halt. + */ + if (!CryptGenRandom(hProv, (DWORD)length, buf)) { + res = apr_get_os_error(); + } + CryptReleaseContext(hProv, 0); + return res; +} + + +APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data) +{ + /* Note: this call doesn't actually require CoInitialize() first + * + * XXX: we should scramble the bytes or some such to eliminate the + * possible misuse/abuse since uuid is based on the NIC address, and + * is therefore not only a uniqifier, but an identity (which might not + * be appropriate in all cases. + * + * Note that Win2000, XP and later no longer suffer from this problem, + * a scrambling fix is only needed for (apr_os_level < APR_WIN_2000) + */ + if (FAILED(UuidCreate((UUID *)uuid_data))) { + return APR_EGENERAL; + } + return APR_SUCCESS; +} diff --git a/misc/win32/start.c b/misc/win32/start.c new file mode 100644 index 0000000..2d7b5ff --- /dev/null +++ b/misc/win32/start.c @@ -0,0 +1,232 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_signal.h" +#include "shellapi.h" + +#include "apr_arch_misc.h" /* for WSAHighByte / WSALowByte */ +#include "wchar.h" +#include "apr_arch_file_io.h" /* bring in unicode-ness */ +#include "apr_arch_threadproc.h" /* bring in apr_threadproc_init */ +#include "assert.h" + +/* This symbol is _private_, although it must be exported. + */ +int APR_DECLARE_DATA apr_app_init_complete = 0; + +#if !defined(_WIN32_WCE) +/* Used by apr_app_initialize to reprocess the environment + * + * An internal apr function to convert a double-null terminated set + * of single-null terminated strings from wide Unicode to narrow utf-8 + * as a list of strings. These are allocated from the MSVCRT's + * _CRT_BLOCK to trick the system into trusting our store. + */ +static int warrsztoastr(const char * const * *retarr, + const wchar_t * arrsz) +{ + const apr_wchar_t *wch; + apr_size_t totlen; + apr_size_t newlen; + apr_size_t wsize; + char **env; + char *pstrs; + char *strs; + int arg, args; + + for (args = 1, wch = arrsz; wch[0] || wch[1]; ++wch) + if (!*wch) + ++args; + wsize = 1 + wch - arrsz; + + /* This is a safe max allocation, we will alloc each + * string exactly after processing and return this + * temporary buffer to the free store. + * 3 ucs bytes hold any single wchar_t value (16 bits) + * 4 ucs bytes will hold a wchar_t pair value (20 bits) + */ + newlen = totlen = wsize * 3 + 1; + pstrs = strs = apr_malloc_dbg(newlen * sizeof(char), + __FILE__, __LINE__); + + (void)apr_conv_ucs2_to_utf8(arrsz, &wsize, strs, &newlen); + + assert(newlen && !wsize); + + *retarr = env = apr_malloc_dbg((args + 1) * sizeof(char*), + __FILE__, __LINE__); + for (arg = 0; arg < args; ++arg) { + char* p = pstrs; + int len = 0; + while (*p++) + ++len; + len += 1; + + *env = apr_malloc_dbg(len * sizeof(char), + __FILE__, __LINE__); + memcpy(*env, pstrs, len * sizeof(char)); + + pstrs += len; + ++env; + } + + *env = NULL; + free(strs); + + return args; +} +#endif + +/* Reprocess the arguments to main() for a completely apr-ized application + */ + +APR_DECLARE(apr_status_t) apr_app_initialize(int *argc, + const char * const * *argv, + const char * const * *env) +{ + apr_status_t rv = apr_initialize(); + + if (rv != APR_SUCCESS) { + return rv; + } + +#if defined(_WIN32_WCE) + apr_app_init_complete = 1; +#elif APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t **wstrs; + apr_wchar_t *sysstr; + int wstrc; + int dupenv; + + if (apr_app_init_complete) { + return rv; + } + + apr_app_init_complete = 1; + + sysstr = GetCommandLineW(); + if (sysstr) { + wstrs = CommandLineToArgvW(sysstr, &wstrc); + if (wstrs) { + *argc = apr_wastrtoastr(argv, wstrs, wstrc); + GlobalFree(wstrs); + } + } + + sysstr = GetEnvironmentStringsW(); + dupenv = warrsztoastr(&_environ, sysstr); + + if (env) { + *env = apr_malloc_dbg((dupenv + 1) * sizeof (char *), + __FILE__, __LINE__ ); + memcpy((void*)*env, _environ, (dupenv + 1) * sizeof (char *)); + } + else { + } + + FreeEnvironmentStringsW(sysstr); + + /* MSVCRT will attempt to maintain the wide environment calls + * on _putenv(), which is bogus if we've passed a non-ascii + * string to _putenv(), since they use MultiByteToWideChar + * and breaking the implicit utf-8 assumption we've built. + * + * Reset _wenviron for good measure. + */ + if (_wenviron) { + apr_wchar_t **wenv = _wenviron; + _wenviron = NULL; + free(wenv); + } + + } +#endif + return rv; +} + +static int initialized = 0; + +/* Provide to win32/thread.c */ +extern DWORD tls_apr_thread; + +APR_DECLARE(apr_status_t) apr_initialize(void) +{ + apr_pool_t *pool; + apr_status_t status; + int iVersionRequested; + WSADATA wsaData; + int err; + apr_oslevel_e osver; + + if (initialized++) { + return APR_SUCCESS; + } + + /* Initialize apr_os_level global */ + if (apr_get_oslevel(&osver) != APR_SUCCESS) { + return APR_EEXIST; + } + + tls_apr_thread = TlsAlloc(); + if ((status = apr_pool_initialize()) != APR_SUCCESS) + return status; + + if (apr_pool_create(&pool, NULL) != APR_SUCCESS) { + return APR_ENOPOOL; + } + + apr_pool_tag(pool, "apr_initialize"); + + iVersionRequested = MAKEWORD(WSAHighByte, WSALowByte); + err = WSAStartup((WORD) iVersionRequested, &wsaData); + if (err) { + return err; + } + if (LOBYTE(wsaData.wVersion) != WSAHighByte || + HIBYTE(wsaData.wVersion) != WSALowByte) { + WSACleanup(); + return APR_EEXIST; + } + + apr_signal_init(pool); + + apr_threadproc_init(pool); + + return APR_SUCCESS; +} + +APR_DECLARE_NONSTD(void) apr_terminate(void) +{ + initialized--; + if (initialized) { + return; + } + apr_pool_terminate(); + + WSACleanup(); + + TlsFree(tls_apr_thread); +} + +APR_DECLARE(void) apr_terminate2(void) +{ + apr_terminate(); +} diff --git a/misc/win32/utf8.c b/misc/win32/utf8.c new file mode 100644 index 0000000..280f406 --- /dev/null +++ b/misc/win32/utf8.c @@ -0,0 +1,259 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include "apr_private.h" +#include "apr_errno.h" +#include "apr_arch_utf8.h" + +/* Implementation of RFC 3629, "UTF-8, a transformation format of ISO 10646" + * with particular attention to canonical translation forms (see section 10 + * "Security Considerations" of the RFC for more info). + * + * Since several architectures including Windows support unicode, with UCS2 + * used as the actual storage conventions by that archicture, these functions + * exist to transform or validate UCS2 strings into APR's 'char' type + * convention. It is left up to the operating system to determine the + * validitity of the string, e.g. normative forms, in the context of + * its native language support. Other file systems which support filename + * characters of 0x80-0xff but have no explicit requirement for Unicode + * will find this function useful only for validating the character sequences + * and rejecting poorly encoded UTF8 sequences. + * + * Len UCS-4 range (hex) UTF-8 octet sequence (binary) + * 1:2 00000000-0000007F 0xxxxxxx + * 2:2 00000080-000007FF 110XXXXx 10xxxxxx + * 3:2 00000800-0000FFFF 1110XXXX 10Xxxxxx 10xxxxxx + * 4:4 00010000-001FFFFF 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx + * 00200000-03FFFFFF 111110XX 10XXXxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 04000000-7FFFFFFF 1111110X 10XXXXxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * + * One of the X bits must be 1 to avoid overlong representation of ucs2 values. + * + * For conversion into ucs2, the 4th form is limited in range to 0010 FFFF, + * and the final two forms are used only by full ucs4, per RFC 3629; + * + * "Pairs of UCS-2 values between D800 and DFFF (surrogate pairs in + * Unicode parlance), being actually UCS-4 characters transformed + * through UTF-16, need special treatment: the UTF-16 transformation + * must be undone, yielding a UCS-4 character that is then transformed + * as above." + * + * From RFC2781 UTF-16: the compressed ISO 10646 encoding bitmask + * + * U' = U - 0x10000 + * U' = 00000000 0000yyyy yyyyyyxx xxxxxxxx + * W1 = 110110yy yyyyyyyy + * W2 = 110111xx xxxxxxxx + * Max U' = 0000 00001111 11111111 11111111 + * Max U = 0000 00010000 11111111 11111111 + * + * Len is the table above is a mapping of bytes used for utf8:ucs2 values, + * which results in these conclusions of maximum allocations; + * + * apr_conv_utf8_to_ucs2 out bytes:sizeof(in) * 1 <= Req <= sizeof(in) * 2 + * apr_conv_ucs2_to_utf8 out words:sizeof(in) / 2 <= Req <= sizeof(in) * 3 / 2 + */ + +APR_DECLARE(apr_status_t) apr_conv_utf8_to_ucs2(const char *in, + apr_size_t *inbytes, + apr_wchar_t *out, + apr_size_t *outwords) +{ + apr_int64_t newch, mask; + apr_size_t expect, eating; + int ch; + + while (*inbytes && *outwords) + { + ch = (unsigned char)(*in++); + if (!(ch & 0200)) { + /* US-ASCII-7 plain text + */ + --*inbytes; + --*outwords; + *(out++) = ch; + } + else + { + if ((ch & 0300) != 0300) { + /* Multibyte Continuation is out of place + */ + return APR_EINVAL; + } + else + { + /* Multibyte Sequence Lead Character + * + * Compute the expected bytes while adjusting + * or lead byte and leading zeros mask. + */ + mask = 0340; + expect = 1; + while ((ch & mask) == mask) { + mask |= mask >> 1; + if (++expect > 3) /* (truly 5 for ucs-4) */ + return APR_EINVAL; + } + newch = ch & ~mask; + eating = expect + 1; + if (*inbytes <= expect) + return APR_INCOMPLETE; + /* Reject values of excessive leading 0 bits + * utf-8 _demands_ the shortest possible byte length + */ + if (expect == 1) { + if (!(newch & 0036)) + return APR_EINVAL; + } + else { + /* Reject values of excessive leading 0 bits + */ + if (!newch && !((unsigned char)*in & 0077 & (mask << 1))) + return APR_EINVAL; + if (expect == 2) { + /* Reject values D800-DFFF when not utf16 encoded + * (may not be an appropriate restriction for ucs-4) + */ + if (newch == 0015 && ((unsigned char)*in & 0040)) + return APR_EINVAL; + } + else if (expect == 3) { + /* Short circuit values > 110000 + */ + if (newch > 4) + return APR_EINVAL; + if (newch == 4 && ((unsigned char)*in & 0060)) + return APR_EINVAL; + } + } + /* Where the boolean (expect > 2) is true, we will need + * an extra word for the output. + */ + if (*outwords < (apr_size_t)(expect > 2) + 1) + break; /* buffer full */ + while (expect--) + { + /* Multibyte Continuation must be legal */ + if (((ch = (unsigned char)*(in++)) & 0300) != 0200) + return APR_EINVAL; + newch <<= 6; + newch |= (ch & 0077); + } + *inbytes -= eating; + /* newch is now a true ucs-4 character + * + * now we need to fold to ucs-2 + */ + if (newch < 0x10000) + { + --*outwords; + *(out++) = (apr_wchar_t) newch; + } + else + { + *outwords -= 2; + newch -= 0x10000; + *(out++) = (apr_wchar_t) (0xD800 | (newch >> 10)); + *(out++) = (apr_wchar_t) (0xDC00 | (newch & 0x03FF)); + } + } + } + } + /* Buffer full 'errors' aren't errors, the client must inspect both + * the inbytes and outwords values + */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_conv_ucs2_to_utf8(const apr_wchar_t *in, + apr_size_t *inwords, + char *out, + apr_size_t *outbytes) +{ + apr_int64_t newch, require; + apr_size_t need; + char *invout; + int ch; + + while (*inwords && *outbytes) + { + ch = (unsigned short)(*in++); + if (ch < 0x80) + { + --*inwords; + --*outbytes; + *(out++) = (unsigned char) ch; + } + else + { + if ((ch & 0xFC00) == 0xDC00) { + /* Invalid Leading ucs-2 Multiword Continuation Character + */ + return APR_EINVAL; + } + if ((ch & 0xFC00) == 0xD800) { + /* Leading ucs-2 Multiword Character + */ + if (*inwords < 2) { + /* Missing ucs-2 Multiword Continuation Character + */ + return APR_INCOMPLETE; + } + if (((unsigned short)(*in) & 0xFC00) != 0xDC00) { + /* Invalid ucs-2 Multiword Continuation Character + */ + return APR_EINVAL; + } + newch = (ch & 0x03FF) << 10 | ((unsigned short)(*in++) & 0x03FF); + newch += 0x10000; + } + else { + /* ucs-2 Single Word Character + */ + newch = ch; + } + /* Determine the absolute minimum utf-8 bytes required + */ + require = newch >> 11; + need = 1; + while (require) + require >>= 5, ++need; + if (need >= *outbytes) + break; /* Insufficient buffer */ + *inwords -= (need > 2) + 1; + *outbytes -= need + 1; + /* Compute the utf-8 characters in last to first order, + * calculating the lead character length bits along the way. + */ + ch = 0200; + out += need + 1; + invout = out; + while (need--) { + ch |= ch >> 1; + *(--invout) = (unsigned char)(0200 | (newch & 0077)); + newch >>= 6; + } + /* Compute the lead utf-8 character and move the dest offset + */ + *(--invout) = (unsigned char)(ch | newch); + } + } + /* Buffer full 'errors' aren't errors, the client must inspect both + * the inwords and outbytes values + */ + return APR_SUCCESS; +} |