diff options
Diffstat (limited to '')
-rw-r--r-- | misc/netware/apr.xdc | bin | 0 -> 128 bytes | |||
-rw-r--r-- | misc/netware/aprlib.def | 3 | ||||
-rw-r--r-- | misc/netware/charset.c | 34 | ||||
-rw-r--r-- | misc/netware/libprews.c | 186 | ||||
-rw-r--r-- | misc/netware/rand.c | 70 | ||||
-rw-r--r-- | misc/netware/start.c | 203 | ||||
-rw-r--r-- | misc/unix/charset.c | 83 | ||||
-rw-r--r-- | misc/unix/env.c | 88 | ||||
-rw-r--r-- | misc/unix/errorcodes.c | 443 | ||||
-rw-r--r-- | misc/unix/getopt.c | 309 | ||||
-rw-r--r-- | misc/unix/otherchild.c | 221 | ||||
-rw-r--r-- | misc/unix/rand.c | 302 | ||||
-rw-r--r-- | misc/unix/randbyte_os2.inc | 123 | ||||
-rw-r--r-- | misc/unix/start.c | 89 | ||||
-rw-r--r-- | misc/unix/version.c | 35 | ||||
-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 |
23 files changed, 3467 insertions, 0 deletions
diff --git a/misc/netware/apr.xdc b/misc/netware/apr.xdc Binary files differnew file mode 100644 index 0000000..12a7f6b --- /dev/null +++ b/misc/netware/apr.xdc diff --git a/misc/netware/aprlib.def b/misc/netware/aprlib.def new file mode 100644 index 0000000..0a2a01e --- /dev/null +++ b/misc/netware/aprlib.def @@ -0,0 +1,3 @@ +MODULE LIBC.NLM +MODULE WS2_32.NLM +EXPORT @aprlib.imp diff --git a/misc/netware/charset.c b/misc/netware/charset.c new file mode 100644 index 0000000..b79add1 --- /dev/null +++ b/misc/netware/charset.c @@ -0,0 +1,34 @@ +/* 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" + +/* static struct utsname sysinfo; */ + +/* XXX This needs to be fixed to produce the correct system language */ + +APR_DECLARE(const char*) apr_os_default_encoding (apr_pool_t *pool) +{ + return apr_pstrdup(pool, "CP1252"); +} + + +APR_DECLARE(const char*) apr_os_locale_encoding (apr_pool_t *pool) +{ + return apr_os_default_encoding(pool); +} diff --git a/misc/netware/libprews.c b/misc/netware/libprews.c new file mode 100644 index 0000000..6e37ccf --- /dev/null +++ b/misc/netware/libprews.c @@ -0,0 +1,186 @@ +/* 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 <netware.h> +#include <library.h> +#include <nks/synch.h> + +#include "apr_pools.h" +#include "apr_private.h" +#include "apr_arch_internal_time.h" + + +/* library-private data...*/ +int gLibId = -1; +void *gLibHandle = (void *) NULL; +NXMutex_t *gLibLock = (NXMutex_t *) NULL; + +/* internal library function prototypes...*/ +int DisposeLibraryData(void *); + +int _NonAppStart +( + void *NLMHandle, + void *errorScreen, + const char *cmdLine, + const char *loadDirPath, + size_t uninitializedDataLength, + void *NLMFileHandle, + int (*readRoutineP)( int conn, void *fileHandle, size_t offset, + size_t nbytes, size_t *bytesRead, void *buffer ), + size_t customDataOffset, + size_t customDataSize, + int messageCount, + const char **messages +) +{ +#ifdef USE_WINSOCK + WSADATA wsaData; +#endif + apr_status_t status; + + NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); + +#pragma unused(cmdLine) +#pragma unused(loadDirPath) +#pragma unused(uninitializedDataLength) +#pragma unused(NLMFileHandle) +#pragma unused(readRoutineP) +#pragma unused(customDataOffset) +#pragma unused(customDataSize) +#pragma unused(messageCount) +#pragma unused(messages) + + gLibId = register_library(DisposeLibraryData); + + if (gLibId < -1) + { + OutputToScreen(errorScreen, "Unable to register library with kernel.\n"); + return -1; + } + + gLibHandle = NLMHandle; + + gLibLock = NXMutexAlloc(0, 0, &liblock); + + if (!gLibLock) + { + OutputToScreen(errorScreen, "Unable to allocate library data lock.\n"); + return -1; + } + + apr_netware_setup_time(); + + if ((status = apr_pool_initialize()) != APR_SUCCESS) + return status; + +#ifdef USE_WINSOCK + return WSAStartup((WORD) MAKEWORD(2, 0), &wsaData); +#else + return 0; +#endif +} + +void _NonAppStop( void ) +{ + apr_pool_terminate(); + +#ifdef USE_WINSOCK + WSACleanup(); +#endif + + unregister_library(gLibId); + NXMutexFree(gLibLock); +} + +int _NonAppCheckUnload( void ) +{ + return 0; +} + +int register_NLM(void *NLMHandle) +{ + APP_DATA *app_data = (APP_DATA*) get_app_data(gLibId); + + NXLock(gLibLock); + if (!app_data) { + app_data = (APP_DATA*)library_malloc(gLibHandle, sizeof(APP_DATA)); + + if (app_data) { + memset (app_data, 0, sizeof(APP_DATA)); + set_app_data(gLibId, app_data); + app_data->gs_nlmhandle = NLMHandle; + } + } + + if (app_data && (!app_data->initialized)) { + app_data->initialized = 1; + NXUnlock(gLibLock); + return 0; + } + + NXUnlock(gLibLock); + return 1; +} + +int unregister_NLM(void *NLMHandle) +{ + APP_DATA *app_data = (APP_DATA*) get_app_data(gLibId); + + NXLock(gLibLock); + if (app_data) { + app_data->initialized = 0; + NXUnlock(gLibLock); + return 0; + } + NXUnlock(gLibLock); + return 1; +} + +int DisposeLibraryData(void *data) +{ + if (data) + { + library_free(data); + } + + return 0; +} + +int setGlobalPool(void *data) +{ + APP_DATA *app_data = (APP_DATA*) get_app_data(gLibId); + + NXLock(gLibLock); + + if (app_data && !app_data->gPool) { + app_data->gPool = data; + } + + NXUnlock(gLibLock); + return 1; +} + +void* getGlobalPool() +{ + APP_DATA *app_data = (APP_DATA*) get_app_data(gLibId); + + if (app_data) { + return app_data->gPool; + } + + return NULL; +} + diff --git a/misc/netware/rand.c b/misc/netware/rand.c new file mode 100644 index 0000000..a2baae7 --- /dev/null +++ b/misc/netware/rand.c @@ -0,0 +1,70 @@ +/* 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_MEMFUNC +#include "apr_want.h" +#include "apr_general.h" +#include "apr_private.h" + +#if APR_HAS_RANDOM + +#include <nks/plat.h> + +static int NXSeedRandomInternal( size_t width, void *seed ) +{ + static int init = 0; + int *s = (int *) seed; + union { int x; char y[4]; } u; + + if (!init) { + srand(NXGetSystemTick()); + init = 1; + } + + if (width > 3) + { + do + { + *s++ = rand(); + } + while ((width -= 4) > 3); + } + + if (width > 0) + { + char *p = (char *) s; + + u.x = rand(); + + while (width > 0) + *p++ = u.y[width--]; + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf, + apr_size_t length) +{ + if (NXSeedRandom(length, buf) != 0) { + return NXSeedRandomInternal (length, buf); + } + return APR_SUCCESS; +} + + + +#endif /* APR_HAS_RANDOM */ diff --git a/misc/netware/start.c b/misc/netware/start.c new file mode 100644 index 0000000..76817d9 --- /dev/null +++ b/misc/netware/start.c @@ -0,0 +1,203 @@ +/* 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_general.h" +#include "apr_pools.h" +#include "apr_signal.h" + +#include "apr_arch_misc.h" /* for WSAHighByte / WSALowByte */ +#include "apr_arch_proc_mutex.h" /* for apr_proc_mutex_unix_setup_lock() */ +#include "apr_arch_internal_time.h" +#include "apr_ldap.h" /* for apr_ldap_rebind_init() */ + +#ifdef USE_WINSOCK +/* Prototypes missing from older NDKs */ +int WSAStartupRTags(WORD wVersionRequested, + LPWSADATA lpWSAData, + rtag_t WSAStartupRTag, + rtag_t WSPSKTRTag, + rtag_t lookUpServiceBeginRTag, + rtag_t WSAEventRTag, + rtag_t WSPCPRTag); + +int WSACleanupRTag(rtag_t rTag); + +/* +** Resource tag signatures for using NetWare WinSock 2. These will no longer +** be needed by anyone once the new WSAStartupWithNlmHandle() is available +** since WinSock will make the calls to AllocateResourceTag(). +*/ +#define WS_LOAD_ENTRY_SIGNATURE (*(unsigned long *) "WLDE") +#define WS_SKT_SIGNATURE (*(unsigned long *) "WSKT") +#define WS_LOOKUP_SERVICE_SIGNATURE (*(unsigned long *) "WLUP") +#define WS_WSAEVENT_SIGNATURE (*(unsigned long *) "WEVT") +#define WS_CPORT_SIGNATURE (*(unsigned long *) "WCPT") + + +int (*WSAStartupWithNLMHandle)( WORD version, LPWSADATA data, void *handle ) = NULL; +int (*WSACleanupWithNLMHandle)( void *handle ) = NULL; + +static int wsa_startup_with_handle (WORD wVersionRequested, LPWSADATA data, void *handle) +{ + APP_DATA *app_data; + + if (!(app_data = (APP_DATA*) get_app_data(gLibId))) + return APR_EGENERAL; + + app_data->gs_startup_rtag = AllocateResourceTag(handle, "WinSock Start-up", WS_LOAD_ENTRY_SIGNATURE); + app_data->gs_socket_rtag = AllocateResourceTag(handle, "WinSock socket()", WS_SKT_SIGNATURE); + app_data->gs_lookup_rtag = AllocateResourceTag(handle, "WinSock Look-up", WS_LOOKUP_SERVICE_SIGNATURE); + app_data->gs_event_rtag = AllocateResourceTag(handle, "WinSock Event", WS_WSAEVENT_SIGNATURE); + app_data->gs_pcp_rtag = AllocateResourceTag(handle, "WinSock C-Port", WS_CPORT_SIGNATURE); + + return WSAStartupRTags(wVersionRequested, data, + app_data->gs_startup_rtag, + app_data->gs_socket_rtag, + app_data->gs_lookup_rtag, + app_data->gs_event_rtag, + app_data->gs_pcp_rtag); +} + +static int wsa_cleanup_with_handle (void *handle) +{ + APP_DATA *app_data; + + if (!(app_data = (APP_DATA*) get_app_data(gLibId))) + return APR_EGENERAL; + + return WSACleanupRTag(app_data->gs_startup_rtag); +} + +static int UnregisterAppWithWinSock (void *nlm_handle) +{ + if (!WSACleanupWithNLMHandle) + { + if (!(WSACleanupWithNLMHandle = ImportPublicObject(gLibHandle, "WSACleanupWithNLMHandle"))) + WSACleanupWithNLMHandle = wsa_cleanup_with_handle; + } + + return (*WSACleanupWithNLMHandle)(nlm_handle); +} + +static int RegisterAppWithWinSock (void *nlm_handle) +{ + int err; + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(WSAHighByte, WSALowByte); + + if (!WSAStartupWithNLMHandle) + { + if (!(WSAStartupWithNLMHandle = ImportPublicObject(gLibHandle, "WSAStartupWithNLMHandle"))) + WSAStartupWithNLMHandle = wsa_startup_with_handle; + } + + err = (*WSAStartupWithNLMHandle)(wVersionRequested, &wsaData, nlm_handle); + + if (LOBYTE(wsaData.wVersion) != WSAHighByte || + HIBYTE(wsaData.wVersion) != WSALowByte) { + + UnregisterAppWithWinSock (nlm_handle); + return APR_EEXIST; + } + + return err; +} +#endif + + + +APR_DECLARE(apr_status_t) apr_app_initialize(int *argc, + const char * const * *argv, + const char * const * *env) +{ + /* An absolute noop. At present, only Win32 requires this stub, but it's + * required in order to move command arguments passed through the service + * control manager into the process, and it's required to fix the char* + * data passed in from win32 unicode into utf-8, win32's apr internal fmt. + */ + return apr_initialize(); +} + +APR_DECLARE(apr_status_t) apr_initialize(void) +{ + apr_pool_t *pool; + void *nlmhandle = getnlmhandle(); + + /* Register the NLM as using APR. If it is already + registered then just return. */ + if (register_NLM(nlmhandle) != 0) { + return APR_SUCCESS; + } + + /* apr_pool_initialize() is being called from the library + startup code since all of the memory resources belong + to the library rather than the application. */ + + if (apr_pool_create(&pool, NULL) != APR_SUCCESS) { + return APR_ENOPOOL; + } + + apr_pool_tag(pool, "apr_initilialize"); + +#ifdef USE_WINSOCK + { + int err; + if ((err = RegisterAppWithWinSock (nlmhandle))) { + return err; + } + } +#endif + + apr_signal_init(pool); +#if APR_HAS_LDAP + apr_ldap_rebind_init(pool); +#endif + + return APR_SUCCESS; +} + +APR_DECLARE_NONSTD(void) apr_terminate(void) +{ + APP_DATA *app_data; + + /* Get our instance data for shutting down. */ + if (!(app_data = (APP_DATA*) get_app_data(gLibId))) + return; + + /* Unregister the NLM. If it is not registered + then just return. */ + if (unregister_NLM(app_data->gs_nlmhandle) != 0) { + return; + } + + /* apr_pool_terminate() is being called from the + library shutdown code since the memory resources + belong to the library rather than the application */ + + /* Just clean up the memory for the app that is going + away. */ + netware_pool_proc_cleanup (); + +#ifdef USE_WINSOCK + UnregisterAppWithWinSock (app_data->gs_nlmhandle); +#endif +} + +APR_DECLARE(void) apr_terminate2(void) +{ + apr_terminate(); +} diff --git a/misc/unix/charset.c b/misc/unix/charset.c new file mode 100644 index 0000000..a16310c --- /dev/null +++ b/misc/unix/charset.c @@ -0,0 +1,83 @@ +/* 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_strings.h" +#include "apr_portable.h" + +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#endif + +/* + * simple heuristic to determine codepage of source code so that + * literal strings (e.g., "GET /\r\n") in source code can be translated + * properly + * + * If appropriate, a symbol can be set at configure time to determine + * this. On EBCDIC platforms, it will be important how the code was + * unpacked. + */ + +APR_DECLARE(const char*) apr_os_default_encoding (apr_pool_t *pool) +{ +#ifdef __MVS__ +# ifdef __CODESET__ + return __CODESET__; +# else + return "IBM-1047"; +# endif +#endif + + if ('}' == 0xD0) { + return "IBM-1047"; + } + + if ('{' == 0xFB) { + return "EDF04"; + } + + if ('A' == 0xC1) { + return "EBCDIC"; /* not useful */ + } + + if ('A' == 0x41) { + return "ISO-8859-1"; /* not necessarily true */ + } + + return "unknown"; +} + + +APR_DECLARE(const char*) apr_os_locale_encoding (apr_pool_t *pool) +{ +#if defined(HAVE_NL_LANGINFO) && defined(CODESET) + const char *charset; + + charset = nl_langinfo(CODESET); + if (charset && *charset) { +#ifdef _OSD_POSIX /* Bug workaround - delete as soon as fixed in OSD_POSIX */ + /* Some versions of OSD_POSIX return nl_langinfo(CODESET)="^[nN]" */ + /* Ignore the bogus information and use apr_os_default_encoding() */ + if (charset[0] != '^') +#endif + return apr_pstrdup(pool, charset); + } +#endif + + return apr_os_default_encoding(pool); +} diff --git a/misc/unix/env.c b/misc/unix/env.c new file mode 100644 index 0000000..b41f8f1 --- /dev/null +++ b/misc/unix/env.c @@ -0,0 +1,88 @@ +/* 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_private.h" +#include "apr_env.h" +#include "apr_strings.h" + +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +APR_DECLARE(apr_status_t) apr_env_get(char **value, + const char *envvar, + apr_pool_t *pool) +{ +#ifdef HAVE_GETENV + + char *val = getenv(envvar); + if (!val) + return APR_ENOENT; + *value = val; + return APR_SUCCESS; + +#else + return APR_ENOTIMPL; +#endif +} + + +APR_DECLARE(apr_status_t) apr_env_set(const char *envvar, + const char *value, + apr_pool_t *pool) +{ +#if defined(HAVE_SETENV) + + if (0 > setenv(envvar, value, 1)) + return APR_ENOMEM; + return APR_SUCCESS; + +#elif defined(HAVE_PUTENV) + + if (0 > putenv(apr_pstrcat(pool, envvar, "=", value, NULL))) + return APR_ENOMEM; + return APR_SUCCESS; + +#else + return APR_ENOTIMPL; +#endif +} + + +APR_DECLARE(apr_status_t) apr_env_delete(const char *envvar, apr_pool_t *pool) +{ +#ifdef HAVE_UNSETENV + + unsetenv(envvar); + return APR_SUCCESS; + +#else + /* hint: some platforms allow envvars to be unset via + * putenv("varname")... that isn't Single Unix spec, + * but if your platform doesn't have unsetenv() it is + * worth investigating and potentially adding a + * configure check to decide when to use that form of + * putenv() here + */ + return APR_ENOTIMPL; +#endif +} diff --git a/misc/unix/errorcodes.c b/misc/unix/errorcodes.c new file mode 100644 index 0000000..60ea2f7 --- /dev/null +++ b/misc/unix/errorcodes.c @@ -0,0 +1,443 @@ +/* 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_arch_misc.h" +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_dso.h" + +#if APR_HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +/* + * stuffbuffer - like apr_cpystrn() but returns the address of the + * dest buffer instead of the address of the terminating '\0' + */ +static char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s) +{ + apr_cpystrn(buf,s,bufsize); + return buf; +} + +static char *apr_error_string(apr_status_t statcode) +{ + switch (statcode) { + case APR_ENOSTAT: + return "Could not perform a stat on the file."; + case APR_ENOPOOL: + return "A new pool could not be created."; + case APR_EBADDATE: + return "An invalid date has been provided"; + case APR_EINVALSOCK: + return "An invalid socket was returned"; + case APR_ENOPROC: + return "No process was provided and one was required."; + case APR_ENOTIME: + return "No time was provided and one was required."; + case APR_ENODIR: + return "No directory was provided and one was required."; + case APR_ENOLOCK: + return "No lock was provided and one was required."; + case APR_ENOPOLL: + return "No poll structure was provided and one was required."; + case APR_ENOSOCKET: + return "No socket was provided and one was required."; + case APR_ENOTHREAD: + return "No thread was provided and one was required."; + case APR_ENOTHDKEY: + return "No thread key structure was provided and one was required."; + case APR_ENOSHMAVAIL: + return "No shared memory is currently available"; + case APR_EDSOOPEN: +#if APR_HAS_DSO && defined(HAVE_LIBDL) + return dlerror(); +#else + return "DSO load failed"; +#endif /* HAVE_LIBDL */ + case APR_EBADIP: + return "The specified IP address is invalid."; + case APR_EBADMASK: + return "The specified network mask is invalid."; + case APR_ESYMNOTFOUND: + return "Could not find the requested symbol."; + case APR_ENOTENOUGHENTROPY: + return "Not enough entropy to continue."; + case APR_INCHILD: + return + "Your code just forked, and you are currently executing in the " + "child process"; + case APR_INPARENT: + return + "Your code just forked, and you are currently executing in the " + "parent process"; + case APR_DETACH: + return "The specified thread is detached"; + case APR_NOTDETACH: + return "The specified thread is not detached"; + case APR_CHILD_DONE: + return "The specified child process is done executing"; + case APR_CHILD_NOTDONE: + return "The specified child process is not done executing"; + case APR_TIMEUP: + return "The timeout specified has expired"; + case APR_INCOMPLETE: + return "Partial results are valid but processing is incomplete"; + case APR_BADCH: + return "Bad character specified on command line"; + case APR_BADARG: + return "Missing parameter for the specified command line option"; + case APR_EOF: + return "End of file found"; + case APR_NOTFOUND: + return "Could not find specified socket in poll list."; + case APR_ANONYMOUS: + return "Shared memory is implemented anonymously"; + case APR_FILEBASED: + return "Shared memory is implemented using files"; + case APR_KEYBASED: + return "Shared memory is implemented using a key system"; + case APR_EINIT: + return + "There is no error, this value signifies an initialized " + "error code"; + case APR_ENOTIMPL: + return "This function has not been implemented on this platform"; + case APR_EMISMATCH: + return "passwords do not match"; + case APR_EABSOLUTE: + return "The given path is absolute"; + case APR_ERELATIVE: + return "The given path is relative"; + case APR_EINCOMPLETE: + return "The given path is incomplete"; + case APR_EABOVEROOT: + return "The given path was above the root path"; + case APR_EBADPATH: + return "The given path is misformatted or contained invalid characters"; + case APR_EPATHWILD: + return "The given path contained wildcard characters"; + case APR_EBUSY: + return "The given lock was busy."; + case APR_EPROC_UNKNOWN: + return "The process is not recognized."; + case APR_EGENERAL: + return "Internal error (specific information not available)"; + default: + return "Error string not specified yet"; + } +} + + +#ifdef OS2 +#include <ctype.h> + +int apr_canonical_error(apr_status_t err); + +static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) +{ + char result[200]; + unsigned char message[HUGE_STRING_LEN]; + ULONG len; + char *pos; + int c; + + if (err >= 10000 && err < 12000) { /* socket error codes */ + return stuffbuffer(buf, bufsize, + strerror(apr_canonical_error(err+APR_OS_START_SYSERR))); + } + else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err, + "OSO001.MSG", &len) == 0) { + len--; + message[len] = 0; + pos = result; + + if (len >= sizeof(result)) + len = sizeof(result) - 1; + + for (c=0; c<len; c++) { + /* skip multiple whitespace */ + while (apr_isspace(message[c]) && apr_isspace(message[c+1])) + c++; + *(pos++) = apr_isspace(message[c]) ? ' ' : message[c]; + } + + *pos = 0; + } + else { + sprintf(result, "OS/2 error %d", err); + } + + /* Stuff the string into the caller supplied buffer, then return + * a pointer to it. + */ + return stuffbuffer(buf, bufsize, result); +} + +#elif defined(WIN32) || (defined(NETWARE) && defined(USE_WINSOCK)) + +static const struct { + apr_status_t code; + const char *msg; +} gaErrorList[] = { + {WSAEINTR, "Interrupted system call"}, + {WSAEBADF, "Bad file number"}, + {WSAEACCES, "Permission denied"}, + {WSAEFAULT, "Bad address"}, + {WSAEINVAL, "Invalid argument"}, + {WSAEMFILE, "Too many open sockets"}, + {WSAEWOULDBLOCK, "Operation would block"}, + {WSAEINPROGRESS, "Operation now in progress"}, + {WSAEALREADY, "Operation already in progress"}, + {WSAENOTSOCK, "Socket operation on non-socket"}, + {WSAEDESTADDRREQ, "Destination address required"}, + {WSAEMSGSIZE, "Message too long"}, + {WSAEPROTOTYPE, "Protocol wrong type for socket"}, + {WSAENOPROTOOPT, "Bad protocol option"}, + {WSAEPROTONOSUPPORT, "Protocol not supported"}, + {WSAESOCKTNOSUPPORT, "Socket type not supported"}, + {WSAEOPNOTSUPP, "Operation not supported on socket"}, + {WSAEPFNOSUPPORT, "Protocol family not supported"}, + {WSAEAFNOSUPPORT, "Address family not supported"}, + {WSAEADDRINUSE, "Address already in use"}, + {WSAEADDRNOTAVAIL, "Can't assign requested address"}, + {WSAENETDOWN, "Network is down"}, + {WSAENETUNREACH, "Network is unreachable"}, + {WSAENETRESET, "Net connection reset"}, + {WSAECONNABORTED, "Software caused connection abort"}, + {WSAECONNRESET, "Connection reset by peer"}, + {WSAENOBUFS, "No buffer space available"}, + {WSAEISCONN, "Socket is already connected"}, + {WSAENOTCONN, "Socket is not connected"}, + {WSAESHUTDOWN, "Can't send after socket shutdown"}, + {WSAETOOMANYREFS, "Too many references, can't splice"}, + {WSAETIMEDOUT, "Connection timed out"}, + {WSAECONNREFUSED, "Connection refused"}, + {WSAELOOP, "Too many levels of symbolic links"}, + {WSAENAMETOOLONG, "File name too long"}, + {WSAEHOSTDOWN, "Host is down"}, + {WSAEHOSTUNREACH, "No route to host"}, + {WSAENOTEMPTY, "Directory not empty"}, + {WSAEPROCLIM, "Too many processes"}, + {WSAEUSERS, "Too many users"}, + {WSAEDQUOT, "Disc quota exceeded"}, + {WSAESTALE, "Stale NFS file handle"}, + {WSAEREMOTE, "Too many levels of remote in path"}, + {WSASYSNOTREADY, "Network system is unavailable"}, + {WSAVERNOTSUPPORTED, "Winsock version out of range"}, + {WSANOTINITIALISED, "WSAStartup not yet called"}, + {WSAEDISCON, "Graceful shutdown in progress"}, + {WSAHOST_NOT_FOUND, "Host not found"}, + {WSANO_DATA, "No host data of that type was found"}, + {0, NULL} +}; + + +static char *apr_os_strerror(char *buf, apr_size_t bufsize, apr_status_t errcode) +{ + apr_size_t len=0, i; + +#ifndef NETWARE +#ifndef _WIN32_WCE + len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + buf, + (DWORD)bufsize, + NULL); +#else /* _WIN32_WCE speaks unicode */ + LPTSTR msg = (LPTSTR) buf; + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + msg, + (DWORD) (bufsize/sizeof(TCHAR)), + NULL); + /* in-place convert to US-ASCII, substituting '?' for non ASCII */ + for(i = 0; i <= len; i++) { + if (msg[i] < 0x80 && msg[i] >= 0) { + buf[i] = (char) msg[i]; + } else { + buf[i] = '?'; + } + } +#endif +#endif + + if (!len) { + for (i = 0; gaErrorList[i].msg; ++i) { + if (gaErrorList[i].code == errcode) { + apr_cpystrn(buf, gaErrorList[i].msg, bufsize); + len = strlen(buf); + break; + } + } + } + + if (len) { + /* FormatMessage put the message in the buffer, but it may + * have embedded a newline (\r\n), and possible more than one. + * Remove the newlines replacing them with a space. This is not + * as visually perfect as moving all the remaining message over, + * but more efficient. + */ + i = len; + while (i) { + i--; + if ((buf[i] == '\r') || (buf[i] == '\n')) + buf[i] = ' '; + } + } + else { + /* Windows didn't provide us with a message. Even stuff like * WSAECONNREFUSED won't get a message. + */ + apr_snprintf(buf, bufsize, "Unrecognized Win32 error code %d", errcode); + } + + return buf; +} + +#else +/* On Unix, apr_os_strerror() handles error codes from the resolver + * (h_errno). + */ +static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) +{ +#ifdef HAVE_HSTRERROR + return stuffbuffer(buf, bufsize, hstrerror(err)); +#else /* HAVE_HSTRERROR */ + const char *msg; + + switch(err) { + case HOST_NOT_FOUND: + msg = "Unknown host"; + break; +#if defined(NO_DATA) + case NO_DATA: +#if defined(NO_ADDRESS) && (NO_DATA != NO_ADDRESS) + case NO_ADDRESS: +#endif + msg = "No address for host"; + break; +#elif defined(NO_ADDRESS) + case NO_ADDRESS: + msg = "No address for host"; + break; +#endif /* NO_DATA */ + default: + msg = "Unrecognized resolver error"; + } + return stuffbuffer(buf, bufsize, msg); +#endif /* HAVE_STRERROR */ +} +#endif + +#if defined(HAVE_STRERROR_R) && defined(STRERROR_R_RC_INT) && !defined(BEOS) +/* AIX and Tru64 style */ +static char *native_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) +{ + if (strerror_r(statcode, buf, bufsize) < 0) { + return stuffbuffer(buf, bufsize, + "APR does not understand this error code"); + } + else { + return buf; + } +} +#elif defined(HAVE_STRERROR_R) +/* glibc style */ + +/* BeOS has the function available, but it doesn't provide + * the prototype publicly (doh!), so to avoid a build warning + * we add a suitable prototype here. + */ +#if defined(BEOS) +const char *strerror_r(apr_status_t, char *, apr_size_t); +#endif + +static char *native_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) +{ + const char *msg; + + buf[0] = '\0'; + msg = strerror_r(statcode, buf, bufsize); + if (buf[0] == '\0') { /* libc didn't use our buffer */ + return stuffbuffer(buf, bufsize, msg); + } + else { + return buf; + } +} +#else +/* plain old strerror(); + * thread-safe on some platforms (e.g., Solaris, OS/390) + */ +static char *native_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) +{ +#ifdef _WIN32_WCE + static char err[32]; + sprintf(err, "Native Error #%d", statcode); + return stuffbuffer(buf, bufsize, err); +#else + const char *err = strerror(statcode); + if (err) { + return stuffbuffer(buf, bufsize, err); + } else { + return stuffbuffer(buf, bufsize, + "APR does not understand this error code"); + } +#endif +} +#endif + +APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) +{ + if (statcode < APR_OS_START_ERROR) { + return native_strerror(statcode, buf, bufsize); + } + else if (statcode < APR_OS_START_USERERR) { + return stuffbuffer(buf, bufsize, apr_error_string(statcode)); + } + else if (statcode < APR_OS_START_EAIERR) { + return stuffbuffer(buf, bufsize, "APR does not understand this error code"); + } + else if (statcode < APR_OS_START_SYSERR) { +#if defined(HAVE_GAI_STRERROR) + statcode -= APR_OS_START_EAIERR; +#if defined(NEGATIVE_EAI) + statcode = -statcode; +#endif + return stuffbuffer(buf, bufsize, gai_strerror(statcode)); +#else + return stuffbuffer(buf, bufsize, "APR does not understand this error code"); +#endif + } + else { + return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR); + } +} + diff --git a/misc/unix/getopt.c b/misc/unix/getopt.c new file mode 100644 index 0000000..24be3c8 --- /dev/null +++ b/misc/unix/getopt.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "apr_arch_misc.h" +#include "apr_strings.h" +#include "apr_lib.h" + +#define EMSG "" + +APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont, + int argc, const char *const *argv) +{ + void *argv_buff; + + *os = apr_palloc(cont, sizeof(apr_getopt_t)); + (*os)->cont = cont; + (*os)->reset = 0; + (*os)->errfn = (apr_getopt_err_fn_t*)(fprintf); + (*os)->errarg = (void*)(stderr); + + (*os)->place = EMSG; + (*os)->argc = argc; + + /* The argv parameter must be compatible with main()'s argv, since + that's the primary purpose of this function. But people might + want to use this function with arrays other than the main argv, + and we shouldn't touch the caller's data. So we copy. */ + argv_buff = apr_palloc(cont, (argc + 1) * sizeof(const char *)); + memcpy(argv_buff, argv, argc * sizeof(const char *)); + (*os)->argv = argv_buff; + (*os)->argv[argc] = NULL; + + (*os)->interleave = 0; + (*os)->ind = 1; + (*os)->skip_start = 1; + (*os)->skip_end = 1; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts, + char *optch, const char **optarg) +{ + const char *oli; /* option letter list index */ + + if (os->reset || !*os->place) { /* update scanning pointer */ + os->reset = 0; + if (os->ind >= os->argc || *(os->place = os->argv[os->ind]) != '-') { + os->place = EMSG; + *optch = os->opt; + return (APR_EOF); + } + if (os->place[1] && *++os->place == '-') { /* found "--" */ + ++os->ind; + os->place = EMSG; + *optch = os->opt; + return (APR_EOF); + } + } /* option letter okay? */ + if ((os->opt = (int) *os->place++) == (int) ':' || + !(oli = strchr(opts, os->opt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (os->opt == (int) '-') { + *optch = os->opt; + return (APR_EOF); + } + if (!*os->place) + ++os->ind; + if (os->errfn && *opts != ':') { + (os->errfn)(os->errarg, "%s: illegal option -- %c\n", + apr_filepath_name_get(*os->argv), os->opt); + } + *optch = os->opt; + return (APR_BADCH); + } + if (*++oli != ':') { /* don't need argument */ + *optarg = NULL; + if (!*os->place) + ++os->ind; + } + else { /* need an argument */ + if (*os->place) /* no white space */ + *optarg = os->place; + else if (os->argc <= ++os->ind) { /* no arg */ + os->place = EMSG; + if (*opts == ':') { + *optch = os->opt; + return (APR_BADARG); + } + if (os->errfn) { + (os->errfn)(os->errarg, + "%s: option requires an argument -- %c\n", + apr_filepath_name_get(*os->argv), os->opt); + } + *optch = os->opt; + return (APR_BADCH); + } + else /* white space */ + *optarg = os->argv[os->ind]; + os->place = EMSG; + ++os->ind; + } + *optch = os->opt; + return APR_SUCCESS; +} + +/* Reverse the sequence argv[start..start+len-1]. */ +static void reverse(const char **argv, int start, int len) +{ + const char *temp; + + for (; len >= 2; start++, len -= 2) { + temp = argv[start]; + argv[start] = argv[start + len - 1]; + argv[start + len - 1] = temp; + } +} + +/* + * Permute os->argv with the goal that non-option arguments will all + * appear at the end. os->skip_start is where we started skipping + * non-option arguments, os->skip_end is where we stopped, and os->ind + * is where we are now. + */ +static void permute(apr_getopt_t *os) +{ + int len1 = os->skip_end - os->skip_start; + int len2 = os->ind - os->skip_end; + + if (os->interleave) { + /* + * Exchange the sequences argv[os->skip_start..os->skip_end-1] and + * argv[os->skip_end..os->ind-1]. The easiest way to do that is + * to reverse the entire range and then reverse the two + * sub-ranges. + */ + reverse(os->argv, os->skip_start, len1 + len2); + reverse(os->argv, os->skip_start, len2); + reverse(os->argv, os->skip_start + len2, len1); + } + + /* Reset skip range to the new location of the non-option sequence. */ + os->skip_start += len2; + os->skip_end += len2; +} + +/* Helper function to print out an error involving a long option */ +static apr_status_t serr(apr_getopt_t *os, const char *err, const char *str, + apr_status_t status) +{ + if (os->errfn) + (os->errfn)(os->errarg, "%s: %s: %s\n", + apr_filepath_name_get(*os->argv), err, str); + return status; +} + +/* Helper function to print out an error involving a short option */ +static apr_status_t cerr(apr_getopt_t *os, const char *err, int ch, + apr_status_t status) +{ + if (os->errfn) + (os->errfn)(os->errarg, "%s: %s: %c\n", + apr_filepath_name_get(*os->argv), err, ch); + return status; +} + +APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os, + const apr_getopt_option_t *opts, + int *optch, const char **optarg) +{ + const char *p; + int i; + + /* Let the calling program reset option processing. */ + if (os->reset) { + os->place = EMSG; + os->ind = 1; + os->reset = 0; + } + + /* + * We can be in one of two states: in the middle of processing a + * run of short options, or about to process a new argument. + * Since the second case can lead to the first one, handle that + * one first. */ + p = os->place; + if (*p == '\0') { + /* If we are interleaving, skip non-option arguments. */ + if (os->interleave) { + while (os->ind < os->argc && *os->argv[os->ind] != '-') + os->ind++; + os->skip_end = os->ind; + } + if (os->ind >= os->argc || *os->argv[os->ind] != '-') { + os->ind = os->skip_start; + return APR_EOF; + } + + p = os->argv[os->ind++] + 1; + if (*p == '-' && p[1] != '\0') { /* Long option */ + /* Search for the long option name in the caller's table. */ + apr_size_t len = 0; + + p++; + for (i = 0; ; i++) { + if (opts[i].optch == 0) /* No match */ + return serr(os, "invalid option", p - 2, APR_BADCH); + + if (opts[i].name) { + len = strlen(opts[i].name); + if (strncmp(p, opts[i].name, len) == 0 + && (p[len] == '\0' || p[len] == '=')) + break; + } + } + *optch = opts[i].optch; + + if (opts[i].has_arg) { + if (p[len] == '=') /* Argument inline */ + *optarg = p + len + 1; + else { + if (os->ind >= os->argc) /* Argument missing */ + return serr(os, "missing argument", p - 2, APR_BADARG); + else /* Argument in next arg */ + *optarg = os->argv[os->ind++]; + } + } else { + *optarg = NULL; + if (p[len] == '=') + return serr(os, "erroneous argument", p - 2, APR_BADARG); + } + permute(os); + return APR_SUCCESS; + } else { + if (*p == '-') { /* Bare "--"; we're done */ + permute(os); + os->ind = os->skip_start; + return APR_EOF; + } + else + if (*p == '\0') /* Bare "-" is illegal */ + return serr(os, "invalid option", p, APR_BADCH); + } + } + + /* + * Now we're in a run of short options, and *p is the next one. + * Look for it in the caller's table. + */ + for (i = 0; ; i++) { + if (opts[i].optch == 0) /* No match */ + return cerr(os, "invalid option character", *p, APR_BADCH); + + if (*p == opts[i].optch) + break; + } + *optch = *p++; + + if (opts[i].has_arg) { + if (*p != '\0') /* Argument inline */ + *optarg = p; + else { + if (os->ind >= os->argc) /* Argument missing */ + return cerr(os, "missing argument", *optch, APR_BADARG); + else /* Argument in next arg */ + *optarg = os->argv[os->ind++]; + } + os->place = EMSG; + } else { + *optarg = NULL; + os->place = p; + } + + permute(os); + return APR_SUCCESS; +} diff --git a/misc/unix/otherchild.c b/misc/unix/otherchild.c new file mode 100644 index 0000000..427a57e --- /dev/null +++ b/misc/unix/otherchild.c @@ -0,0 +1,221 @@ +/* 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_arch_misc.h" +#include "apr_arch_threadproc.h" +#include "apr_arch_file_io.h" + +#if APR_HAS_OTHER_CHILD + +#ifdef HAVE_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#if APR_HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#ifdef BEOS +#include <sys/socket.h> /* for fd_set definition! */ +#endif + +static apr_other_child_rec_t *other_children = NULL; + +static apr_status_t other_child_cleanup(void *data) +{ + apr_other_child_rec_t **pocr, *nocr; + + for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) { + if ((*pocr)->data == data) { + nocr = (*pocr)->next; + (*(*pocr)->maintenance) (APR_OC_REASON_UNREGISTER, (*pocr)->data, -1); + *pocr = nocr; + /* XXX: um, well we've just wasted some space in pconf ? */ + return APR_SUCCESS; + } + } + return APR_SUCCESS; +} + +APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc, + void (*maintenance) (int reason, void *, int status), + void *data, apr_file_t *write_fd, apr_pool_t *p) +{ + apr_other_child_rec_t *ocr; + + ocr = apr_palloc(p, sizeof(*ocr)); + ocr->p = p; + ocr->proc = proc; + ocr->maintenance = maintenance; + ocr->data = data; + if (write_fd == NULL) { + ocr->write_fd = (apr_os_file_t) -1; + } + else { +#ifdef WIN32 + /* This should either go away as part of eliminating apr_proc_probe_writable_fds + * or write_fd should point to an apr_file_t + */ + ocr->write_fd = write_fd->filehand; +#else + ocr->write_fd = write_fd->filedes; +#endif + + } + ocr->next = other_children; + other_children = ocr; + apr_pool_cleanup_register(p, ocr->data, other_child_cleanup, + apr_pool_cleanup_null); +} + +APR_DECLARE(void) apr_proc_other_child_unregister(void *data) +{ + apr_other_child_rec_t *cur; + + cur = other_children; + while (cur) { + if (cur->data == data) { + break; + } + cur = cur->next; + } + + /* segfault if this function called with invalid parm */ + apr_pool_cleanup_kill(cur->p, cur->data, other_child_cleanup); + other_child_cleanup(data); +} + +APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc, + int reason, + int status) +{ + apr_other_child_rec_t *ocr, *nocr; + + for (ocr = other_children; ocr; ocr = nocr) { + nocr = ocr->next; + if (ocr->proc->pid != proc->pid) + continue; + + ocr->proc = NULL; + (*ocr->maintenance) (reason, ocr->data, status); + return APR_SUCCESS; + } + return APR_EPROC_UNKNOWN; +} + +APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr, + int reason) +{ + /* Todo: + * Implement code to detect if pipes are still alive. + */ +#ifdef WIN32 + DWORD status; + + if (ocr->proc == NULL) + return; + + if (!ocr->proc->hproc) { + /* Already mopped up, perhaps we apr_proc_kill'ed it, + * they should have already unregistered! + */ + ocr->proc = NULL; + (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1); + } + else if (!GetExitCodeProcess(ocr->proc->hproc, &status)) { + CloseHandle(ocr->proc->hproc); + ocr->proc->hproc = NULL; + ocr->proc = NULL; + (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1); + } + else if (status == STILL_ACTIVE) { + (*ocr->maintenance) (reason, ocr->data, -1); + } + else { + CloseHandle(ocr->proc->hproc); + ocr->proc->hproc = NULL; + ocr->proc = NULL; + (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status); + } + +#else /* ndef Win32 */ + pid_t waitret; + int status; + + if (ocr->proc == NULL) + return; + + waitret = waitpid(ocr->proc->pid, &status, WNOHANG); + if (waitret == ocr->proc->pid) { + ocr->proc = NULL; + (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status); + } + else if (waitret == 0) { + (*ocr->maintenance) (reason, ocr->data, -1); + } + else if (waitret == -1) { + /* uh what the heck? they didn't call unregister? */ + ocr->proc = NULL; + (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1); + } +#endif +} + +APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason) +{ + apr_other_child_rec_t *ocr, *next_ocr; + + for (ocr = other_children; ocr; ocr = next_ocr) { + next_ocr = ocr->next; + apr_proc_other_child_refresh(ocr, reason); + } +} + +#else /* !APR_HAS_OTHER_CHILD */ + +APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc, + void (*maintenance) (int reason, void *, int status), + void *data, apr_file_t *write_fd, apr_pool_t *p) +{ + return; +} + +APR_DECLARE(void) apr_proc_other_child_unregister(void *data) +{ + return; +} + +APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc, + int reason, + int status) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr, + int reason) +{ + return; +} + +APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason) +{ + return; +} + +#endif /* APR_HAS_OTHER_CHILD */ diff --git a/misc/unix/rand.c b/misc/unix/rand.c new file mode 100644 index 0000000..c0567a6 --- /dev/null +++ b/misc/unix/rand.c @@ -0,0 +1,302 @@ +/* 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_MEMFUNC +#include "apr_want.h" +#include "apr_general.h" + +#include "apr_arch_misc.h" +#include <sys/stat.h> +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if APR_HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_SYS_UN_H +#include <sys/un.h> +#endif +#if defined(HAVE_UUID_H) +#include <uuid.h> +#elif defined(HAVE_UUID_UUID_H) +#include <uuid/uuid.h> +#elif defined(HAVE_SYS_UUID_H) +#include <sys/uuid.h> +#endif + +#if defined(SYS_RANDOM) +#if defined(HAVE_SYS_RANDOM_H) && \ + defined(HAVE_GETRANDOM) + +#include <sys/random.h> +#define USE_GETRANDOM + +#elif defined(HAVE_SYS_SYSCALL_H) && \ + defined(HAVE_LINUX_RANDOM_H) && \ + defined(HAVE_DECL_SYS_GETRANDOM) && \ + HAVE_DECL_SYS_GETRANDOM + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <unistd.h> +#include <sys/syscall.h> +#include <linux/random.h> +#define getrandom(buf, buflen, flags) \ + syscall(SYS_getrandom, (buf), (buflen), (flags)) +#define USE_GETRANDOM + +#endif /* HAVE_SYS_RANDOM_H */ +#endif /* SYS_RANDOM */ + +#ifndef SHUT_RDWR +#define SHUT_RDWR 2 +#endif + +#if APR_HAS_OS_UUID + +#if defined(HAVE_UUID_CREATE) + +APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data) +{ + uint32_t rv; + uuid_t g; + + uuid_create(&g, &rv); + + if (rv != uuid_s_ok) + return APR_EGENERAL; + + memcpy(uuid_data, &g, sizeof(uuid_t)); + + return APR_SUCCESS; +} + +#elif defined(HAVE_UUID_GENERATE) + +APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data) +{ + uuid_t g; + + uuid_generate(g); + + memcpy(uuid_data, g, sizeof(uuid_t)); + + return APR_SUCCESS; +} +#endif + +#endif /* APR_HAS_OS_UUID */ + +#if APR_HAS_RANDOM + +APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf, + apr_size_t length) +{ +#if defined(HAVE_EGD) + /* use EGD-compatible socket daemon (such as EGD or PRNGd). + * message format: + * 0x00 (get entropy level) + * 0xMM (msb) 0xmm 0xll 0xLL (lsb) + * 0x01 (read entropy nonblocking) 0xNN (bytes requested) + * 0xMM (bytes granted) MM bytes + * 0x02 (read entropy blocking) 0xNN (bytes desired) + * [block] NN bytes + * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data) + * NN bytes + * (no response - write only) + * 0x04 (report PID) + * 0xMM (length of PID string, not null-terminated) MM chars + */ + static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL }; + const char **egdsockname = NULL; + + int egd_socket, egd_path_len, rv, bad_errno; + struct sockaddr_un addr; + apr_socklen_t egd_addr_len; + apr_size_t resp_expected; + unsigned char req[2], resp[255]; + unsigned char *curbuf = buf; + + for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) { + egd_path_len = strlen(*egdsockname); + + if (egd_path_len > sizeof(addr.sun_path)) { + return APR_EINVAL; + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + memcpy(addr.sun_path, *egdsockname, egd_path_len); + egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) + + egd_path_len; + + egd_socket = socket(PF_UNIX, SOCK_STREAM, 0); + + if (egd_socket == -1) { + return errno; + } + + rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len); + + if (rv == -1) { + bad_errno = errno; + continue; + } + + /* EGD can only return 255 bytes of data at a time. Silly. */ + while (length > 0) { + apr_ssize_t srv; + req[0] = 2; /* We'll block for now. */ + req[1] = length > 255 ? 255: length; + + srv = write(egd_socket, req, 2); + if (srv == -1) { + bad_errno = errno; + shutdown(egd_socket, SHUT_RDWR); + close(egd_socket); + break; + } + + if (srv != 2) { + shutdown(egd_socket, SHUT_RDWR); + close(egd_socket); + return APR_EGENERAL; + } + + resp_expected = req[1]; + srv = read(egd_socket, resp, resp_expected); + if (srv == -1) { + bad_errno = errno; + shutdown(egd_socket, SHUT_RDWR); + close(egd_socket); + return bad_errno; + } + + memcpy(curbuf, resp, srv); + curbuf += srv; + length -= srv; + } + + shutdown(egd_socket, SHUT_RDWR); + close(egd_socket); + } + + if (length > 0) { + /* We must have iterated through the list of sockets, + * and no go. Return the errno. + */ + return bad_errno; + } + +#elif defined(SYS_RANDOM) && defined(USE_GETRANDOM) + + do { + int rc; + + rc = getrandom(buf, length, 0); + if (rc == -1) { + if (errno == EINTR) { + continue; + } + return errno; + } + + buf += rc; + length -= rc; + } while (length > 0); + +#elif defined(SYS_RANDOM) && defined(HAVE_ARC4RANDOM_BUF) + + arc4random_buf(buf, length); + +#elif defined(DEV_RANDOM) + + int fd = -1; + + /* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then + * gives EOF, so reading 'length' bytes may require opening the + * device several times. */ + do { + apr_ssize_t rc; + + if (fd == -1) + if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1) + return errno; + + do { + rc = read(fd, buf, length); + } while (rc == -1 && errno == EINTR); + + if (rc < 0) { + int errnum = errno; + close(fd); + return errnum; + } + else if (rc == 0) { + close(fd); + fd = -1; /* force open() again */ + } + else { + buf += rc; + length -= rc; + } + } while (length > 0); + + close(fd); + +#elif defined(OS2) + + static UCHAR randbyte(); + unsigned int idx; + + for (idx=0; idx<length; idx++) + buf[idx] = randbyte(); + +#elif defined(HAVE_TRUERAND) /* use truerand */ + + extern int randbyte(void); /* from the truerand library */ + unsigned int idx; + + /* this will increase the startup time of the server, unfortunately... + * (generating 20 bytes takes about 8 seconds) + */ + for (idx=0; idx<length; idx++) + buf[idx] = (unsigned char) randbyte(); + +#else + +#error APR_HAS_RANDOM defined with no implementation + +#endif /* DEV_RANDOM */ + + return APR_SUCCESS; +} + +#undef STR +#undef XSTR + +#ifdef OS2 +#include "randbyte_os2.inc" +#endif + +#endif /* APR_HAS_RANDOM */ diff --git a/misc/unix/randbyte_os2.inc b/misc/unix/randbyte_os2.inc new file mode 100644 index 0000000..4020e31 --- /dev/null +++ b/misc/unix/randbyte_os2.inc @@ -0,0 +1,123 @@ +/* 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. + */ + +/* The high resolution timer API provides access to the hardware timer + * running at around 1.1MHz. The amount this changes in a time slice is + * varies randomly due to system events, hardware interrupts etc + */ +static UCHAR randbyte_hrtimer() +{ + QWORD t1, t2; + UCHAR byte; + + DosTmrQueryTime(&t1); + DosSleep(5); + DosTmrQueryTime(&t2); + + byte = (t2.ulLo - t1.ulLo) & 0xFF; + byte ^= (t2.ulLo - t1.ulLo) >> 8; + return byte; +} + + + +/* A bunch of system information like memory & process stats. + * Not highly random but every bit helps.... + */ +static UCHAR randbyte_sysinfo() +{ + UCHAR byte = 0; + UCHAR SysVars[100]; + int b; + + DosQuerySysInfo(1, QSV_FOREGROUND_PROCESS, SysVars, sizeof(SysVars)); + + for (b = 0; b < 100; b++) { + byte ^= SysVars[b]; + } + + return byte; +} + + + +/* Similar in concept to randbyte_hrtimer() but accesses the CPU's internal + * counters which run at the CPU's MHz speed. We get separate + * idle / busy / interrupt cycle counts which should provide very good + * randomness due to interference of hardware events. + * This only works on newer CPUs (at least PPro or K6) and newer OS/2 versions + * which is why it's run-time linked. + */ + +static APIRET APIENTRY(*DosPerfSysCall) (ULONG ulCommand, ULONG ulParm1, + ULONG ulParm2, ULONG ulParm3) = NULL; +static HMODULE hDoscalls = 0; +#define CMD_KI_RDCNT (0x63) + +typedef struct _CPUUTIL { + ULONG ulTimeLow; /* Low 32 bits of time stamp */ + ULONG ulTimeHigh; /* High 32 bits of time stamp */ + ULONG ulIdleLow; /* Low 32 bits of idle time */ + ULONG ulIdleHigh; /* High 32 bits of idle time */ + ULONG ulBusyLow; /* Low 32 bits of busy time */ + ULONG ulBusyHigh; /* High 32 bits of busy time */ + ULONG ulIntrLow; /* Low 32 bits of interrupt time */ + ULONG ulIntrHigh; /* High 32 bits of interrupt time */ +} CPUUTIL; + + +static UCHAR randbyte_perf() +{ + UCHAR byte = 0; + CPUUTIL util; + int c; + + if (hDoscalls == 0) { + char failed_module[20]; + ULONG rc; + + rc = DosLoadModule(failed_module, sizeof(failed_module), "DOSCALLS", + &hDoscalls); + + if (rc == 0) { + rc = DosQueryProcAddr(hDoscalls, 976, NULL, (PFN *)&DosPerfSysCall); + + if (rc) { + DosPerfSysCall = NULL; + } + } + } + + if (DosPerfSysCall) { + if (DosPerfSysCall(CMD_KI_RDCNT, (ULONG)&util, 0, 0) == 0) { + for (c = 0; c < sizeof(util); c++) { + byte ^= ((UCHAR *)&util)[c]; + } + } + else { + DosPerfSysCall = NULL; + } + } + + return byte; +} + + + +static UCHAR randbyte() +{ + return randbyte_hrtimer() ^ randbyte_sysinfo() ^ randbyte_perf(); +} diff --git a/misc/unix/start.c b/misc/unix/start.c new file mode 100644 index 0000000..4b8ad99 --- /dev/null +++ b/misc/unix/start.c @@ -0,0 +1,89 @@ +/* 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_general.h" +#include "apr_pools.h" +#include "apr_signal.h" +#include "apr_atomic.h" + +#include "apr_arch_proc_mutex.h" /* for apr_proc_mutex_unix_setup_lock() */ +#include "apr_arch_internal_time.h" + + +APR_DECLARE(apr_status_t) apr_app_initialize(int *argc, + const char * const * *argv, + const char * const * *env) +{ + /* An absolute noop. At present, only Win32 requires this stub, but it's + * required in order to move command arguments passed through the service + * control manager into the process, and it's required to fix the char* + * data passed in from win32 unicode into utf-8, win32's apr internal fmt. + */ + return apr_initialize(); +} + +static int initialized = 0; + +APR_DECLARE(apr_status_t) apr_initialize(void) +{ + apr_pool_t *pool; + apr_status_t status; + + if (initialized++) { + return APR_SUCCESS; + } + +#if !defined(BEOS) && !defined(OS2) + apr_proc_mutex_unix_setup_lock(); + apr_unix_setup_time(); +#endif + + 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"); + + /* apr_atomic_init() used to be called from here aswell. + * Pools rely on mutexes though, which can be backed by + * atomics. Due to this circular dependency + * apr_pool_initialize() is taking care of calling + * apr_atomic_init() at the correct time. + */ + + apr_signal_init(pool); + + return APR_SUCCESS; +} + +APR_DECLARE_NONSTD(void) apr_terminate(void) +{ + initialized--; + if (initialized) { + return; + } + apr_pool_terminate(); + +} + +APR_DECLARE(void) apr_terminate2(void) +{ + apr_terminate(); +} diff --git a/misc/unix/version.c b/misc/unix/version.c new file mode 100644 index 0000000..2f111bf --- /dev/null +++ b/misc/unix/version.c @@ -0,0 +1,35 @@ +/* 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_version.h" +#include "apr_general.h" /* for APR_STRINGIFY */ + +APR_DECLARE(void) apr_version(apr_version_t *pvsn) +{ + pvsn->major = APR_MAJOR_VERSION; + pvsn->minor = APR_MINOR_VERSION; + pvsn->patch = APR_PATCH_VERSION; +#ifdef APR_IS_DEV_VERSION + pvsn->is_dev = 1; +#else + pvsn->is_dev = 0; +#endif +} + +APR_DECLARE(const char *) apr_version_string(void) +{ + return APR_VERSION_STRING; +} 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; +} |